1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2023 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7
8 /// @file
9 ///
10 /// This contains the implementation of the comparison engine of
11 /// libabigail.
12
13 #include <ctype.h>
14 #include <libgen.h>
15 #include <algorithm>
16 #include <sstream>
17 #include <set>
18
19 #include "abg-comparison-priv.h"
20 #include "abg-reporter-priv.h"
21 #include "abg-tools-utils.h"
22
23 namespace abigail
24 {
25
26 namespace comparison
27 {
28
29 ///
30 ///
31 ///@defgroup DiffNode Internal Representation of the comparison engine
32 /// @{
33 ///
34 /// @brief How changes are represented in libabigail's comparison engine.
35 ///
36 ///@par diff nodes
37 ///
38 /// The internal representation of the comparison engine is basically
39 /// a graph of @ref instances of @ref diff node. We refer to these
40 /// just as <em>diff nodes</em>. A diff node represents a change
41 /// between two ABI artifacts represented by instances of types of the
42 /// abigail::ir namespace. These two artifacts that are being
43 /// compared are called the <em>subjects of the diff</em>.
44 ///
45 /// The types of that IR are in the abigail::comparison namespace.
46 ///
47 ///@par comparing diff nodes
48 ///
49 /// Comparing two instances of @ref diff nodes amounts to comparing
50 /// the subject of the diff. In other words, two @ref diff nodes are
51 /// equal if and only if their subjects are equal. Thus, two @ref
52 /// diff nodes can have different memory addresses and yet be equal.
53 ///
54 ///@par diff reporting and context
55 ///
56 /// A diff node can be serialized to an output stream to express, in
57 /// a human-readable textual form, the different changes that exist
58 /// between its two subjects. This is done by invoking the
59 /// diff::report() method. That reporting is controlled by several
60 /// parameters that are conceptually part of the context of the diff.
61 /// That context is materialized by an instance of the @ref
62 /// diff_context type.
63 ///
64 /// Please note that the role of the instance(s) of @ref diff_context
65 /// is boreader than just controlling the reporting of @ref diff
66 /// nodes. Basically, a @ref diff node itself is created following
67 /// behaviours that are controlled by a particular instance of
68 /// diff_context. A diff node is created in a particular diff
69 /// context, so to speak.
70 ///
71 /// @}
72 ///
73
74 ///
75 ///@defgroup CanonicalDiff Canonical diff tree nodes
76 /// @{
77 ///
78 /// @brief How equivalent diff nodes are quickly spotted.
79 ///
80 /// @par Equivalence of diff nodes.
81 ///
82 /// Each @ref diff node has a property named <em>Canonical Diff
83 /// Node</em>. If \c D is a diff node, the canonical diff node of @c
84 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
85 /// Thus, a fast way to compare two @ref diff node is to perform a
86 /// pointer comparison of their canonical diff nodes.
87 ///
88 /// A set of equivalent @ref diff nodes is a set of diff nodes that
89 /// all have the same canonical node. All the nodes of that set are
90 /// equal.
91 ///
92 /// A canonical node is registereded for a given diff node by invoking
93 /// the method diff_context::initialize_canonical_diff().
94 ///
95 /// Please note that the diff_context holds all the canonical diffs
96 /// that got registered through it. Thus, the life time of all of
97 /// canonical diff objects is the same as the life time of the @ref
98 /// diff_context they relate to.
99 ///
100 /// @}
101 ///
102
103 // -----------------------------------------
104 // <private functions re-usable elsewhere>
105 // -----------------------------------------
106 /// Sort a map of enumerators by their value.
107 ///
108 /// @param enumerators_map the map to sort.
109 ///
110 /// @param sorted the resulting vector of sorted enumerators.
111 void
sort_enumerators(const string_enumerator_map & enumerators_map,enum_type_decl::enumerators & sorted)112 sort_enumerators(const string_enumerator_map& enumerators_map,
113 enum_type_decl::enumerators& sorted)
114 {
115 for (string_enumerator_map::const_iterator i = enumerators_map.begin();
116 i != enumerators_map.end();
117 ++i)
118 sorted.push_back(i->second);
119 enumerator_value_comp comp;
120 std::sort(sorted.begin(), sorted.end(), comp);
121 }
122
123 /// Sort a map of changed enumerators.
124 ///
125 /// @param enumerators_map the map to sort.
126 ///
127 ///@param output parameter. The resulting sorted enumerators.
128 void
sort_changed_enumerators(const string_changed_enumerator_map & enumerators_map,changed_enumerators_type & sorted)129 sort_changed_enumerators(const string_changed_enumerator_map& enumerators_map,
130 changed_enumerators_type& sorted)
131 {
132 for (string_changed_enumerator_map::const_iterator i =
133 enumerators_map.begin();
134 i != enumerators_map.end();
135 ++i)
136 sorted.push_back(i->second);
137
138 changed_enumerator_comp comp;
139 std::sort(sorted.begin(), sorted.end(), comp);
140 }
141
142 /// Sort a map of data members by the offset of their initial value.
143 ///
144 /// @param data_members the map of changed data members to sort.
145 ///
146 /// @param sorted the resulting vector of sorted changed data members.
147 void
sort_data_members(const string_decl_base_sptr_map & data_members,vector<decl_base_sptr> & sorted)148 sort_data_members(const string_decl_base_sptr_map &data_members,
149 vector<decl_base_sptr>& sorted)
150 {
151 sorted.reserve(data_members.size());
152 for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
153 i != data_members.end();
154 ++i)
155 sorted.push_back(i->second);
156
157 data_member_comp comp;
158 std::sort(sorted.begin(), sorted.end(), comp);
159 }
160
161 /// Sort (in place) a vector of changed data members.
162 ///
163 /// @param to_sort the vector to sort.
164 void
sort_changed_data_members(changed_var_sptrs_type & to_sort)165 sort_changed_data_members(changed_var_sptrs_type& to_sort)
166 {
167 data_member_comp comp;
168 std::sort(to_sort.begin(), to_sort.end(), comp);
169 }
170
171 /// Sort an instance of @ref string_function_ptr_map map and stuff a
172 /// resulting sorted vector of pointers to function_decl.
173 ///
174 /// @param map the map to sort.
175 ///
176 /// @param sorted the resulting sorted vector.
177 void
sort_string_function_ptr_map(const string_function_ptr_map & map,vector<function_decl * > & sorted)178 sort_string_function_ptr_map(const string_function_ptr_map& map,
179 vector<function_decl*>& sorted)
180 {
181 sorted.reserve(map.size());
182 for (string_function_ptr_map::const_iterator i = map.begin();
183 i != map.end();
184 ++i)
185 sorted.push_back(i->second);
186
187 function_comp comp;
188 std::sort(sorted.begin(), sorted.end(), comp);
189 }
190
191 /// Sort a map that's an instance of @ref
192 /// string_member_function_sptr_map and fill a vector of member
193 /// functions with the sorted result.
194 ///
195 /// @param map the map to sort.
196 ///
197 /// @param sorted the resulting sorted vector.
198 void
sort_string_member_function_sptr_map(const string_member_function_sptr_map & map,class_or_union::member_functions & sorted)199 sort_string_member_function_sptr_map(const string_member_function_sptr_map& map,
200 class_or_union::member_functions& sorted)
201 {
202 sorted.reserve(map.size());
203 for (string_member_function_sptr_map::const_iterator i = map.begin();
204 i != map.end();
205 ++i)
206 sorted.push_back(i->second);
207
208 function_comp comp;
209 std::sort(sorted.begin(), sorted.end(), comp);
210 }
211
212 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
213 /// and store the result in a vector of @ref function_decl_diff_sptr
214 /// objects.
215 ///
216 /// @param map the map whose values to store.
217 ///
218 /// @param sorted the vector of function_decl_diff_sptr to store the
219 /// result of the sort into.
220 void
sort_string_function_decl_diff_sptr_map(const string_function_decl_diff_sptr_map & map,function_decl_diff_sptrs_type & sorted)221 sort_string_function_decl_diff_sptr_map
222 (const string_function_decl_diff_sptr_map& map,
223 function_decl_diff_sptrs_type& sorted)
224 {
225 sorted.reserve(map.size());
226 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
227 i != map.end();
228 ++i)
229 sorted.push_back(i->second);
230 function_decl_diff_comp comp;
231 std::sort(sorted.begin(), sorted.end(), comp);
232 }
233
234 /// Sort of an instance of @ref string_var_diff_sptr_map map.
235 ///
236 /// @param map the input map to sort.
237 ///
238 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
239 /// It's populated with the sorted content.
240 void
sort_string_var_diff_sptr_map(const string_var_diff_sptr_map & map,var_diff_sptrs_type & sorted)241 sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
242 var_diff_sptrs_type& sorted)
243 {
244 sorted.reserve(map.size());
245 for (string_var_diff_sptr_map::const_iterator i = map.begin();
246 i != map.end();
247 ++i)
248 sorted.push_back(i->second);
249
250 var_diff_sptr_comp comp;
251 std::sort(sorted.begin(), sorted.end(), comp);
252 }
253
254 /// Sort a map of string -> pointer to @ref elf_symbol.
255 ///
256 /// The result is a vector of @ref elf_symbol_sptr sorted by the
257 /// name of the symbol.
258 ///
259 /// @param map the map to sort.
260 ///
261 /// @param sorted out parameter; the sorted vector of @ref
262 /// elf_symbol_sptr.
263 void
sort_string_elf_symbol_map(const string_elf_symbol_map & map,vector<elf_symbol_sptr> & sorted)264 sort_string_elf_symbol_map(const string_elf_symbol_map& map,
265 vector<elf_symbol_sptr>& sorted)
266 {
267 for (string_elf_symbol_map::const_iterator i = map.begin();
268 i!= map.end();
269 ++i)
270 sorted.push_back(i->second);
271
272 elf_symbol_comp comp;
273 std::sort(sorted.begin(), sorted.end(), comp);
274 }
275
276 /// Sort a map of string -> pointer to @ref var_decl.
277 ///
278 /// The result is a vector of var_decl* sorted by the qualified name
279 /// of the variables.
280 ///
281 /// @param map the map to sort.
282 ///
283 /// @param sorted out parameter; the sorted vector of @ref var_decl.
284 void
sort_string_var_ptr_map(const string_var_ptr_map & map,vector<var_decl * > & sorted)285 sort_string_var_ptr_map(const string_var_ptr_map& map,
286 vector<var_decl*>& sorted)
287 {
288 for (string_var_ptr_map::const_iterator i = map.begin();
289 i != map.end();
290 ++i)
291 sorted.push_back(i->second);
292
293 var_comp comp;
294 std::sort(sorted.begin(), sorted.end(), comp);
295 }
296
297 /// Sort the values of a string_var_diff_sptr_map and store the result
298 /// in a vector of var_diff_sptr.
299 ///
300 /// @param map the map of changed data members to sort.
301 ///
302 /// @param sorted the resulting vector of var_diff_sptr.
303 void
sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map & map,var_diff_sptrs_type & sorted)304 sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map,
305 var_diff_sptrs_type& sorted)
306 {
307 sorted.reserve(map.size());
308 for (string_var_diff_sptr_map::const_iterator i = map.begin();
309 i != map.end();
310 ++i)
311 sorted.push_back(i->second);
312 data_member_diff_comp comp;
313 std::sort(sorted.begin(), sorted.end(), comp);
314 }
315
316 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
317 /// result into a vector of var_diff_sptr.
318 ///
319 /// @param map the map of changed data members to sort.
320 ///
321 /// @param sorted the resulting vector of sorted var_diff_sptr.
322 void
sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,var_diff_sptrs_type & sorted)323 sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,
324 var_diff_sptrs_type& sorted)
325 {
326 sorted.reserve(map.size());
327 for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
328 i != map.end();
329 ++i)
330 sorted.push_back(i->second);
331 data_member_diff_comp comp;
332 std::sort(sorted.begin(), sorted.end(), comp);
333 }
334
335 /// Sort an map of string -> virtual member function into a vector of
336 /// virtual member functions. The virtual member functions are sorted
337 /// by increasing order of their virtual index.
338 ///
339 /// @param map the input map.
340 ///
341 /// @param sorted the resulting sorted vector of virtual function
342 /// member.
343 void
sort_string_virtual_member_function_diff_sptr_map(const string_function_decl_diff_sptr_map & map,function_decl_diff_sptrs_type & sorted)344 sort_string_virtual_member_function_diff_sptr_map
345 (const string_function_decl_diff_sptr_map& map,
346 function_decl_diff_sptrs_type& sorted)
347 {
348 sorted.reserve(map.size());
349 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
350 i != map.end();
351 ++i)
352 sorted.push_back(i->second);
353
354 virtual_member_function_diff_comp comp;
355 sort(sorted.begin(), sorted.end(), comp);
356 }
357
358 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
359 /// diff_sptr. The diff_sptr are sorted lexicographically wrt
360 /// qualified names of their first subjects.
361 ///
362 /// @param map the map to sort.
363 ///
364 /// @param sorted the resulting sorted vector.
365 void
sort_string_diff_sptr_map(const string_diff_sptr_map & map,diff_sptrs_type & sorted)366 sort_string_diff_sptr_map(const string_diff_sptr_map& map,
367 diff_sptrs_type& sorted)
368 {
369 sorted.reserve(map.size());
370 for (string_diff_sptr_map::const_iterator i = map.begin();
371 i != map.end();
372 ++i)
373 sorted.push_back(i->second);
374
375 diff_comp comp;
376 sort(sorted.begin(), sorted.end(), comp);
377 }
378
379 /// Sort a map ofg string -> @ref diff* into a vector of @ref
380 /// diff_ptr. The diff_ptr are sorted lexicographically wrt
381 /// qualified names of their first subjects.
382 ///
383 /// @param map the map to sort.
384 ///
385 /// @param sorted the resulting sorted vector.
386 void
sort_string_diff_ptr_map(const string_diff_ptr_map & map,diff_ptrs_type & sorted)387 sort_string_diff_ptr_map(const string_diff_ptr_map& map,
388 diff_ptrs_type& sorted)
389 {
390 sorted.reserve(map.size());
391 for (string_diff_ptr_map::const_iterator i = map.begin();
392 i != map.end();
393 ++i)
394 sorted.push_back(i->second);
395
396 diff_comp comp;
397 sort(sorted.begin(), sorted.end(), comp);
398 }
399
400 /// Sort a map of string -> base_diff_sptr into a sorted vector of
401 /// base_diff_sptr. The base_diff_sptr are sorted by increasing value
402 /// of their offset in their containing type.
403 ///
404 /// @param map the input map to sort.
405 ///
406 /// @param sorted the resulting sorted vector.
407 void
sort_string_base_diff_sptr_map(const string_base_diff_sptr_map & map,base_diff_sptrs_type & sorted)408 sort_string_base_diff_sptr_map(const string_base_diff_sptr_map& map,
409 base_diff_sptrs_type& sorted)
410 {
411 for (string_base_diff_sptr_map::const_iterator i = map.begin();
412 i != map.end();
413 ++i)
414 sorted.push_back(i->second);
415 base_diff_comp comp;
416 sort(sorted.begin(), sorted.end(), comp);
417 }
418
419 /// Lexicographically sort base specifications found
420 /// in instances of string_base_sptr_map.
421 void
sort_string_base_sptr_map(const string_base_sptr_map & m,class_decl::base_specs & sorted)422 sort_string_base_sptr_map(const string_base_sptr_map& m,
423 class_decl::base_specs& sorted)
424 {
425 for (string_base_sptr_map::const_iterator i = m.begin();
426 i != m.end();
427 ++i)
428 sorted.push_back(i->second);
429
430 base_spec_comp comp;
431 std::sort(sorted.begin(), sorted.end(), comp);
432 }
433
434 /// Sort a map of @ref fn_parm_diff by the indexes of the function
435 /// parameters.
436 ///
437 /// @param map the map to sort.
438 ///
439 /// @param sorted the resulting sorted vector of changed function
440 /// parms.
441 void
sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map & map,vector<fn_parm_diff_sptr> & sorted)442 sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map,
443 vector<fn_parm_diff_sptr>& sorted)
444 {
445 sorted.reserve(map.size());
446 for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
447 i != map.end();
448 ++i)
449 sorted.push_back(i->second);
450
451 fn_parm_diff_comp comp;
452 std::sort(sorted.begin(), sorted.end(), comp);
453 }
454
455 /// Sort a map of changed function parameters by the indexes of the
456 /// function parameters.
457 ///
458 /// @param map the map to sort.
459 ///
460 /// @param sorted the resulting sorted vector of instances of @ref
461 /// fn_parm_diff_sptr
462 void
sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map & map,vector<fn_parm_diff_sptr> & sorted)463 sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map& map,
464 vector<fn_parm_diff_sptr>& sorted)
465 {
466 sorted.reserve(map.size());
467 for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
468 i != map.end();
469 ++i)
470 sorted.push_back(i->second);
471
472 fn_parm_diff_comp comp;
473 std::sort(sorted.begin(), sorted.end(), comp);
474 }
475
476 /// Sort a map of string -> function parameters.
477 ///
478 /// @param map the map to sort.
479 ///
480 /// @param sorted the resulting sorted vector of
481 /// @ref vector<function_decl::parameter_sptr>
482 void
sort_string_parm_map(const string_parm_map & map,vector<function_decl::parameter_sptr> & sorted)483 sort_string_parm_map(const string_parm_map& map,
484 vector<function_decl::parameter_sptr>& sorted)
485 {
486 for (string_parm_map::const_iterator i = map.begin();
487 i != map.end();
488 ++i)
489 sorted.push_back(i->second);
490
491 parm_comp comp;
492 std::sort(sorted.begin(), sorted.end(), comp);
493 }
494
495 /// Sort the set of ABI artifacts contained in a @ref
496 /// artifact_sptr_set_type.
497 ///
498 /// @param set the set of ABI artifacts to sort.
499 ///
500 /// @param output parameter the vector containing the sorted ABI
501 /// artifacts.
502 void
sort_artifacts_set(const artifact_sptr_set_type & set,vector<type_or_decl_base_sptr> & sorted)503 sort_artifacts_set(const artifact_sptr_set_type& set,
504 vector<type_or_decl_base_sptr>& sorted)
505 {
506
507 for (artifact_sptr_set_type::const_iterator it = set.begin();
508 it != set.end();
509 ++it)
510 sorted.push_back(*it);
511
512 type_or_decl_base_comp comp;
513 std::sort(sorted.begin(), sorted.end(), comp);
514 }
515
516 /// Sort a map of string to type_base_sptr entities.
517 ///
518 /// The entries are sorted based on the lexicographic order of the
519 /// pretty representation of the type_sptr_sptr. The sorted result is
520 /// put in a vector of type_base_sptr.
521 ///
522 /// @param map the map to sort.
523 ///
524 /// @param sorted the resulting vector of type_base_sptr
525 /// lexicographically sorted using their pretty representation.
526 void
sort_string_type_base_sptr_map(string_type_base_sptr_map & map,vector<type_base_sptr> & sorted)527 sort_string_type_base_sptr_map(string_type_base_sptr_map& map,
528 vector<type_base_sptr>& sorted)
529 {
530 for (string_type_base_sptr_map::const_iterator i = map.begin();
531 i != map.end();
532 ++i)
533 sorted.push_back(i->second);
534
535 type_or_decl_base_comp comp;
536 std::sort(sorted.begin(), sorted.end(), comp);
537 }
538
539 /// Return the first underlying type that is not a qualified type.
540 /// @param t the qualified type to consider.
541 ///
542 /// @return the first underlying type that is not a qualified type, or
543 /// NULL if t is NULL.
544 type_base_sptr
get_leaf_type(qualified_type_def_sptr t)545 get_leaf_type(qualified_type_def_sptr t)
546 {
547 if (!t)
548 return type_base_sptr();
549
550 type_base_sptr ut = t->get_underlying_type();
551 qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
552
553 if (!qut)
554 return ut;
555 return get_leaf_type(qut);
556 }
557
558 /// Tests if a given diff node is to represent the changes between two
559 /// gobal decls.
560 ///
561 /// @param d the diff node to consider.
562 ///
563 /// @return true iff @p d represents the changes between two global
564 /// decls.
565 bool
is_diff_of_global_decls(const diff * d)566 is_diff_of_global_decls(const diff* d)
567 {
568 ABG_ASSERT(d != 0);
569
570 if (d == 0)
571 return false;
572
573 type_or_decl_base_sptr first = d->first_subject();
574 ABG_ASSERT(first);
575
576 type_or_decl_base_sptr second = d->first_subject();
577 ABG_ASSERT(second);
578
579 if (decl_base_sptr decl = is_decl(first))
580 if (is_at_global_scope(decl))
581 if ((decl = is_decl(second)))
582 if (is_at_global_scope(decl))
583 return true;
584
585 return false;
586 }
587
588 // -----------------------------------------
589 // </private functions re-usable elsewhere>
590 // -----------------------------------------
591
592 /// The overloaded or operator for @ref visiting_kind.
593 visiting_kind
operator |(visiting_kind l,visiting_kind r)594 operator|(visiting_kind l, visiting_kind r)
595 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
596 | static_cast<unsigned>(r));}
597
598 /// The overloaded and operator for @ref visiting_kind.
599 visiting_kind
operator &(visiting_kind l,visiting_kind r)600 operator&(visiting_kind l, visiting_kind r)
601 {
602 return static_cast<visiting_kind>(static_cast<unsigned>(l)
603 & static_cast<unsigned>(r));
604 }
605
606 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
607 visiting_kind
operator ~(visiting_kind l)608 operator~(visiting_kind l)
609 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
610
611 /// Test if a diff node is about differences between types.
612 ///
613 /// @param diff the diff node to test.
614 ///
615 /// @return a pointer to the actual type_diff_base* that @p diff
616 /// extends, iff it is about differences between types.
617 const type_diff_base*
is_type_diff(const diff * diff)618 is_type_diff(const diff* diff)
619 {return dynamic_cast<const type_diff_base*>(diff);}
620
621 /// Test if a diff node is about differences between declarations.
622 ///
623 /// @param diff the diff node to test.
624 ///
625 /// @return a pointer to the actual decl_diff_base @p diff extends,
626 /// iff it is about differences between declarations.
627 const decl_diff_base*
is_decl_diff(const diff * diff)628 is_decl_diff(const diff* diff)
629 {return dynamic_cast<const decl_diff_base*>(diff);}
630
631 /// Test if a diff node is a @ref class_diff node.
632 ///
633 /// @param diff the diff node to consider.
634 ///
635 /// @return a non-nil pointer to a @ref class_diff iff @p diff is a
636 /// @ref class_diff node.
637 const class_diff*
is_class_diff(const diff * diff)638 is_class_diff(const diff* diff)
639 {return dynamic_cast<const class_diff*>(diff);}
640
641 /// Test if a diff node is a @ref enum_diff node.
642 ///
643 /// @param diff the diff node to consider.
644 ///
645 /// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
646 /// a @ref enum_diff node.
647 const enum_diff*
is_enum_diff(const diff * diff)648 is_enum_diff(const diff *diff)
649 {return dynamic_cast<const enum_diff*>(diff);}
650
651 /// Test if a diff node is a @ref union_diff node.
652 ///
653 /// @param diff the diff node to consider.
654 ///
655 /// @return a non-nil pointer to a @ref union_diff iff @p diff is a
656 /// @ref union_diff node.
657 const union_diff*
is_union_diff(const diff * diff)658 is_union_diff(const diff* diff)
659 {return dynamic_cast<const union_diff*>(diff);}
660
661 /// Test if a diff node is a @ref class_or_union_diff node.
662 ///
663 /// @param d the diff node to consider.
664 ///
665 /// @return a non-nil pointer to the @ref class_or_union_diff denoted
666 /// by @p d iff @p d is a @ref class_or_union_diff.
667 const class_or_union_diff*
is_class_or_union_diff(const diff * d)668 is_class_or_union_diff(const diff* d)
669 {return dynamic_cast<const class_or_union_diff*>(d);}
670
671 /// Test if a diff node is a @ref class_or_union_diff between two
672 /// anonymous classes or unions.
673 ///
674 /// @param d the diff node to consider.
675 ///
676 /// @return a non-nil pointer to the @ref class_or_union_diff iff @p
677 /// denoted by @p d iff @p is pointer to an anonymous class or union
678 /// diff.
679 const class_or_union_diff*
is_anonymous_class_or_union_diff(const diff * d)680 is_anonymous_class_or_union_diff(const diff* d)
681 {
682 if (const class_or_union_diff *dif = is_class_or_union_diff(d))
683 if (dif->first_class_or_union()->get_is_anonymous())
684 return dif;
685 return 0;
686 }
687
688 /// Test if a diff node is a @ref typedef_diff node.
689 ///
690 /// @param diff the diff node to consider.
691 ///
692 /// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
693 /// @ref typedef_diff node.
694 const typedef_diff*
is_typedef_diff(const diff * diff)695 is_typedef_diff(const diff *diff)
696 {return dynamic_cast<const typedef_diff*>(diff);}
697
698 /// Test if a diff node is a @ref subrange_diff node.
699 ///
700 /// @param diff the diff node to consider.
701 ///
702 /// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
703 /// @ref subrange_diff node.
704 const subrange_diff*
is_subrange_diff(const diff * diff)705 is_subrange_diff(const diff* diff)
706 {return dynamic_cast<const subrange_diff*>(diff);}
707
708 /// Test if a diff node is a @ref array_diff node.
709 ///
710 /// @param diff the diff node to consider.
711 ///
712 /// @return a non-nil pointer to a @ref array_diff iff @p diff is a
713 /// @ref array_diff node.
714 const array_diff*
is_array_diff(const diff * diff)715 is_array_diff(const diff* diff)
716 {return dynamic_cast<const array_diff*>(diff);}
717
718 /// Test if a diff node is a @ref function_type_diff node.
719 ///
720 /// @param diff the diff node to consider.
721 ///
722 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
723 /// @ref function_type_diff node.
724 const function_type_diff*
is_function_type_diff(const diff * diff)725 is_function_type_diff(const diff* diff)
726 {return dynamic_cast<const function_type_diff*>(diff);}
727
728 /// Test if a given diff node carries a function type change with
729 /// local changes.
730 ///
731 /// @param diff the diff node to consider.
732 ///
733 /// @return a non-nil pointer to a @ref function_type_diff iff @p diff
734 /// is a function_type_diff node that carries a local change.
735 const function_type_diff*
is_function_type_diff_with_local_changes(const diff * diff)736 is_function_type_diff_with_local_changes(const diff* diff)
737 {
738 if (const function_type_diff* d = is_function_type_diff(diff))
739 if (d->has_local_changes())
740 return d;
741
742 return 0;
743 }
744
745 /// Test if a diff node is about differences between variables.
746 ///
747 /// @param diff the diff node to test.
748 ///
749 /// @return a pointer to the actual var_diff that @p diff is a type
750 /// of, iff it is about differences between variables.
751 const var_diff*
is_var_diff(const diff * diff)752 is_var_diff(const diff* diff)
753 {
754 const var_diff* d = dynamic_cast<const var_diff*>(diff);
755 if (d)
756 ABG_ASSERT(is_decl_diff(diff));
757 return d;
758 }
759
760 /// Test if a diff node is about differences between functions.
761 ///
762 /// @param diff the diff node to test.
763 ///
764 /// @return a pointer to the actual var_diff that @p diff is a type
765 /// of, iff it is about differences between variables.
766 const function_decl_diff*
is_function_decl_diff(const diff * diff)767 is_function_decl_diff(const diff* diff)
768 {
769 const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
770 if (d)
771 ABG_ASSERT(is_decl_diff(diff));
772 return d;
773 }
774
775 /// Test if a diff node is about differences between two pointers.
776 ///
777 /// @param diff the diff node to consider.
778 ///
779 /// @return the @p diff converted into an instance of @ref
780 /// pointer_diff iff @p diff is about differences between two
781 /// pointers.
782 const pointer_diff*
is_pointer_diff(const diff * diff)783 is_pointer_diff(const diff* diff)
784 {return dynamic_cast<const pointer_diff*>(diff);}
785
786 /// Test if a diff node is about differences between two references.
787 ///
788 /// @param diff the diff node to consider.
789 ///
790 /// @return the @p diff converted into an instance of @ref
791 /// reference_diff iff @p diff is about differences between two
792 /// references.
793 const reference_diff*
is_reference_diff(const diff * diff)794 is_reference_diff(const diff* diff)
795 {return dynamic_cast<const reference_diff*>(diff);}
796
797 /// Test if a diff node is about differences between two qualified
798 /// types.
799 ///
800 /// @param diff the diff node to consider.
801 ///
802 /// @return @p diff converted into an instance of @ref
803 /// qualified_type_diff iff @p diff is about differences between two
804 /// qualified types.
805 const qualified_type_diff*
is_qualified_type_diff(const diff * diff)806 is_qualified_type_diff(const diff* diff)
807 {return dynamic_cast<const qualified_type_diff*>(diff);}
808
809 /// Test if a diff node is a reference or pointer diff node to a
810 /// change that is neither basic type change nor distinct type change.
811 ///
812 /// Note that this function also works on diffs of typedefs of
813 /// reference or pointer.
814 ///
815 /// @param diff the diff node to consider.
816 ///
817 /// @return true iff @p diff is a eference or pointer diff node to a
818 /// change that is neither basic type change nor distinct type change.
819 bool
is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff * diff)820 is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff* diff)
821 {
822 diff = peel_typedef_diff(diff);
823 if (const reference_diff* d = is_reference_diff(diff))
824 {
825 diff = peel_reference_diff(d);
826 if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
827 return false;
828 return true;
829 }
830 else if (const pointer_diff *d = is_pointer_diff(diff))
831 {
832 diff = peel_pointer_diff(d);
833 if (is_diff_of_basic_type(diff) || is_distinct_diff(diff))
834 return false;
835 return true;
836 }
837
838 return false;
839 }
840
841 /// Test if a diff node is about differences between two function
842 /// parameters.
843 ///
844 /// @param diff the diff node to consider.
845 ///
846 /// @return the @p diff converted into an instance of @ref
847 /// reference_diff iff @p diff is about differences between two
848 /// function parameters.
849 const fn_parm_diff*
is_fn_parm_diff(const diff * diff)850 is_fn_parm_diff(const diff* diff)
851 {return dynamic_cast<const fn_parm_diff*>(diff);}
852
853 /// Test if a diff node is about differences between two base class
854 /// specifiers.
855 ///
856 /// @param diff the diff node to consider.
857 ///
858 /// @return the @p diff converted into an instance of @ref base_diff
859 /// iff @p diff is about differences between two base class
860 /// specifiers.
861 const base_diff*
is_base_diff(const diff * diff)862 is_base_diff(const diff* diff)
863 {return dynamic_cast<const base_diff*>(diff);}
864
865 /// Test if a diff node is about differences between two diff nodes of
866 /// different kinds.
867 ///
868 /// @param diff the diff node to consider.
869 ///
870 /// @return the @p diff converted into an instance of @ref
871 /// distintc_diff iff @p diff is about differences between two diff
872 /// nodes of different kinds.
873 const distinct_diff*
is_distinct_diff(const diff * diff)874 is_distinct_diff(const diff *diff)
875 {return dynamic_cast<const distinct_diff*>(diff);}
876
877 /// Test if a diff node is a @ref corpus_diff node.
878 ///
879 /// @param diff the diff node to consider.
880 ///
881 /// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
882 /// @ref corpus_diff node.
883 const corpus_diff*
is_corpus_diff(const diff * diff)884 is_corpus_diff(const diff* diff)
885 {return dynamic_cast<const corpus_diff*>(diff);}
886
887 /// Test if a diff node is a child node of a function parameter diff node.
888 ///
889 /// @param diff the diff node to test.
890 ///
891 /// @return true iff @p diff is a child node of a function parameter
892 /// diff node.
893 bool
is_child_node_of_function_parm_diff(const diff * diff)894 is_child_node_of_function_parm_diff(const diff* diff)
895 {return diff && is_fn_parm_diff(diff->parent_node());}
896
897 /// Test if a diff node is a child node of a base diff node.
898 ///
899 /// @param diff the diff node to test.
900 ///
901 /// @return true iff @p diff is a child node of a base diff node.
902 bool
is_child_node_of_base_diff(const diff * diff)903 is_child_node_of_base_diff(const diff* diff)
904 {return diff && is_base_diff(diff->parent_node());}
905
906 /// The default traverse function.
907 ///
908 /// @return true.
909 bool
traverse(diff_node_visitor &)910 diff_traversable_base::traverse(diff_node_visitor&)
911 {return true;}
912
diff_context()913 diff_context::diff_context()
914 : priv_(new diff_context::priv)
915 {
916 // Setup all the diff output filters we have.
917 filtering::filter_base_sptr f;
918
919 f.reset(new filtering::harmless_harmful_filter);
920 add_diff_filter(f);
921
922 // f.reset(new filtering::harmless_filter);
923 // add_diff_filter(f);
924
925 // f.reset(new filtering::harmful_filter);
926 // add_diff_filter(f);
927 }
928
929 diff_context::~diff_context() = default;
930
931 /// Test if logging was requested.
932 ///
933 /// @return true iff logging was requested.
934 bool
do_log() const935 diff_context::do_log() const
936 {return priv_->do_log_;}
937
938 /// Set logging as requested.
939 ///
940 /// @param f the flag
941 void
do_log(bool f)942 diff_context::do_log(bool f)
943 {priv_->do_log_ = f;}
944
945 /// Set the corpus diff relevant to this context.
946 ///
947 /// @param d the corpus_diff we are interested in.
948 void
set_corpus_diff(const corpus_diff_sptr & d)949 diff_context::set_corpus_diff(const corpus_diff_sptr& d)
950 {priv_->corpus_diff_ = d;}
951
952 /// Get the corpus diff for the current context.
953 ///
954 /// @return the corpus diff of this context.
955 const corpus_diff_sptr&
get_corpus_diff() const956 diff_context::get_corpus_diff() const
957 {return priv_->corpus_diff_;}
958
959 /// Getter for the first corpus of the corpus diff of the current context.
960 ///
961 /// @return the first corpus of the corpus diff of the current
962 /// context, if no corpus diff is associated to the context.
963 corpus_sptr
get_first_corpus() const964 diff_context::get_first_corpus() const
965 {
966 if (priv_->corpus_diff_)
967 return priv_->corpus_diff_->first_corpus();
968 return corpus_sptr();
969 }
970
971 /// Getter for the second corpus of the corpus diff of the current
972 /// context.
973 ///
974 /// @return the second corpus of the corpus diff of the current
975 /// context, if no corpus diff is associated to the context.
976 corpus_sptr
get_second_corpus() const977 diff_context::get_second_corpus() const
978 {
979 if (priv_->corpus_diff_)
980 return priv_->corpus_diff_->second_corpus();
981 return corpus_sptr();
982 }
983
984 /// Getter of the reporter to be used in this context.
985 ///
986 /// @return the reporter to be used in this context.
987 reporter_base_sptr
get_reporter() const988 diff_context::get_reporter() const
989 {
990 if (!priv_->reporter_)
991 {
992 if (show_leaf_changes_only())
993 priv_->reporter_.reset(new leaf_reporter);
994 else
995 priv_->reporter_.reset(new default_reporter);
996 }
997 ABG_ASSERT(priv_->reporter_);
998 return priv_->reporter_;
999 }
1000
1001 /// Setter of the reporter to be used in this context.
1002 ///
1003 /// @param r the reporter to be used in this context.
1004 void
set_reporter(reporter_base_sptr & r)1005 diff_context::set_reporter(reporter_base_sptr& r)
1006 {priv_->reporter_ = r;}
1007
1008 /// Tests if the current diff context already has a diff for two decls.
1009 ///
1010 /// @param first the first decl to consider.
1011 ///
1012 /// @param second the second decl to consider.
1013 ///
1014 /// @return a pointer to the diff for @p first @p second if found,
1015 /// null otherwise.
1016 diff_sptr
has_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second) const1017 diff_context::has_diff_for(const type_or_decl_base_sptr first,
1018 const type_or_decl_base_sptr second) const
1019 {
1020 types_or_decls_diff_map_type::const_iterator i =
1021 priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1022 if (i != priv_->types_or_decls_diff_map.end())
1023 return i->second;
1024 return diff_sptr();
1025 }
1026
1027 /// Tests if the current diff context already has a diff for two types.
1028 ///
1029 /// @param first the first type to consider.
1030 ///
1031 /// @param second the second type to consider.
1032 ///
1033 /// @return a pointer to the diff for @p first @p second if found,
1034 /// null otherwise.
1035 diff_sptr
has_diff_for_types(const type_base_sptr first,const type_base_sptr second) const1036 diff_context::has_diff_for_types(const type_base_sptr first,
1037 const type_base_sptr second) const
1038 {return has_diff_for(first, second);}
1039
1040 /// Tests if the current diff context already has a given diff.
1041 ///
1042 ///@param d the diff to consider.
1043 ///
1044 /// @return a pointer to the diff found for @p d
1045 const diff*
has_diff_for(const diff * d) const1046 diff_context::has_diff_for(const diff* d) const
1047 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
1048
1049 /// Tests if the current diff context already has a given diff.
1050 ///
1051 ///@param d the diff to consider.
1052 ///
1053 /// @return a pointer to the diff found for @p d
1054 diff_sptr
has_diff_for(const diff_sptr d) const1055 diff_context::has_diff_for(const diff_sptr d) const
1056 {return has_diff_for(d->first_subject(), d->second_subject());}
1057
1058 /// Getter for the bitmap that represents the set of categories that
1059 /// the user wants to see reported.
1060 ///
1061 /// @return a bitmap that represents the set of categories that the
1062 /// user wants to see reported.
1063 diff_category
get_allowed_category() const1064 diff_context::get_allowed_category() const
1065 {return priv_->allowed_category_;}
1066
1067 /// Setter for the bitmap that represents the set of categories that
1068 /// the user wants to see reported.
1069 ///
1070 /// @param c a bitmap that represents the set of categories that the
1071 /// user wants to see represented.
1072 void
set_allowed_category(diff_category c)1073 diff_context::set_allowed_category(diff_category c)
1074 {priv_->allowed_category_ = c;}
1075
1076 /// Setter for the bitmap that represents the set of categories that
1077 /// the user wants to see reported
1078 ///
1079 /// This function perform a bitwise or between the new set of
1080 /// categories and the current ones, and then sets the current
1081 /// categories to the result of the or.
1082 ///
1083 /// @param c a bitmap that represents the set of categories that the
1084 /// user wants to see represented.
1085 void
switch_categories_on(diff_category c)1086 diff_context::switch_categories_on(diff_category c)
1087 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
1088
1089 /// Setter for the bitmap that represents the set of categories that
1090 /// the user wants to see reported
1091 ///
1092 /// This function actually unsets bits from the current categories.
1093 ///
1094 /// @param c a bitmap that represents the set of categories to unset
1095 /// from the current categories.
1096 void
switch_categories_off(diff_category c)1097 diff_context::switch_categories_off(diff_category c)
1098 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1099
1100 /// Add a diff for two decls to the cache of the current diff_context.
1101 ///
1102 /// Doing this allows to later find the added diff from its two
1103 /// subject decls.
1104 ///
1105 /// @param first the first decl to consider.
1106 ///
1107 /// @param second the second decl to consider.
1108 ///
1109 /// @param the diff to add.
1110 void
add_diff(type_or_decl_base_sptr first,type_or_decl_base_sptr second,const diff_sptr d)1111 diff_context::add_diff(type_or_decl_base_sptr first,
1112 type_or_decl_base_sptr second,
1113 const diff_sptr d)
1114 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1115
1116 /// Add a diff tree node to the cache of the current diff_context
1117 ///
1118 /// @param d the diff tree node to add.
1119 void
add_diff(const diff * d)1120 diff_context::add_diff(const diff* d)
1121 {
1122 if (d)
1123 {
1124 diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1125 add_diff(d->first_subject(), d->second_subject(), dif);
1126 }
1127 }
1128
1129 /// Add a diff tree node to the cache of the current diff_context
1130 ///
1131 /// @param d the diff tree node to add.
1132 void
add_diff(const diff_sptr d)1133 diff_context::add_diff(const diff_sptr d)
1134 {
1135 if (d)
1136 add_diff(d->first_subject(), d->second_subject(), d);
1137 }
1138
1139 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1140 /// @ref diff represented by their two subjects.
1141 ///
1142 /// @param first the first subject of the diff.
1143 ///
1144 /// @param second the second subject of the diff.
1145 ///
1146 /// @return the canonical diff for the diff node represented by the
1147 /// two diff subjects @p first and @p second. If no canonical diff
1148 /// node was registered for these subjects, then a nil node is
1149 /// returned.
1150 diff_sptr
get_canonical_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second) const1151 diff_context::get_canonical_diff_for(const type_or_decl_base_sptr first,
1152 const type_or_decl_base_sptr second) const
1153 {return has_diff_for(first, second);}
1154
1155 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
1156 /// @ref diff represented by the two subjects of a given diff node.
1157 ///
1158 /// @param d the diff node to get the canonical node for.
1159 ///
1160 /// @return the canonical diff for the diff node represented by the
1161 /// two diff subjects of @p d. If no canonical diff node was
1162 /// registered for these subjects, then a nil node is returned.
1163 diff_sptr
get_canonical_diff_for(const diff_sptr d) const1164 diff_context::get_canonical_diff_for(const diff_sptr d) const
1165 {return has_diff_for(d);}
1166
1167 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
1168 /// @ref diff represented by their two subjects.
1169 ///
1170 /// @param first the first subject of the diff.
1171 ///
1172 /// @param second the second subject of the diff.
1173 ///
1174 /// @param d the new canonical diff.
1175 void
set_canonical_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,const diff_sptr d)1176 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1177 const type_or_decl_base_sptr second,
1178 const diff_sptr d)
1179 {
1180 ABG_ASSERT(d);
1181 if (!has_diff_for(first, second))
1182 {
1183 add_diff(first, second, d);
1184 priv_->canonical_diffs.push_back(d);
1185 }
1186 }
1187
1188 /// If there is is a @ref CanonicalDiff "canonical diff node"
1189 /// registered for two diff subjects, return it. Otherwise, register
1190 /// a canonical diff node for these two diff subjects and return it.
1191 ///
1192 /// @param first the first subject of the diff.
1193 ///
1194 /// @param second the second subject of the diff.
1195 ///
1196 /// @param d the new canonical diff node.
1197 ///
1198 /// @return the canonical diff node.
1199 diff_sptr
set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,const diff_sptr canonical_diff)1200 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1201 const type_or_decl_base_sptr second,
1202 const diff_sptr canonical_diff)
1203 {
1204 ABG_ASSERT(canonical_diff);
1205
1206 diff_sptr canonical = get_canonical_diff_for(first, second);
1207 if (!canonical)
1208 {
1209 canonical = canonical_diff;
1210 set_canonical_diff_for(first, second, canonical);
1211 }
1212 return canonical;
1213 }
1214
1215 /// Set the canonical diff node property of a given diff node
1216 /// appropriately.
1217 ///
1218 /// For a given diff node that has no canonical diff node, retrieve
1219 /// the canonical diff node (by looking at its diff subjects and at
1220 /// the current context) and set the canonical diff node property of
1221 /// the diff node to that canonical diff node. If no canonical diff
1222 /// node has been registered to the diff context for the subjects of
1223 /// the diff node then, register the canonical diff node as being the
1224 /// diff node itself; and set its canonical diff node property as
1225 /// such. Otherwise, if the diff node already has a canonical diff
1226 /// node, do nothing.
1227 ///
1228 /// @param diff the diff node to initialize the canonical diff node
1229 /// property for.
1230 void
initialize_canonical_diff(const diff_sptr diff)1231 diff_context::initialize_canonical_diff(const diff_sptr diff)
1232 {
1233 if (diff->get_canonical_diff() == 0)
1234 {
1235 diff_sptr canonical =
1236 set_or_get_canonical_diff_for(diff->first_subject(),
1237 diff->second_subject(),
1238 diff);
1239 diff->set_canonical_diff(canonical.get());
1240 }
1241 }
1242
1243 /// Add a diff node to the set of diff nodes that are kept alive for
1244 /// the life time of the current instance of diff_context.
1245 ///
1246 /// Note that diff added to the diff cache are kept alive as well, and
1247 /// don't need to be passed to this function to be kept alive.
1248 ///
1249 /// @param d the diff node to be kept alive during the life time of
1250 /// the current instance of @ref diff_context.
1251 void
keep_diff_alive(diff_sptr & d)1252 diff_context::keep_diff_alive(diff_sptr& d)
1253 {priv_->live_diffs_.insert(d);}
1254
1255 /// Test if a diff node has been traversed.
1256 ///
1257 /// @param d the diff node to consider.
1258 ///
1259 /// @return the first diff node against which @p d is redundant.
1260 diff*
diff_has_been_visited(const diff * d) const1261 diff_context::diff_has_been_visited(const diff* d) const
1262 {
1263 const diff* canonical = d->get_canonical_diff();
1264 ABG_ASSERT(canonical);
1265
1266 size_t ptr_value = reinterpret_cast<size_t>(canonical);
1267 pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1268 if (it != priv_->visited_diff_nodes_.end())
1269 return reinterpret_cast<diff*>(it->second);
1270 else
1271 return 0;
1272 }
1273
1274 /// Test if a diff node has been traversed.
1275 ///
1276 /// @param d the diff node to consider.
1277 ///
1278 /// @return the first diff node against which @p d is redundant.
1279 diff_sptr
diff_has_been_visited(const diff_sptr d) const1280 diff_context::diff_has_been_visited(const diff_sptr d) const
1281 {
1282 diff_sptr diff(diff_has_been_visited(d.get()));
1283 return diff;
1284 }
1285
1286 /// Mark a diff node as traversed by a traversing algorithm.
1287 ///
1288 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1289 /// node that is marked as traversed.
1290 ///
1291 /// Subsequent invocations of diff_has_been_visited() on the diff node
1292 /// will yield true.
1293 void
mark_diff_as_visited(const diff * d)1294 diff_context::mark_diff_as_visited(const diff* d)
1295 {
1296 if (diff_has_been_visited(d))
1297 return;
1298
1299 const diff* canonical = d->get_canonical_diff();
1300 ABG_ASSERT(canonical);
1301
1302 size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1303 size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1304 priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1305 }
1306
1307 /// Unmark all the diff nodes that were marked as being traversed.
1308 void
forget_visited_diffs()1309 diff_context::forget_visited_diffs()
1310 {priv_->visited_diff_nodes_.clear();}
1311
1312 /// This sets a flag that, if it's true, then during the traversing of
1313 /// a diff nodes tree each node is visited at most once.
1314 ///
1315 /// @param f if true then during the traversing of a diff nodes tree
1316 /// each node is visited at most once.
1317 ///
1318 void
forbid_visiting_a_node_twice(bool f)1319 diff_context::forbid_visiting_a_node_twice(bool f)
1320 {priv_->forbid_visiting_a_node_twice_ = f;}
1321
1322 /// This function sets a flag os that if @ref
1323 /// forbid_visiting_a_node_twice() returns true, then each time the
1324 /// node visitor starts visiting a new interface, it resets the
1325 /// memory the systems has about already visited node.
1326 ///
1327 /// @param f the flag to set.
1328 void
forbid_visiting_a_node_twice_per_interface(bool f)1329 diff_context::forbid_visiting_a_node_twice_per_interface(bool f)
1330 {priv_->reset_visited_diffs_for_each_interface_ = f;}
1331
1332 /// Return a flag that, if true, then during the traversing of a diff
1333 /// nodes tree each node is visited at most once.
1334 ///
1335 /// @return the boolean flag.
1336 bool
visiting_a_node_twice_is_forbidden() const1337 diff_context::visiting_a_node_twice_is_forbidden() const
1338 {return priv_->forbid_visiting_a_node_twice_;}
1339
1340 /// Return a flag that, if true, then during the traversing of a diff
1341 /// nodes tree each node is visited at most once, while visiting the
1342 /// diff tree underneath a given interface (public function or
1343 /// variable). Each time a new interface is visited, the nodes
1344 /// visited while visiting previous interfaces can be visited again.
1345 ///
1346 /// @return the boolean flag.
1347 ///
1348 /// @return the boolean flag.
1349 bool
visiting_a_node_twice_is_forbidden_per_interface() const1350 diff_context::visiting_a_node_twice_is_forbidden_per_interface() const
1351 {
1352 return (priv_->forbid_visiting_a_node_twice_
1353 && priv_->reset_visited_diffs_for_each_interface_);
1354 }
1355
1356 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
1357 ///
1358 /// @return the vector of tree filters to apply to diff sub-trees.
1359 const filtering::filters&
diff_filters() const1360 diff_context::diff_filters() const
1361 {return priv_->filters_;}
1362
1363 /// Setter for the diff filters to apply to a given diff sub-tree.
1364 ///
1365 /// @param f the new diff filter to add to the vector of diff filters
1366 /// to apply to diff sub-trees.
1367 void
add_diff_filter(filtering::filter_base_sptr f)1368 diff_context::add_diff_filter(filtering::filter_base_sptr f)
1369 {priv_->filters_.push_back(f);}
1370
1371 /// Apply the diff filters to a given diff sub-tree.
1372 ///
1373 /// If the current context is instructed to filter out some categories
1374 /// then this function walks the given sub-tree and categorizes its
1375 /// nodes by using the filters held by the context.
1376 ///
1377 /// @param diff the diff sub-tree to apply the filters to.
1378 void
maybe_apply_filters(diff_sptr diff)1379 diff_context::maybe_apply_filters(diff_sptr diff)
1380 {
1381 if (!diff)
1382 return;
1383
1384 if (!diff->has_changes())
1385 return;
1386
1387 for (filtering::filters::const_iterator i = diff_filters().begin();
1388 i != diff_filters().end();
1389 ++i)
1390 {
1391 tools_utils::timer t;
1392 if (do_log())
1393 {
1394 std::cerr << "applying a filter to diff '"
1395 << diff->get_pretty_representation()
1396 << "'...\n";
1397 t.start();
1398 }
1399
1400 filtering::apply_filter(*i, diff);
1401
1402 if (do_log())
1403 {
1404 t.stop();
1405 std::cerr << "filter applied!:" << t << "\n";
1406
1407 std::cerr << "propagating categories for the same diff node ... \n";
1408 t.start();
1409 }
1410
1411 propagate_categories(diff);
1412
1413 if (do_log())
1414 {
1415 t.stop();
1416 std::cerr << "category propagated!: " << t << "\n";
1417 }
1418 }
1419
1420 }
1421
1422 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
1423 /// instance.
1424 ///
1425 /// If the current context is instructed to filter out some categories
1426 /// then this function walks the diff tree and categorizes its nodes
1427 /// by using the filters held by the context.
1428 ///
1429 /// @param diff the corpus diff to apply the filters to.
1430 void
maybe_apply_filters(corpus_diff_sptr diff)1431 diff_context::maybe_apply_filters(corpus_diff_sptr diff)
1432 {
1433
1434 if (!diff || !diff->has_changes())
1435 return;
1436
1437 for (filtering::filters::const_iterator i = diff_filters().begin();
1438 i != diff_filters().end();
1439 ++i)
1440 {
1441 filtering::apply_filter(**i, diff);
1442 propagate_categories(diff);
1443 }
1444 }
1445
1446 /// Getter for the vector of suppressions that specify which diff node
1447 /// reports should be dropped on the floor.
1448 ///
1449 /// @return the set of suppressions.
1450 const suppressions_type&
suppressions() const1451 diff_context::suppressions() const
1452 {return priv_->suppressions_;}
1453
1454 /// Getter for the vector of suppressions that specify which diff node
1455 /// reports should be dropped on the floor.
1456 ///
1457 /// @return the set of suppressions.
1458 suppr::suppressions_type&
suppressions()1459 diff_context::suppressions()
1460 {
1461 // Invalidate negated and direct suppressions caches that are built
1462 // from priv_->suppressions_;
1463 priv_->negated_suppressions_.clear();
1464 priv_->direct_suppressions_.clear();
1465 return priv_->suppressions_;
1466 }
1467
1468 /// Getter of the negated suppression specifications that are
1469 /// comprised in the general vector of suppression specifications
1470 /// returned by diff_context::suppressions().
1471 ///
1472 /// Note that the first invocation of this function scans the vector
1473 /// returned by diff_context::suppressions() and caches the negated
1474 /// suppressions from there.
1475 ///
1476 /// Subsequent invocations of this function just return the cached
1477 /// negated suppressions.
1478 ///
1479 /// @return the negated suppression specifications stored in this diff
1480 /// context.
1481 const suppr::suppressions_type&
negated_suppressions() const1482 diff_context::negated_suppressions() const
1483 {
1484 if (priv_->negated_suppressions_.empty())
1485 for (auto s : suppressions())
1486 if (is_negated_suppression(s))
1487 priv_->negated_suppressions_.push_back(s);
1488
1489 return priv_->negated_suppressions_;
1490 }
1491
1492 /// Getter of the direct suppression specification (those that are
1493 /// not negated) comprised in the general vector of suppression
1494 /// specifications returned by diff_context::suppression().
1495 ///
1496 /// Note that the first invocation of this function scans the vector
1497 /// returned by diff_context::suppressions() and caches the direct
1498 /// suppressions from there.
1499 ///
1500 /// Subsequent invocations of this function just return the cached
1501 /// direct suppressions.
1502 ///
1503 /// @return the direct suppression specifications.
1504 const suppr::suppressions_type&
direct_suppressions() const1505 diff_context::direct_suppressions() const
1506 {
1507 if (priv_->direct_suppressions_.empty())
1508 {
1509 for (auto s : suppressions())
1510 if (!is_negated_suppression(s))
1511 priv_->direct_suppressions_.push_back(s);
1512 }
1513 return priv_->direct_suppressions_;
1514 }
1515
1516 /// Add a new suppression specification that specifies which diff node
1517 /// reports should be dropped on the floor.
1518 ///
1519 /// @param suppr the new suppression specification to add to the
1520 /// existing set of suppressions specifications of the diff context.
1521 void
add_suppression(const suppression_sptr suppr)1522 diff_context::add_suppression(const suppression_sptr suppr)
1523 {
1524 priv_->suppressions_.push_back(suppr);
1525 // Invalidate negated and direct suppressions caches that are built
1526 // from priv_->suppressions_;
1527 priv_->negated_suppressions_.clear();
1528 priv_->direct_suppressions_.clear();
1529 }
1530
1531 /// Add new suppression specifications that specify which diff node
1532 /// reports should be dropped on the floor.
1533 ///
1534 /// @param supprs the new suppression specifications to add to the
1535 /// existing set of suppression specifications of the diff context.
1536 void
add_suppressions(const suppressions_type & supprs)1537 diff_context::add_suppressions(const suppressions_type& supprs)
1538 {
1539 priv_->suppressions_.insert(priv_->suppressions_.end(),
1540 supprs.begin(), supprs.end());
1541 }
1542
1543 /// Test if it's requested to perform diff node categorization.
1544 ///
1545 /// @return true iff it's requested to perform diff node
1546 /// categorization.
1547 bool
perform_change_categorization() const1548 diff_context::perform_change_categorization() const
1549 {return priv_->perform_change_categorization_;}
1550
1551 /// Request change categorization or not.
1552 ///
1553 /// @param f true iff change categorization is requested.
1554 void
perform_change_categorization(bool f)1555 diff_context::perform_change_categorization(bool f)
1556 {priv_->perform_change_categorization_ = f;}
1557
1558 /// Set the flag that indicates if the diff using this context should
1559 /// show only leaf changes or not.
1560 ///
1561 /// @param f the new value of the flag that indicates if the diff
1562 /// using this context should show only leaf changes or not.
1563 void
show_leaf_changes_only(bool f)1564 diff_context::show_leaf_changes_only(bool f)
1565 {
1566 // This function can be called only if the reporter hasn't yet been
1567 // created. Once it's been created, we are supposed to live with
1568 // it.
1569 ABG_ASSERT(priv_->reporter_ == 0);
1570 priv_->leaf_changes_only_ = f;
1571 }
1572
1573 /// Get the flag that indicates if the diff using this context should
1574 /// show only leaf changes or not.
1575 ///
1576 /// @return the value of the flag that indicates if the diff using
1577 /// this context should show only leaf changes or not.
1578 bool
show_leaf_changes_only() const1579 diff_context::show_leaf_changes_only() const
1580 {return priv_->leaf_changes_only_;}
1581
1582 /// Get the flag that indicates if the diff reports using this context
1583 /// should show sizes and offsets in an hexadecimal base or not. If
1584 /// not, then they are to be shown in a decimal base.
1585 ///
1586 /// @return true iff sizes and offsets are to be shown in an
1587 /// hexadecimal base.
1588 bool
show_hex_values() const1589 diff_context::show_hex_values() const
1590 {return priv_->hex_values_;}
1591
1592 /// Set the flag that indicates if diff reports using this context
1593 /// should show sizes and offsets in an hexadecimal base or not. If
1594 /// not, then they are to be shown in a decimal base.
1595 ///
1596 /// @param f if true then sizes and offsets are to be shown in an
1597 /// hexadecimal base.
1598 void
show_hex_values(bool f)1599 diff_context::show_hex_values(bool f)
1600 {priv_->hex_values_ = f;}
1601
1602 /// Get the flag that indicates if diff reports using this context
1603 /// should show sizes and offsets in bits, rather than bytes.
1604 ///
1605 /// @return true iff sizes and offsets are to be shown in bits.
1606 /// Otherwise they are to be shown in bytes.
1607 bool
show_offsets_sizes_in_bits() const1608 diff_context::show_offsets_sizes_in_bits() const
1609 {return priv_->show_offsets_sizes_in_bits_;}
1610
1611 /// Set the flag that indicates if diff reports using this context
1612 /// should show sizes and offsets in bits, rather than bytes.
1613 ///
1614 /// @param f if true then sizes and offsets are to be shown in bits.
1615 /// Otherwise they are to be shown in bytes.
1616 void
show_offsets_sizes_in_bits(bool f)1617 diff_context::show_offsets_sizes_in_bits(bool f)
1618 {priv_->show_offsets_sizes_in_bits_ = f;}
1619
1620 /// Set a flag saying if offset changes should be reported in a
1621 /// relative way. That is, if the report should say how of many bits
1622 /// a class/struct data member did move.
1623 ///
1624 /// @param f the new boolean value of the flag.
1625 void
show_relative_offset_changes(bool f)1626 diff_context::show_relative_offset_changes(bool f)
1627 {priv_->show_relative_offset_changes_ = f;}
1628
1629 /// Get the flag saying if offset changes should be reported in a
1630 /// relative way. That is, if the report should say how of many bits
1631 /// a class/struct data member did move.
1632 ///
1633 /// @return the boolean value of the flag.
1634 bool
show_relative_offset_changes(void)1635 diff_context::show_relative_offset_changes(void)
1636 {return priv_->show_relative_offset_changes_;}
1637
1638 /// Set a flag saying if the comparison module should only show the
1639 /// diff stats.
1640 ///
1641 /// @param f the flag to set.
1642 void
show_stats_only(bool f)1643 diff_context::show_stats_only(bool f)
1644 {priv_->show_stats_only_ = f;}
1645
1646 /// Test if the comparison module should only show the diff stats.
1647 ///
1648 /// @return true if the comparison module should only show the diff
1649 /// stats, false otherwise.
1650 bool
show_stats_only() const1651 diff_context::show_stats_only() const
1652 {return priv_->show_stats_only_;}
1653
1654 /// Setter for the property that says if the comparison module should
1655 /// show the soname changes in its report.
1656 ///
1657 /// @param f the new value of the property.
1658 void
show_soname_change(bool f)1659 diff_context::show_soname_change(bool f)
1660 {priv_->show_soname_change_ = f;}
1661
1662 /// Getter for the property that says if the comparison module should
1663 /// show the soname changes in its report.
1664 ///
1665 /// @return the value of the property.
1666 bool
show_soname_change() const1667 diff_context::show_soname_change() const
1668 {return priv_->show_soname_change_;}
1669
1670 /// Setter for the property that says if the comparison module should
1671 /// show the architecture changes in its report.
1672 ///
1673 /// @param f the new value of the property.
1674 void
show_architecture_change(bool f)1675 diff_context::show_architecture_change(bool f)
1676 {priv_->show_architecture_change_ = f;}
1677
1678 /// Getter for the property that says if the comparison module should
1679 /// show the architecture changes in its report.
1680 ///
1681 /// @return the value of the property.
1682 bool
show_architecture_change() const1683 diff_context::show_architecture_change() const
1684 {return priv_->show_architecture_change_;}
1685
1686 /// Set a flag saying to show the deleted functions.
1687 ///
1688 /// @param f true to show deleted functions.
1689 void
show_deleted_fns(bool f)1690 diff_context::show_deleted_fns(bool f)
1691 {priv_->show_deleted_fns_ = f;}
1692
1693 /// @return true if we want to show the deleted functions, false
1694 /// otherwise.
1695 bool
show_deleted_fns() const1696 diff_context::show_deleted_fns() const
1697 {return priv_->show_deleted_fns_;}
1698
1699 /// Set a flag saying to show the changed functions.
1700 ///
1701 /// @param f true to show the changed functions.
1702 void
show_changed_fns(bool f)1703 diff_context::show_changed_fns(bool f)
1704 {priv_->show_changed_fns_ = f;}
1705
1706 /// @return true if we want to show the changed functions, false otherwise.
1707 bool
show_changed_fns() const1708 diff_context::show_changed_fns() const
1709 {return priv_->show_changed_fns_;}
1710
1711 /// Set a flag saying to show the added functions.
1712 ///
1713 /// @param f true to show the added functions.
1714 void
show_added_fns(bool f)1715 diff_context::show_added_fns(bool f)
1716 {priv_->show_added_fns_ = f;}
1717
1718 /// @return true if we want to show the added functions, false
1719 /// otherwise.
1720 bool
show_added_fns() const1721 diff_context::show_added_fns() const
1722 {return priv_->show_added_fns_;}
1723
1724 /// Set a flag saying to show the deleted variables.
1725 ///
1726 /// @param f true to show the deleted variables.
1727 void
show_deleted_vars(bool f)1728 diff_context::show_deleted_vars(bool f)
1729 {priv_->show_deleted_vars_ = f;}
1730
1731 /// @return true if we want to show the deleted variables, false
1732 /// otherwise.
1733 bool
show_deleted_vars() const1734 diff_context::show_deleted_vars() const
1735 {return priv_->show_deleted_vars_;}
1736
1737 /// Set a flag saying to show the changed variables.
1738 ///
1739 /// @param f true to show the changed variables.
1740 void
show_changed_vars(bool f)1741 diff_context::show_changed_vars(bool f)
1742 {priv_->show_changed_vars_ = f;}
1743
1744 /// @return true if we want to show the changed variables, false otherwise.
1745 bool
show_changed_vars() const1746 diff_context::show_changed_vars() const
1747 {return priv_->show_changed_vars_;}
1748
1749 /// Set a flag saying to show the added variables.
1750 ///
1751 /// @param f true to show the added variables.
1752 void
show_added_vars(bool f)1753 diff_context::show_added_vars(bool f)
1754 {priv_->show_added_vars_ = f;}
1755
1756 /// @return true if we want to show the added variables, false
1757 /// otherwise.
1758 bool
show_added_vars() const1759 diff_context::show_added_vars() const
1760 {return priv_->show_added_vars_;}
1761
1762 bool
show_linkage_names() const1763 diff_context::show_linkage_names() const
1764 {return priv_->show_linkage_names_;}
1765
1766 void
show_linkage_names(bool f)1767 diff_context::show_linkage_names(bool f)
1768 {priv_->show_linkage_names_= f;}
1769
1770 /// Set a flag saying to show location information.
1771 ///
1772 /// @param f true to show location information.
1773 void
show_locs(bool f)1774 diff_context::show_locs(bool f)
1775 {priv_->show_locs_= f;}
1776
1777 /// @return true if we want to show location information, false
1778 /// otherwise.
1779 bool
show_locs() const1780 diff_context::show_locs() const
1781 {return priv_->show_locs_;}
1782
1783 /// A getter for the flag that says if we should report about
1784 /// functions or variables diff nodes that have *exclusively*
1785 /// redundant diff tree children nodes.
1786 ///
1787 /// @return the flag.
1788 bool
show_redundant_changes() const1789 diff_context::show_redundant_changes() const
1790 {return priv_->show_redundant_changes_;}
1791
1792 /// A setter for the flag that says if we should report about
1793 /// functions or variables diff nodes that have *exclusively*
1794 /// redundant diff tree children nodes.
1795 ///
1796 /// @param f the flag to set.
1797 void
show_redundant_changes(bool f)1798 diff_context::show_redundant_changes(bool f)
1799 {priv_->show_redundant_changes_ = f;}
1800
1801 /// Getter for the flag that indicates if symbols not referenced by
1802 /// any debug info are to be compared and reported about.
1803 ///
1804 /// @return the boolean flag.
1805 bool
show_symbols_unreferenced_by_debug_info() const1806 diff_context::show_symbols_unreferenced_by_debug_info() const
1807 {return priv_->show_syms_unreferenced_by_di_;}
1808
1809 /// Setter for the flag that indicates if symbols not referenced by
1810 /// any debug info are to be compared and reported about.
1811 ///
1812 /// @param f the new flag to set.
1813 void
show_symbols_unreferenced_by_debug_info(bool f)1814 diff_context::show_symbols_unreferenced_by_debug_info(bool f)
1815 {priv_->show_syms_unreferenced_by_di_ = f;}
1816
1817 /// Getter for the flag that indicates if symbols not referenced by
1818 /// any debug info and that got added are to be reported about.
1819 ///
1820 /// @return true iff symbols not referenced by any debug info and that
1821 /// got added are to be reported about.
1822 bool
show_added_symbols_unreferenced_by_debug_info() const1823 diff_context::show_added_symbols_unreferenced_by_debug_info() const
1824 {return priv_->show_added_syms_unreferenced_by_di_;}
1825
1826 /// Setter for the flag that indicates if symbols not referenced by
1827 /// any debug info and that got added are to be reported about.
1828 ///
1829 /// @param f the new flag that says if symbols not referenced by any
1830 /// debug info and that got added are to be reported about.
1831 void
show_added_symbols_unreferenced_by_debug_info(bool f)1832 diff_context::show_added_symbols_unreferenced_by_debug_info(bool f)
1833 {priv_->show_added_syms_unreferenced_by_di_ = f;}
1834
1835 /// Setter for the flag that indicates if changes on types unreachable
1836 /// from global functions and variables are to be reported.
1837 ///
1838 /// @param f if true, then changes on types unreachable from global
1839 /// functions and variables are to be reported.
1840 void
show_unreachable_types(bool f)1841 diff_context::show_unreachable_types(bool f)
1842 {priv_->show_unreachable_types_ = f;}
1843
1844 /// Getter for the flag that indicates if changes on types unreachable
1845 /// from global functions and variables are to be reported.
1846 ///
1847 /// @return true iff changes on types unreachable from global
1848 /// functions and variables are to be reported.
1849 bool
show_unreachable_types()1850 diff_context::show_unreachable_types()
1851 {return priv_->show_unreachable_types_;}
1852
1853 /// Getter of the flag that indicates if the leaf reporter should
1854 /// display a summary of the interfaces impacted by a given leaf
1855 /// change or not.
1856 ///
1857 /// @return the flag that indicates if the leaf reporter should
1858 /// display a summary of the interfaces impacted by a given leaf
1859 /// change or not.
1860 bool
show_impacted_interfaces() const1861 diff_context::show_impacted_interfaces() const
1862 {return priv_->show_impacted_interfaces_;}
1863
1864 /// Setter of the flag that indicates if the leaf reporter should
1865 /// display a summary of the interfaces impacted by a given leaf
1866 /// change or not.
1867 ///
1868 /// @param f the new value of the flag that indicates if the leaf
1869 /// reporter should display a summary of the interfaces impacted by a
1870 /// given leaf change or not.
1871 void
show_impacted_interfaces(bool f)1872 diff_context::show_impacted_interfaces(bool f)
1873 {priv_->show_impacted_interfaces_ = f;}
1874
1875 /// Setter for the default output stream used by code of the
1876 /// comparison engine. By default the default output stream is a NULL
1877 /// pointer.
1878 ///
1879 /// @param o a pointer to the default output stream.
1880 void
default_output_stream(ostream * o)1881 diff_context::default_output_stream(ostream* o)
1882 {priv_->default_output_stream_ = o;}
1883
1884 /// Getter for the default output stream used by code of the
1885 /// comparison engine. By default the default output stream is a NULL
1886 /// pointer.
1887 ///
1888 /// @return a pointer to the default output stream.
1889 ostream*
default_output_stream()1890 diff_context::default_output_stream()
1891 {return priv_->default_output_stream_;}
1892
1893 /// Setter for the errror output stream used by code of the comparison
1894 /// engine. By default the error output stream is a NULL pointer.
1895 ///
1896 /// @param o a pointer to the error output stream.
1897 void
error_output_stream(ostream * o)1898 diff_context::error_output_stream(ostream* o)
1899 {priv_->error_output_stream_ = o;}
1900
1901 /// Getter for the errror output stream used by code of the comparison
1902 /// engine. By default the error output stream is a NULL pointer.
1903 ///
1904 /// @return a pointer to the error output stream.
1905 ostream*
error_output_stream() const1906 diff_context::error_output_stream() const
1907 {return priv_->error_output_stream_;}
1908
1909 /// Test if the comparison engine should dump the diff tree for the
1910 /// changed functions and variables it has.
1911 ///
1912 /// @return true if after the comparison, the engine should dump the
1913 /// diff tree for the changed functions and variables it has.
1914 bool
dump_diff_tree() const1915 diff_context::dump_diff_tree() const
1916 {return priv_->dump_diff_tree_;}
1917
1918 /// Set if the comparison engine should dump the diff tree for the
1919 /// changed functions and variables it has.
1920 ///
1921 /// @param f true if after the comparison, the engine should dump the
1922 /// diff tree for the changed functions and variables it has.
1923 void
dump_diff_tree(bool f)1924 diff_context::dump_diff_tree(bool f)
1925 {priv_->dump_diff_tree_ = f;}
1926
1927 /// Emit a textual representation of a diff tree to the error output
1928 /// stream of the current context, for debugging purposes.
1929 ///
1930 /// @param d the diff tree to serialize to the error output associated
1931 /// to the current instance of @ref diff_context.
1932 void
do_dump_diff_tree(const diff_sptr d) const1933 diff_context::do_dump_diff_tree(const diff_sptr d) const
1934 {
1935 if (error_output_stream())
1936 print_diff_tree(d, *error_output_stream());
1937 }
1938
1939 /// Emit a textual representation of a @ref corpus_diff tree to the error
1940 /// output stream of the current context, for debugging purposes.
1941 ///
1942 /// @param d the @ref corpus_diff tree to serialize to the error
1943 /// output associated to the current instance of @ref diff_context.
1944 void
do_dump_diff_tree(const corpus_diff_sptr d) const1945 diff_context::do_dump_diff_tree(const corpus_diff_sptr d) const
1946 {
1947 if (error_output_stream())
1948 print_diff_tree(d, *error_output_stream());
1949 }
1950 // </diff_context stuff>
1951
1952 // <diff stuff>
1953
1954 /// Constructor for the @ref diff type.
1955 ///
1956 /// This constructs a diff between two subjects that are actually
1957 /// declarations; the first and the second one.
1958 ///
1959 /// @param first_subject the first decl (subject) of the diff.
1960 ///
1961 /// @param second_subject the second decl (subject) of the diff.
diff(type_or_decl_base_sptr first_subject,type_or_decl_base_sptr second_subject)1962 diff::diff(type_or_decl_base_sptr first_subject,
1963 type_or_decl_base_sptr second_subject)
1964 : priv_(new priv(first_subject, second_subject,
1965 diff_context_sptr(),
1966 NO_CHANGE_CATEGORY,
1967 /*reported_once=*/false,
1968 /*currently_reporting=*/false))
1969 {}
1970
1971 /// Constructor for the @ref diff type.
1972 ///
1973 /// This constructs a diff between two subjects that are actually
1974 /// declarations; the first and the second one.
1975 ///
1976 /// @param first_subject the first decl (subject) of the diff.
1977 ///
1978 /// @param second_subject the second decl (subject) of the diff.
1979 ///
1980 /// @param ctxt the context of the diff. Note that this context
1981 /// object must stay alive during the entire life time of the current
1982 /// instance of @ref diff. Otherwise, memory corruption issues occur.
diff(type_or_decl_base_sptr first_subject,type_or_decl_base_sptr second_subject,diff_context_sptr ctxt)1983 diff::diff(type_or_decl_base_sptr first_subject,
1984 type_or_decl_base_sptr second_subject,
1985 diff_context_sptr ctxt)
1986 : priv_(new priv(first_subject, second_subject,
1987 ctxt, NO_CHANGE_CATEGORY,
1988 /*reported_once=*/false,
1989 /*currently_reporting=*/false))
1990 {}
1991
1992 /// Test if logging was requested
1993 ///
1994 /// @return true iff logging was requested.
1995 bool
do_log() const1996 diff::do_log() const
1997 {return context()->do_log();}
1998
1999 /// Request logging (or not)
2000 ///
2001 /// @param f true iff logging is to be requested.
2002 void
do_log(bool f)2003 diff::do_log(bool f)
2004 {context()->do_log(f);}
2005
2006 /// Flag a given diff node as being traversed.
2007 ///
2008 /// For certain diff nodes like @ref class_diff, it's important to
2009 /// avoid traversing the node again while it's already being
2010 /// traversed; otherwise this leads to infinite loops. So the
2011 /// diff::begin_traversing() and diff::end_traversing() methods flag a
2012 /// given node as being traversed (or not), so that
2013 /// diff::is_traversing() can tell if the node is being traversed.
2014 ///
2015 /// Note that traversing a node means visiting it *and* visiting its
2016 /// children nodes.
2017 ///
2018 /// The canonical node is marked as being traversed too.
2019 ///
2020 /// These functions are called by the traversing code.
2021 void
begin_traversing()2022 diff::begin_traversing()
2023 {
2024 ABG_ASSERT(!is_traversing());
2025 if (priv_->canonical_diff_)
2026 priv_->canonical_diff_->priv_->traversing_ = true;
2027 priv_->traversing_ = true;
2028 }
2029
2030 /// Tell if a given node is being traversed or not.
2031 ///
2032 /// Note that traversing a node means visiting it *and* visiting its
2033 /// children nodes.
2034 ///
2035 /// It's the canonical node which is looked at, actually.
2036 ///
2037 /// Please read the comments for the diff::begin_traversing() for mode
2038 /// context.
2039 ///
2040 /// @return true if the current instance of @diff is being traversed.
2041 bool
is_traversing() const2042 diff::is_traversing() const
2043 {
2044 if (priv_->canonical_diff_)
2045 return priv_->canonical_diff_->priv_->traversing_;
2046 return priv_->traversing_;
2047 }
2048
2049 /// Flag a given diff node as not being traversed anymore.
2050 ///
2051 /// Note that traversing a node means visiting it *and* visiting its
2052 /// children nodes.
2053 ///
2054 /// Please read the comments of the function diff::begin_traversing()
2055 /// for mode context.
2056 void
end_traversing()2057 diff::end_traversing()
2058 {
2059 ABG_ASSERT(is_traversing());
2060 if (priv_->canonical_diff_)
2061 priv_->canonical_diff_->priv_->traversing_ = false;
2062 priv_->traversing_ = false;
2063 }
2064
2065 /// Finish the insertion of a diff tree node into the diff graph.
2066 ///
2067 /// This function might be called several times. It must perform the
2068 /// insertion only once.
2069 ///
2070 /// For instance, certain kinds of diff tree node have specific
2071 /// children nodes that are populated after the constructor of the
2072 /// diff tree node has been called. In that case, calling overloads
2073 /// of this method ensures that these children nodes are properly
2074 /// gathered and setup.
2075 void
finish_diff_type()2076 diff::finish_diff_type()
2077 {
2078 if (diff::priv_->finished_)
2079 return;
2080 chain_into_hierarchy();
2081 diff::priv_->finished_ = true;
2082 }
2083
2084 /// Getter of the first subject of the diff.
2085 ///
2086 /// @return the first subject of the diff.
2087 type_or_decl_base_sptr
first_subject() const2088 diff::first_subject() const
2089 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2090
2091 /// Getter of the second subject of the diff.
2092 ///
2093 /// @return the second subject of the diff.
2094 type_or_decl_base_sptr
second_subject() const2095 diff::second_subject() const
2096 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2097
2098 /// Getter for the children nodes of the current @ref diff node.
2099 ///
2100 /// @return a vector of the children nodes.
2101 const vector<diff*>&
children_nodes() const2102 diff::children_nodes() const
2103 {return priv_->children_;}
2104
2105 /// Getter for the parent node of the current @ref diff node.
2106 ///
2107 /// @return the parent node of the current @ref diff node.
2108 const diff*
parent_node() const2109 diff::parent_node() const
2110 {return priv_->parent_;}
2111
2112 /// Getter for the canonical diff of the current instance of @ref
2113 /// diff.
2114 ///
2115 /// Note that the canonical diff node for the current instanc eof diff
2116 /// node must have been set by invoking
2117 /// class_diff::initialize_canonical_diff() on the current instance of
2118 /// diff node.
2119 ///
2120 /// @return the canonical diff node or null if none was set.
2121 diff*
get_canonical_diff() const2122 diff::get_canonical_diff() const
2123 {return priv_->canonical_diff_;}
2124
2125 /// Setter for the canonical diff of the current instance of @ref
2126 /// diff.
2127 ///
2128 /// @param d the new canonical node to set.
2129 void
set_canonical_diff(diff * d)2130 diff::set_canonical_diff(diff * d)
2131 {priv_->canonical_diff_ = d;}
2132
2133 /// Add a new child node to the vector of children nodes for the
2134 /// current @ref diff node.
2135 ///
2136 /// @param d the new child node to add to the children nodes.
2137 void
append_child_node(diff_sptr d)2138 diff::append_child_node(diff_sptr d)
2139 {
2140 ABG_ASSERT(d);
2141
2142 // Ensure 'd' is kept alive for the life time of the context of this
2143 // diff.
2144 context()->keep_diff_alive(d);
2145
2146 // Add the underlying pointer of 'd' to the vector of children.
2147 // Note that this vector holds no reference to 'd'. This is to avoid
2148 // reference cycles. The reference to 'd' is held by the context of
2149 // this diff, thanks to the call to context()->keep_diff_alive(d)
2150 // above.
2151 priv_->children_.push_back(d.get());
2152
2153 d->priv_->parent_ = this;
2154 }
2155
2156 /// Getter of the context of the current diff.
2157 ///
2158 /// @return the context of the current diff.
2159 const diff_context_sptr
context() const2160 diff::context() const
2161 {return priv_->get_context();}
2162
2163 /// Setter of the context of the current diff.
2164 ///
2165 /// @param c the new context to set.
2166 void
context(diff_context_sptr c)2167 diff::context(diff_context_sptr c)
2168 {priv_->ctxt_ = c;}
2169
2170 /// Tests if we are currently in the middle of emitting a report for
2171 /// this diff.
2172 ///
2173 /// @return true if we are currently emitting a report for the
2174 /// current diff, false otherwise.
2175 bool
currently_reporting() const2176 diff::currently_reporting() const
2177 {
2178 if (priv_->canonical_diff_)
2179 return priv_->canonical_diff_->priv_->currently_reporting_;
2180 return priv_->currently_reporting_;
2181 }
2182
2183 /// Sets a flag saying if we are currently in the middle of emitting
2184 /// a report for this diff.
2185 ///
2186 /// @param f true if we are currently emitting a report for the
2187 /// current diff, false otherwise.
2188 void
currently_reporting(bool f) const2189 diff::currently_reporting(bool f) const
2190 {
2191 if (priv_->canonical_diff_)
2192 priv_->canonical_diff_->priv_->currently_reporting_ = f;
2193 priv_->currently_reporting_ = f;
2194 }
2195
2196 /// Tests if a report has already been emitted for the current diff.
2197 ///
2198 /// @return true if a report has already been emitted for the
2199 /// current diff, false otherwise.
2200 bool
reported_once() const2201 diff::reported_once() const
2202 {
2203 ABG_ASSERT(priv_->canonical_diff_);
2204 return priv_->canonical_diff_->priv_->reported_once_;
2205 }
2206
2207 /// The generic traversing code that walks a given diff sub-tree.
2208 ///
2209 /// Note that there is a difference between traversing a diff node and
2210 /// visiting it. Basically, traversing a diff node means visiting it
2211 /// and visiting its children nodes too. So one can visit a node
2212 /// without traversing it. But traversing a node without visiting it
2213 /// is not possible.
2214 ///
2215 /// Note that the insertion of the "generic view" of the diff node
2216 /// into the graph being traversed is done "on the fly". The
2217 /// insertion of the "typed view" of the diff node into the graph is
2218 /// done implicitely. To learn more about the generic and typed view
2219 /// of the diff node, please read the introductory comments of the
2220 /// @ref diff class.
2221 ///
2222 /// Note that by default this traversing code visits a given class of
2223 /// equivalence of a diff node only once. This behaviour can been
2224 /// changed by calling
2225 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2226 /// very risky as it might create endless loops while visiting a diff
2227 /// tree graph that has changes that refer to themselves; that is,
2228 /// diff tree graphs with cycles.
2229 ///
2230 /// When a diff node is encountered, the
2231 /// diff_node_visitor::visit_begin() method is invoked on the diff
2232 /// node first.
2233 ///
2234 /// If the diff node has already been visited, then
2235 /// node_visitor::visit_end() is called on it and the node traversing
2236 /// is done; the children of the diff node are not visited in this
2237 /// case.
2238 ///
2239 /// If the diff node has *NOT* been visited yet, then the
2240 /// diff_node_visitor::visit() method is invoked with it's 'pre'
2241 /// argument set to true. Then if the diff_node_visitor::visit()
2242 /// returns true, then the children nodes of the diff node are
2243 /// visited. Otherwise, no children nodes of the diff node is
2244 /// visited and the diff_node_visitor::visit_end() is called.
2245
2246 /// After the children nodes are visited (and only if they are
2247 /// visited) the diff_node_visitor::visit() method is invoked with
2248 /// it's 'pre' argument set to false. And then the
2249 /// diff_node_visitor::visit_end() is called.
2250 ///
2251 /// @param v the entity that visits each node of the diff sub-tree.
2252 ///
2253 /// @return true to tell the caller that all of the sub-tree could be
2254 /// walked. This instructs the caller to keep walking the rest of the
2255 /// tree. Return false otherwise.
2256 bool
traverse(diff_node_visitor & v)2257 diff::traverse(diff_node_visitor& v)
2258 {
2259 // Insert the "generic view" of the diff node into its graph.
2260 finish_diff_type();
2261
2262 v.visit_begin(this);
2263
2264 bool already_visited = false;
2265 if (context()->visiting_a_node_twice_is_forbidden()
2266 && context()->diff_has_been_visited(this))
2267 already_visited = true;
2268
2269 bool mark_visited_nodes_as_traversed =
2270 !(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_VISITED);
2271
2272 if (!already_visited && !v.visit(this, /*pre=*/true))
2273 {
2274 v.visit_end(this);
2275 if (mark_visited_nodes_as_traversed)
2276 context()->mark_diff_as_visited(this);
2277 return false;
2278 }
2279
2280 if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND)
2281 && !is_traversing()
2282 && !already_visited)
2283 {
2284 begin_traversing();
2285 for (vector<diff*>::const_iterator i = children_nodes().begin();
2286 i != children_nodes().end();
2287 ++i)
2288 {
2289 if (!(*i)->traverse(v))
2290 {
2291 v.visit_end(this);
2292 if (mark_visited_nodes_as_traversed)
2293 context()->mark_diff_as_visited(this);
2294 end_traversing();
2295 return false;
2296 }
2297 }
2298 end_traversing();
2299 }
2300
2301 if (!v.visit(this, /*pref=*/false))
2302 {
2303 v.visit_end(this);
2304 if (mark_visited_nodes_as_traversed)
2305 context()->mark_diff_as_visited(this);
2306 return false;
2307 }
2308
2309 v.visit_end(this);
2310 if (!already_visited && mark_visited_nodes_as_traversed)
2311 context()->mark_diff_as_visited(this);
2312
2313 return true;
2314 }
2315
2316 /// Sets a flag saying if a report has already been emitted for the
2317 /// current diff.
2318 ///
2319 /// @param f true if a report has already been emitted for the
2320 /// current diff, false otherwise.
2321 void
reported_once(bool f) const2322 diff::reported_once(bool f) const
2323 {
2324 ABG_ASSERT(priv_->canonical_diff_);
2325 priv_->canonical_diff_->priv_->reported_once_ = f;
2326 priv_->reported_once_ = f;
2327 }
2328
2329 /// Getter for the local category of the current diff tree node.
2330 ///
2331 /// The local category represents the set of categories of a diff
2332 /// node, not taking in account the categories inherited from its
2333 /// children nodes.
2334 ///
2335 /// @return the local category of the current diff tree node.
2336 diff_category
get_local_category() const2337 diff::get_local_category() const
2338 {return priv_->local_category_;}
2339
2340 /// Getter of the category of the class of equivalence of the current
2341 /// diff tree node.
2342 ///
2343 /// That is, if the current diff tree node has a canonical node,
2344 /// return the category of that canonical node. Otherwise, return the
2345 /// category of the current node.
2346 ///
2347 /// @return the category of the class of equivalence of the current
2348 /// tree node.
2349 diff_category
get_class_of_equiv_category() const2350 diff::get_class_of_equiv_category() const
2351 {
2352 diff* canonical = get_canonical_diff();
2353 return canonical ? canonical->get_category() : get_category();
2354 }
2355
2356 /// Getter for the category of the current diff tree node.
2357 ///
2358 /// This category represents the union of the local category and the
2359 /// categories inherited from the children diff nodes.
2360 ///
2361 /// @return the category of the current diff tree node.
2362 diff_category
get_category() const2363 diff::get_category() const
2364 {return priv_->category_;}
2365
2366 /// Adds the current diff tree node to an additional set of
2367 /// categories. Note that the categories include thoses inherited
2368 /// from the children nodes of this diff node.
2369 ///
2370 /// @param c a bit-map representing the set of categories to add the
2371 /// current diff tree node to.
2372 ///
2373 /// @return the resulting bit-map representing the categories this
2374 /// current diff tree node belongs to, including those inherited from
2375 /// its children nodes.
2376 diff_category
add_to_category(diff_category c)2377 diff::add_to_category(diff_category c)
2378 {
2379 priv_->category_ = priv_->category_ | c;
2380 return priv_->category_;
2381 }
2382
2383 /// Adds the current diff tree node to the categories resulting from
2384 /// the local changes of the current diff node.
2385 ///
2386 /// @param c a bit-map representing the set of categories to add the
2387 /// current diff tree node to.
2388 ///
2389 /// @return the resulting bit-map representing the categories this
2390 /// current diff tree node belongs to.
2391 diff_category
add_to_local_category(diff_category c)2392 diff::add_to_local_category(diff_category c)
2393 {
2394 priv_->local_category_ = priv_->local_category_ | c;
2395 return priv_->local_category_;
2396 }
2397
2398 /// Adds the current diff tree node to the categories resulting from
2399 /// the local and inherited changes of the current diff node.
2400 ///
2401 /// @param c a bit-map representing the set of categories to add the
2402 /// current diff tree node to.
2403 void
add_to_local_and_inherited_categories(diff_category c)2404 diff::add_to_local_and_inherited_categories(diff_category c)
2405 {
2406 add_to_local_category(c);
2407 add_to_category(c);
2408 }
2409
2410 /// Remove the current diff tree node from an a existing sef of
2411 /// categories. The categories include those inherited from the
2412 /// children nodes of the current diff node.
2413 ///
2414 /// @param c a bit-map representing the set of categories to add the
2415 /// current diff tree node to.
2416 ///
2417 /// @return the resulting bit-map representing the categories this
2418 /// current diff tree onde belongs to, including the categories
2419 /// inherited from the children nodes of the current diff node.
2420 diff_category
remove_from_category(diff_category c)2421 diff::remove_from_category(diff_category c)
2422 {
2423 priv_->category_ = priv_->category_ & ~c;
2424 return priv_->category_;
2425 }
2426
2427 /// Remove the current diff tree node from the categories resulting
2428 /// from the local changes.
2429 ///
2430 /// @param c a bit-map representing the set of categories to add the
2431 /// current diff tree node to.
2432 ///
2433 /// @return the resulting bit-map representing the categories this
2434 /// current diff tree onde belongs to.
2435 diff_category
remove_from_local_category(diff_category c)2436 diff::remove_from_local_category(diff_category c)
2437 {
2438 priv_->local_category_ = priv_->local_category_ & ~c;
2439 return priv_->local_category_;
2440 }
2441
2442 /// Set the category of the current @ref diff node. This category
2443 /// includes the categories inherited from the children nodes of the
2444 /// current diff node.
2445 ///
2446 /// @param c the new category for the current diff node.
2447 void
set_category(diff_category c)2448 diff::set_category(diff_category c)
2449 {priv_->category_ = c;}
2450
2451 /// Set the local category of the current @ref diff node.
2452 ///
2453 /// @param c the new category for the current diff node.
2454 void
set_local_category(diff_category c)2455 diff::set_local_category(diff_category c)
2456 {priv_->local_category_ = c;}
2457
2458 /// Test if this diff tree node is to be filtered out for reporting
2459 /// purposes.
2460 ///
2461 /// There is a difference between a diff node being filtered out and
2462 /// being suppressed. Being suppressed means that there is a
2463 /// suppression specification that suppresses the diff node
2464 /// specifically. Being filtered out mean the node is either
2465 /// suppressed, or it's filtered out because the suppression of a set
2466 /// of (children) nodes caused this node to be filtered out as well.
2467 /// For instance, if a function diff has all its children diff nodes
2468 /// suppressed and if the function diff node carries no local change,
2469 /// then the function diff node itself is going to be filtered out.
2470 ///
2471 /// The function tests if the categories of the diff tree node are
2472 /// "forbidden" by the context or not.
2473 ///
2474 /// @return true iff the current diff node should NOT be reported.
2475 bool
is_filtered_out() const2476 diff::is_filtered_out() const
2477 {
2478 if (diff * canonical = get_canonical_diff())
2479 if ((canonical->get_category() & SUPPRESSED_CATEGORY
2480 || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2481 && !canonical->is_allowed_by_specific_negated_suppression()
2482 && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2483 && !canonical->has_parent_allowed_by_specific_negated_suppression())
2484 // The canonical type was suppressed either by a user-provided
2485 // suppression specification or by a "private-type" suppression
2486 // specification.. This means all the classes of equivalence of
2487 // that canonical type were suppressed. So this node should be
2488 // filtered out.
2489 return true;
2490 return priv_->is_filtered_out(get_category());
2491 }
2492
2493 /// Test if this diff tree node is to be filtered out for reporting
2494 /// purposes, but by considering only the categories that were *NOT*
2495 /// inherited from its children nodes.
2496 ///
2497 /// The function tests if the local categories of the diff tree node
2498 /// are "forbidden" by the context or not.
2499 ///
2500 /// @return true iff the current diff node should NOT be reported,
2501 /// with respect to its local categories.
2502 bool
is_filtered_out_wrt_non_inherited_categories() const2503 diff::is_filtered_out_wrt_non_inherited_categories() const
2504 {return priv_->is_filtered_out(get_local_category());}
2505
2506 /// Test if this diff tree node is to be filtered out for reporting
2507 /// purposes, but without considering the categories that can /force/
2508 /// the node to be unfiltered.
2509 ///
2510 /// The function tests if the categories of the diff tree node are
2511 /// "forbidden" by the context or not.
2512 ///
2513 /// @return true iff the current diff node should should NOT be
2514 /// reported, with respect to the categories that might filter it out
2515 /// only.
2516 bool
is_filtered_out_without_looking_at_allowed_changes() const2517 diff::is_filtered_out_without_looking_at_allowed_changes() const
2518 {
2519 diff_category c = get_category();
2520 c &= ~(HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
2521 | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
2522 | HAS_ALLOWED_CHANGE_CATEGORY);
2523
2524 return priv_->is_filtered_out(c);
2525 }
2526
2527 /// Test if the current diff node has been suppressed by a
2528 /// user-provided suppression specification.
2529 ///
2530 /// @return true if the current diff node has been suppressed by a
2531 /// user-provided suppression list.
2532 bool
is_suppressed() const2533 diff::is_suppressed() const
2534 {
2535 bool is_private = false;
2536 return is_suppressed(is_private);
2537 }
2538
2539 /// Test if the current diff node has been suppressed by a
2540 /// user-provided suppression specification or by an auto-generated
2541 /// "private type" suppression specification.
2542 ///
2543 /// Note that private type suppressions are auto-generated from the
2544 /// path to where public headers are, as given by the user.
2545 ///
2546 /// Here is the current algorithm:
2547 ///
2548 /// First, suppress this diff node if it's not matched by any
2549 /// negated suppression specifications. If it's not
2550 /// suppressed, then suppress it if it's matched by direct
2551 /// suppression specifications.
2552 ///
2553 /// @param is_private_type out parameter if the current diff node was
2554 /// suppressed because it's a private type then this parameter is set
2555 /// to true.
2556 ///
2557 /// @return true if the current diff node has been suppressed by a
2558 /// user-provided suppression list.
2559 bool
is_suppressed(bool & is_private_type) const2560 diff::is_suppressed(bool &is_private_type) const
2561 {
2562 // If there is at least one negated suppression, then suppress the
2563 // current diff node by default ...
2564 bool do_suppress = !context()->negated_suppressions().empty();
2565
2566 // ... unless there is at least one negated suppression that
2567 // specifically asks to keep this diff node around (un-suppressed).
2568 for (auto n : context()->negated_suppressions())
2569 if (!n->suppresses_diff(this))
2570 {
2571 do_suppress = false;
2572 break;
2573 }
2574
2575 // Then walk the set of non-negated, AKA direct, suppressions. If at
2576 // least one suppression suppresses the current diff node then the
2577 // diff node must be suppressed.
2578 for (auto d : context()->direct_suppressions())
2579 if (d->suppresses_diff(this))
2580 {
2581 do_suppress = true;
2582 if (is_private_type_suppr_spec(d))
2583 is_private_type = true;
2584 break;
2585 }
2586
2587 return do_suppress;
2588 }
2589
2590 /// Test if this diff tree node should be reported.
2591 ///
2592 /// @return true iff the current node should be reported.
2593 bool
to_be_reported() const2594 diff::to_be_reported() const
2595 {
2596 if (has_changes() && !is_filtered_out())
2597 return true;
2598 return false;
2599 }
2600
2601 /// Test if this diff tree node should be reported when considering
2602 /// the categories that were *NOT* inherited from its children nodes.
2603 ///
2604 /// @return true iff the current node should be reported.
2605 bool
has_local_changes_to_be_reported() const2606 diff::has_local_changes_to_be_reported() const
2607 {
2608 if (has_local_changes()
2609 && !is_filtered_out_wrt_non_inherited_categories())
2610 return true;
2611 return false;
2612 }
2613
2614 /// Test if this diff node is allowed (prevented from being
2615 /// suppressed) by at least one negated suppression specification.
2616 ///
2617 /// @return true if this diff node is meant to be allowed by at least
2618 /// one negated suppression specification.
2619 bool
is_allowed_by_specific_negated_suppression() const2620 diff::is_allowed_by_specific_negated_suppression() const
2621 {
2622 const suppressions_type& suppressions = context()->suppressions();
2623 for (suppressions_type::const_iterator i = suppressions.begin();
2624 i != suppressions.end();
2625 ++i)
2626 {
2627 if (is_negated_suppression(*i)
2628 && !(*i)->suppresses_diff(this))
2629 return true;
2630 }
2631 return false;
2632 }
2633
2634 /// Test if the current diff node has a descendant node which is
2635 /// specifically allowed by a negated suppression specification.
2636 ///
2637 /// @return true iff the current diff node has a descendant node
2638 /// which is specifically allowed by a negated suppression
2639 /// specification.
2640 bool
has_descendant_allowed_by_specific_negated_suppression() const2641 diff::has_descendant_allowed_by_specific_negated_suppression() const
2642 {
2643 bool result = (get_category() & HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY);
2644 return result;
2645 }
2646
2647 /// Test if the current diff node has a parent node which is
2648 /// specifically allowed by a negated suppression specification.
2649 ///
2650 /// @return true iff the current diff node has a parent node which is
2651 /// specifically allowed by a negated suppression specification.
2652 bool
has_parent_allowed_by_specific_negated_suppression() const2653 diff::has_parent_allowed_by_specific_negated_suppression() const
2654 {
2655 bool result = (get_category() & HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
2656 return result;
2657 }
2658
2659 /// Get a pretty representation of the current @ref diff node.
2660 ///
2661 /// This is suitable for e.g. emitting debugging traces for the diff
2662 /// tree nodes.
2663 ///
2664 /// @return the pretty representation of the diff node.
2665 const string&
get_pretty_representation() const2666 diff::get_pretty_representation() const
2667 {
2668 if (priv_->pretty_representation_.empty())
2669 priv_->pretty_representation_ = "empty_diff";
2670 return priv_->pretty_representation_;
2671 }
2672
2673 /// Default implementation of the hierachy chaining virtual function.
2674 ///
2675 /// There are several types of diff nodes that have logical children
2676 /// nodes; for instance, a typedef_diff has the diff of the underlying
2677 /// type as a child node. A var_diff has the diff of the types of the
2678 /// variables as a child node, etc.
2679 ///
2680 /// But because the @ref diff base has a generic representation for
2681 /// children nodes of the all the types of @ref diff nodes (regardless
2682 /// of the specific most-derived type of diff node) that one can get
2683 /// using the method diff::children_nodes(), one need to populate that
2684 /// vector of children node.
2685 ///
2686 /// Populating that vector of children node is done by this function;
2687 /// it must be overloaded by each most-derived type of diff node that
2688 /// extends the @ref diff type.
2689 void
chain_into_hierarchy()2690 diff::chain_into_hierarchy()
2691 {}
2692
2693 // </diff stuff>
2694
2695 // <type_diff_base stuff>
2696
type_diff_base(type_base_sptr first_subject,type_base_sptr second_subject,diff_context_sptr ctxt)2697 type_diff_base::type_diff_base(type_base_sptr first_subject,
2698 type_base_sptr second_subject,
2699 diff_context_sptr ctxt)
2700 : diff(first_subject, second_subject, ctxt),
2701 priv_(new priv)
2702 {}
2703
~type_diff_base()2704 type_diff_base::~type_diff_base()
2705 {}
2706 // </type_diff_base stuff>
2707
2708 // <decl_diff_base stuff>
2709
2710 /// Constructor of @ref decl_diff_base.
2711 ///
2712 /// @param first_subject the first subject of the diff.
2713 ///
2714 /// @param second_subject the second subject of the diff.
2715 ///
2716 /// @param ctxt the context of the diff. This object must stay alive
2717 /// at least during the life time of the current instance of @ref
2718 /// decl_diff_base, otherwise, memory corruption issues occur.
decl_diff_base(decl_base_sptr first_subject,decl_base_sptr second_subject,diff_context_sptr ctxt)2719 decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2720 decl_base_sptr second_subject,
2721 diff_context_sptr ctxt)
2722 : diff(first_subject, second_subject, ctxt),
2723 priv_(new priv)
2724 {}
2725
~decl_diff_base()2726 decl_diff_base::~decl_diff_base()
2727 {}
2728
2729 // </decl_diff_base stuff>
2730
2731 // <distinct_diff stuff>
2732
2733 /// @return a pretty representation for the @ref distinct_diff node.
2734 const string&
get_pretty_representation() const2735 distinct_diff::get_pretty_representation() const
2736 {
2737 if (diff::priv_->pretty_representation_.empty())
2738 {
2739 std::ostringstream o;
2740 o << "distinct_diff[";
2741 if (first_subject())
2742 o << first_subject()->get_pretty_representation();
2743 else
2744 o << "null";
2745 o << ", ";
2746 if (second_subject())
2747 o << second_subject()->get_pretty_representation() ;
2748 else
2749 o << "null";
2750 o << "]" ;
2751 diff::priv_->pretty_representation_ = o.str();
2752 }
2753 return diff::priv_->pretty_representation_;
2754 }
2755
2756 /// Populate the vector of children node of the @ref diff base type
2757 /// sub-object of this instance of @distinct_diff.
2758 ///
2759 /// The children nodes can then later be retrieved using
2760 /// diff::children_nodes().
2761 void
chain_into_hierarchy()2762 distinct_diff::chain_into_hierarchy()
2763 {
2764 ABG_ASSERT(entities_are_of_distinct_kinds(first(), second()));
2765
2766 if (diff_sptr d = compatible_child_diff())
2767 append_child_node(d);
2768 }
2769
2770 /// Constructor for @ref distinct_diff.
2771 ///
2772 /// Note that the two entities considered for the diff (and passed in
2773 /// parameter) must be of different kinds.
2774 ///
2775 /// @param first the first entity to consider for the diff.
2776 ///
2777 /// @param second the second entity to consider for the diff.
2778 ///
2779 /// @param ctxt the context of the diff. Note that this context
2780 /// object must stay alive at least during the life time of the
2781 /// current instance of @ref distinct_diff. Otherwise memory
2782 /// corruption issues occur.
distinct_diff(type_or_decl_base_sptr first,type_or_decl_base_sptr second,diff_context_sptr ctxt)2783 distinct_diff::distinct_diff(type_or_decl_base_sptr first,
2784 type_or_decl_base_sptr second,
2785 diff_context_sptr ctxt)
2786 : diff(first, second, ctxt),
2787 priv_(new priv)
2788 {ABG_ASSERT(entities_are_of_distinct_kinds(first, second));}
2789
2790 /// Getter for the first subject of the diff.
2791 ///
2792 /// @return the first subject of the diff.
2793 const type_or_decl_base_sptr
first() const2794 distinct_diff::first() const
2795 {return first_subject();}
2796
2797 /// Getter for the second subject of the diff.
2798 ///
2799 /// @return the second subject of the diff.
2800 const type_or_decl_base_sptr
second() const2801 distinct_diff::second() const
2802 {return second_subject();}
2803
2804 /// Getter for the child diff of this distinct_diff instance.
2805 ///
2806 /// When a distinct_diff has two subjects that are different but
2807 /// compatible, then the distinct_diff instance has a child diff node
2808 /// (named the compatible child diff) that is the diff between the two
2809 /// subjects stripped from their typedefs. Otherwise, the compatible
2810 /// child diff is nul.
2811 ///
2812 /// Note that two diff subjects (that compare different) are
2813 /// considered compatible if stripping typedefs out of them makes them
2814 /// comparing equal.
2815 ///
2816 /// @return the compatible child diff node, if any. Otherwise, null.
2817 const diff_sptr
compatible_child_diff() const2818 distinct_diff::compatible_child_diff() const
2819 {
2820 if (!priv_->compatible_child_diff)
2821 {
2822 type_base_sptr fs = strip_typedef(is_type(first())),
2823 ss = strip_typedef(is_type(second()));
2824
2825 if (fs && ss
2826 && !entities_are_of_distinct_kinds(get_type_declaration(fs),
2827 get_type_declaration(ss)))
2828 priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2829 get_type_declaration(ss),
2830 context());
2831 }
2832 return priv_->compatible_child_diff;
2833 }
2834
2835 /// Test if the two arguments are of different kind, or that are both
2836 /// NULL.
2837 ///
2838 /// @param first the first argument to test for similarity in kind.
2839 ///
2840 /// @param second the second argument to test for similarity in kind.
2841 ///
2842 /// @return true iff the two arguments are of different kind.
2843 bool
entities_are_of_distinct_kinds(type_or_decl_base_sptr first,type_or_decl_base_sptr second)2844 distinct_diff::entities_are_of_distinct_kinds(type_or_decl_base_sptr first,
2845 type_or_decl_base_sptr second)
2846 {
2847 if (!!first != !!second)
2848 return true;
2849 if (!first && !second)
2850 // We do consider diffs of two empty decls as a diff of distinct
2851 // kinds, for now.
2852 return true;
2853 if (first == second)
2854 return false;
2855
2856 const type_or_decl_base &f = *first, &s = *second;
2857 return typeid(f) != typeid(s);
2858 }
2859
2860 /// @return true if the two subjects of the diff are different, false
2861 /// otherwise.
2862 bool
has_changes() const2863 distinct_diff::has_changes() const
2864 {return first() != second();}
2865
2866 /// @return the kind of local change carried by the current diff node.
2867 /// The value returned is zero if the current node carries no local
2868 /// change.
2869 enum change_kind
has_local_changes() const2870 distinct_diff::has_local_changes() const
2871 {
2872 // Changes on a distinct_diff are all local.
2873 if (has_changes())
2874 return LOCAL_TYPE_CHANGE_KIND;
2875 return NO_CHANGE_KIND;
2876 }
2877
2878 /// Emit a report about the current diff instance.
2879 ///
2880 /// @param out the output stream to send the diff report to.
2881 ///
2882 /// @param indent the indentation string to use in the report.
2883 void
report(ostream & out,const string & indent) const2884 distinct_diff::report(ostream& out, const string& indent) const
2885 {
2886 context()->get_reporter()->report(*this, out, indent);
2887 }
2888
2889 /// Try to diff entities that are of distinct kinds.
2890 ///
2891 /// @param first the first entity to consider for the diff.
2892 ///
2893 /// @param second the second entity to consider for the diff.
2894 ///
2895 /// @param ctxt the context of the diff.
2896 ///
2897 /// @return a non-null diff if a diff object could be built, null
2898 /// otherwise.
2899 distinct_diff_sptr
compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2900 compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first,
2901 const type_or_decl_base_sptr second,
2902 diff_context_sptr ctxt)
2903 {
2904 if (!distinct_diff::entities_are_of_distinct_kinds(first, second))
2905 return distinct_diff_sptr();
2906
2907 distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2908
2909 ctxt->initialize_canonical_diff(result);
2910
2911 return result;
2912 }
2913
2914 /// </distinct_diff stuff>
2915
2916 /// Try to compute a diff on two instances of DiffType representation.
2917 ///
2918 /// The function template performs the diff if and only if the decl
2919 /// representations are of a DiffType.
2920 ///
2921 /// @tparm DiffType the type of instances to diff.
2922 ///
2923 /// @param first the first representation of decl to consider in the
2924 /// diff computation.
2925 ///
2926 /// @param second the second representation of decl to consider in the
2927 /// diff computation.
2928 ///
2929 /// @param ctxt the diff context to use.
2930 ///
2931 ///@return the diff of the two types @p first and @p second if and
2932 ///only if they represent the parametrized type DiffType. Otherwise,
2933 ///returns a NULL pointer value.
2934 template<typename DiffType>
2935 diff_sptr
try_to_diff(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2936 try_to_diff(const type_or_decl_base_sptr first,
2937 const type_or_decl_base_sptr second,
2938 diff_context_sptr ctxt)
2939 {
2940 if (shared_ptr<DiffType> f =
2941 dynamic_pointer_cast<DiffType>(first))
2942 {
2943 shared_ptr<DiffType> s =
2944 dynamic_pointer_cast<DiffType>(second);
2945 if (!s)
2946 return diff_sptr();
2947 return compute_diff(f, s, ctxt);
2948 }
2949 return diff_sptr();
2950 }
2951
2952
2953 /// This is a specialization of @ref try_to_diff() template to diff
2954 /// instances of @ref class_decl.
2955 ///
2956 /// @param first the first representation of decl to consider in the
2957 /// diff computation.
2958 ///
2959 /// @param second the second representation of decl to consider in the
2960 /// diff computation.
2961 ///
2962 /// @param ctxt the diff context to use.
2963 template<>
2964 diff_sptr
try_to_diff(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)2965 try_to_diff<class_decl>(const type_or_decl_base_sptr first,
2966 const type_or_decl_base_sptr second,
2967 diff_context_sptr ctxt)
2968 {
2969 if (class_decl_sptr f =
2970 dynamic_pointer_cast<class_decl>(first))
2971 {
2972 class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2973 if (!s)
2974 return diff_sptr();
2975
2976 if (f->get_is_declaration_only())
2977 {
2978 class_decl_sptr f2 =
2979 is_class_type (f->get_definition_of_declaration());
2980 if (f2)
2981 f = f2;
2982 }
2983 if (s->get_is_declaration_only())
2984 {
2985 class_decl_sptr s2 =
2986 is_class_type(s->get_definition_of_declaration());
2987 if (s2)
2988 s = s2;
2989 }
2990 return compute_diff(f, s, ctxt);
2991 }
2992 return diff_sptr();
2993 }
2994
2995 /// Try to diff entities that are of distinct kinds.
2996 ///
2997 /// @param first the first entity to consider for the diff.
2998 ///
2999 /// @param second the second entity to consider for the diff.
3000 ///
3001 /// @param ctxt the context of the diff.
3002 ///
3003 /// @return a non-null diff if a diff object could be built, null
3004 /// otherwise.
3005 static diff_sptr
try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,const type_or_decl_base_sptr second,diff_context_sptr ctxt)3006 try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3007 const type_or_decl_base_sptr second,
3008 diff_context_sptr ctxt)
3009 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
3010
3011 /// Compute the difference between two types.
3012 ///
3013 /// The function considers every possible types known to libabigail
3014 /// and runs the appropriate diff function on them.
3015 ///
3016 /// Whenever a new kind of type decl is supported by abigail, if we
3017 /// want to be able to diff two instances of it, we need to update
3018 /// this function to support it.
3019 ///
3020 /// @param first the first type decl to consider for the diff
3021 ///
3022 /// @param second the second type decl to consider for the diff.
3023 ///
3024 /// @param ctxt the diff context to use.
3025 ///
3026 /// @return the resulting diff. It's a pointer to a descendent of
3027 /// abigail::comparison::diff.
3028 static diff_sptr
compute_diff_for_types(const type_or_decl_base_sptr & first,const type_or_decl_base_sptr & second,const diff_context_sptr & ctxt)3029 compute_diff_for_types(const type_or_decl_base_sptr& first,
3030 const type_or_decl_base_sptr& second,
3031 const diff_context_sptr& ctxt)
3032 {
3033 type_or_decl_base_sptr f = first;
3034 type_or_decl_base_sptr s = second;
3035
3036 diff_sptr d;
3037
3038 ((d = try_to_diff<type_decl>(f, s, ctxt))
3039 ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3040 ||(d = try_to_diff<union_decl>(f, s,ctxt))
3041 ||(d = try_to_diff<class_decl>(f, s,ctxt))
3042 ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3043 ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3044 ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3045 ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3046 ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3047 ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3048 ||(d = try_to_diff<function_type>(f, s, ctxt))
3049 ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3050
3051 ABG_ASSERT(d);
3052
3053 return d;
3054 }
3055
3056 diff_category
operator |(diff_category c1,diff_category c2)3057 operator|(diff_category c1, diff_category c2)
3058 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3059 | static_cast<unsigned>(c2));}
3060
3061 diff_category&
operator |=(diff_category & c1,diff_category c2)3062 operator|=(diff_category& c1, diff_category c2)
3063 {
3064 c1 = c1 | c2;
3065 return c1;
3066 }
3067
3068 diff_category&
operator &=(diff_category & c1,diff_category c2)3069 operator&=(diff_category& c1, diff_category c2)
3070 {
3071 c1 = c1 & c2;
3072 return c1;
3073 }
3074
3075 diff_category
operator ^(diff_category c1,diff_category c2)3076 operator^(diff_category c1, diff_category c2)
3077 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3078 ^ static_cast<unsigned>(c2));}
3079
3080 diff_category
operator &(diff_category c1,diff_category c2)3081 operator&(diff_category c1, diff_category c2)
3082 {return static_cast<diff_category>(static_cast<unsigned>(c1)
3083 & static_cast<unsigned>(c2));}
3084
3085 diff_category
operator ~(diff_category c)3086 operator~(diff_category c)
3087 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
3088
3089
3090 /// Getter of a bitmap made of the set of change categories that are
3091 /// considered harmless.
3092 ///
3093 /// @return the bitmap made of the set of change categories that are
3094 /// considered harmless.
3095 diff_category
get_default_harmless_categories_bitmap()3096 get_default_harmless_categories_bitmap()
3097 {
3098 return (abigail::comparison::ACCESS_CHANGE_CATEGORY
3099 | abigail::comparison::COMPATIBLE_TYPE_CHANGE_CATEGORY
3100 | abigail::comparison::HARMLESS_DECL_NAME_CHANGE_CATEGORY
3101 | abigail::comparison::NON_VIRT_MEM_FUN_CHANGE_CATEGORY
3102 | abigail::comparison::STATIC_DATA_MEMBER_CHANGE_CATEGORY
3103 | abigail::comparison::HARMLESS_ENUM_CHANGE_CATEGORY
3104 | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
3105 | abigail::comparison::HARMLESS_UNION_CHANGE_CATEGORY
3106 | abigail::comparison::HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
3107 | abigail::comparison::TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
3108 | abigail::comparison::FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
3109 | abigail::comparison::FN_PARM_TYPE_CV_CHANGE_CATEGORY
3110 | abigail::comparison::FN_RETURN_TYPE_CV_CHANGE_CATEGORY
3111 | abigail::comparison::VAR_TYPE_CV_CHANGE_CATEGORY
3112 | abigail::comparison::VOID_PTR_TO_PTR_CHANGE_CATEGORY
3113 | abigail::comparison::BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY);
3114 }
3115
3116 /// Getter of a bitmap made of the set of change categories that are
3117 /// considered harmful.
3118 ///
3119 /// @return the bitmap made of the set of change categories that are
3120 /// considered harmful.
3121 diff_category
get_default_harmful_categories_bitmap()3122 get_default_harmful_categories_bitmap()
3123 {
3124 return (abigail::comparison::SIZE_OR_OFFSET_CHANGE_CATEGORY
3125 | abigail::comparison::VIRTUAL_MEMBER_CHANGE_CATEGORY
3126 | abigail::comparison::FN_PARM_ADD_REMOVE_CHANGE_CATEGORY);
3127 }
3128
3129 /// Serialize an instance of @ref diff_category to an output stream.
3130 ///
3131 /// @param o the output stream to serialize @p c to.
3132 ///
3133 /// @param c the instance of diff_category to serialize.
3134 ///
3135 /// @return the output stream to serialize @p c to.
3136 ostream&
operator <<(ostream & o,diff_category c)3137 operator<<(ostream& o, diff_category c)
3138 {
3139 bool emitted_a_category = false;
3140
3141 if (c == NO_CHANGE_CATEGORY)
3142 {
3143 o << "NO_CHANGE_CATEGORY";
3144 emitted_a_category = true;
3145 }
3146
3147 if (c & ACCESS_CHANGE_CATEGORY)
3148 {
3149 if (emitted_a_category)
3150 o << "|";
3151 o << "ACCESS_CHANGE_CATEGORY";
3152 emitted_a_category |= true;
3153 }
3154
3155 if (c & COMPATIBLE_TYPE_CHANGE_CATEGORY)
3156 {
3157 if (emitted_a_category)
3158 o << "|";
3159 o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3160 emitted_a_category |= true;
3161 }
3162
3163 if (c & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
3164 {
3165 if (emitted_a_category)
3166 o << "|";
3167 o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3168 emitted_a_category |= true;
3169 }
3170
3171 if (c & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
3172 {
3173 if (emitted_a_category)
3174 o << "|";
3175 o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3176 emitted_a_category |= true;
3177 }
3178
3179 if (c & STATIC_DATA_MEMBER_CHANGE_CATEGORY)
3180 {
3181 if (emitted_a_category)
3182 o << "|";
3183 o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3184 emitted_a_category |= true;
3185 }
3186
3187 if (c & HARMLESS_ENUM_CHANGE_CATEGORY)
3188 {
3189 if (emitted_a_category)
3190 o << "|";
3191 o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3192 emitted_a_category |= true;
3193 }
3194
3195 if (c & HARMLESS_DATA_MEMBER_CHANGE_CATEGORY)
3196 {
3197 if (emitted_a_category)
3198 o << "|";
3199 o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3200 emitted_a_category |= true;
3201 }
3202
3203 if (c & HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY)
3204 {
3205 if (emitted_a_category)
3206 o << "|";
3207 o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3208 emitted_a_category |= true;
3209 }
3210
3211 if (c & HARMLESS_UNION_CHANGE_CATEGORY)
3212 {
3213 if (emitted_a_category)
3214 o << "|";
3215 o << "HARMLESS_UNION_CHANGE_CATEGORY";
3216 emitted_a_category |= true;
3217 }
3218
3219 if (c & SUPPRESSED_CATEGORY)
3220 {
3221 if (emitted_a_category)
3222 o << "|";
3223 o << "SUPPRESSED_CATEGORY";
3224 emitted_a_category |= true;
3225 }
3226
3227 if (c & PRIVATE_TYPE_CATEGORY)
3228 {
3229 if (emitted_a_category)
3230 o << "|";
3231 o << "PRIVATE_TYPE_CATEGORY";
3232 emitted_a_category |= true;
3233 }
3234
3235 if (c & SIZE_OR_OFFSET_CHANGE_CATEGORY)
3236 {
3237 if (emitted_a_category)
3238 o << "|";
3239 o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3240 emitted_a_category |= true;
3241 }
3242
3243 if (c & VIRTUAL_MEMBER_CHANGE_CATEGORY)
3244 {
3245 if (emitted_a_category)
3246 o << "|";
3247 o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3248 emitted_a_category |= true;
3249 }
3250
3251 if (c & REDUNDANT_CATEGORY)
3252 {
3253 if (emitted_a_category)
3254 o << "|";
3255 o << "REDUNDANT_CATEGORY";
3256 emitted_a_category |= true;
3257 }
3258
3259 if (c & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
3260 {
3261 if (emitted_a_category)
3262 o << "|";
3263 o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3264 emitted_a_category |= true;
3265 }
3266
3267 if (c & FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY)
3268 {
3269 if (emitted_a_category)
3270 o << "|";
3271 o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3272 emitted_a_category |= true;
3273 }
3274
3275 if (c & FN_PARM_TYPE_CV_CHANGE_CATEGORY)
3276 {
3277 if (emitted_a_category)
3278 o << "|";
3279 o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3280 emitted_a_category |= true;
3281 }
3282
3283 if (c & FN_RETURN_TYPE_CV_CHANGE_CATEGORY)
3284 {
3285 if (emitted_a_category)
3286 o << "|";
3287 o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3288 emitted_a_category |= true;
3289 }
3290
3291 if (c & FN_PARM_ADD_REMOVE_CHANGE_CATEGORY)
3292 {
3293 if (emitted_a_category)
3294 o << "|";
3295 o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3296 emitted_a_category |= true;
3297 }
3298
3299 if (c & VAR_TYPE_CV_CHANGE_CATEGORY)
3300 {
3301 if (emitted_a_category)
3302 o << "|";
3303 o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3304 emitted_a_category |= true;
3305 }
3306
3307 if (c & VOID_PTR_TO_PTR_CHANGE_CATEGORY)
3308 {
3309 if (emitted_a_category)
3310 o << "|";
3311 o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3312 emitted_a_category |= true;
3313 }
3314
3315 if (c & BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY)
3316 {
3317 if (emitted_a_category)
3318 o << "|";
3319 o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3320 emitted_a_category |= true;
3321 }
3322
3323 if (c & HAS_ALLOWED_CHANGE_CATEGORY)
3324 {
3325 if (emitted_a_category)
3326 o << "|";
3327 o << "HAS_ALLOWED_CHANGE_CATEGORY";
3328 emitted_a_category |= true;
3329 }
3330
3331 if (c & HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY)
3332 {
3333 if (emitted_a_category)
3334 o << "|";
3335 o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3336 emitted_a_category |= true;
3337 }
3338
3339 if (c & HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY)
3340 {
3341 if (emitted_a_category)
3342 o << "|";
3343 o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3344 emitted_a_category |= true;
3345 }
3346
3347 return o;
3348 }
3349
3350 /// Compute the difference between two decls.
3351 ///
3352 /// The function consider every possible decls known to libabigail and
3353 /// runs the appropriate diff function on them.
3354 ///
3355 /// Whenever a new kind of non-type decl is supported by abigail, if
3356 /// we want to be able to diff two instances of it, we need to update
3357 /// this function to support it.
3358 ///
3359 /// @param first the first decl to consider for the diff
3360 ///
3361 /// @param second the second decl to consider for the diff.
3362 ///
3363 /// @param ctxt the diff context to use.
3364 ///
3365 /// @return the resulting diff.
3366 static diff_sptr
compute_diff_for_decls(const decl_base_sptr first,const decl_base_sptr second,diff_context_sptr ctxt)3367 compute_diff_for_decls(const decl_base_sptr first,
3368 const decl_base_sptr second,
3369 diff_context_sptr ctxt)
3370 {
3371
3372 diff_sptr d;
3373
3374 ((d = try_to_diff<function_decl>(first, second, ctxt))
3375 || (d = try_to_diff<var_decl>(first, second, ctxt))
3376 || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3377
3378 ABG_ASSERT(d);
3379
3380 return d;
3381 }
3382
3383 /// Compute the difference between two decls. The decls can represent
3384 /// either type declarations, or non-type declaration.
3385 ///
3386 /// Note that the two decls must have been created in the same @ref
3387 /// environment, otherwise, this function aborts.
3388 ///
3389 /// @param first the first decl to consider.
3390 ///
3391 /// @param second the second decl to consider.
3392 ///
3393 /// @param ctxt the diff context to use.
3394 ///
3395 /// @return the resulting diff, or NULL if the diff could not be
3396 /// computed.
3397 diff_sptr
compute_diff(const decl_base_sptr first,const decl_base_sptr second,diff_context_sptr ctxt)3398 compute_diff(const decl_base_sptr first,
3399 const decl_base_sptr second,
3400 diff_context_sptr ctxt)
3401 {
3402 if (!first || !second)
3403 return diff_sptr();
3404
3405 diff_sptr d;
3406 if (is_type(first) && is_type(second))
3407 d = compute_diff_for_types(first, second, ctxt);
3408 else
3409 d = compute_diff_for_decls(first, second, ctxt);
3410 ABG_ASSERT(d);
3411 return d;
3412 }
3413
3414 /// Compute the difference between two types.
3415 ///
3416 /// Note that the two types must have been created in the same @ref
3417 /// environment, otherwise, this function aborts.
3418 ///
3419 /// @param first the first type to consider.
3420 ///
3421 /// @param second the second type to consider.
3422 ///
3423 /// @param ctxt the diff context to use.
3424 ///
3425 /// @return the resulting diff, or NULL if the diff couldn't be
3426 /// computed.
3427 diff_sptr
compute_diff(const type_base_sptr first,const type_base_sptr second,diff_context_sptr ctxt)3428 compute_diff(const type_base_sptr first,
3429 const type_base_sptr second,
3430 diff_context_sptr ctxt)
3431 {
3432 decl_base_sptr f = get_type_declaration(first),
3433 s = get_type_declaration(second);
3434
3435 diff_sptr d = compute_diff_for_types(f,s, ctxt);
3436 ABG_ASSERT(d);
3437 return d;
3438 }
3439
3440 /// Get a copy of the pretty representation of a diff node.
3441 ///
3442 /// @param d the diff node to consider.
3443 ///
3444 /// @return the pretty representation string.
3445 string
get_pretty_representation(diff * d)3446 get_pretty_representation(diff* d)
3447 {
3448 if (!d)
3449 return "";
3450 string prefix= "diff of ";
3451 return prefix + get_pretty_representation(d->first_subject());
3452 }
3453
3454 // <var_diff stuff>
3455
3456 /// Populate the vector of children node of the @ref diff base type
3457 /// sub-object of this instance of @ref var_diff.
3458 ///
3459 /// The children node can then later be retrieved using
3460 /// diff::children_node().
3461 void
chain_into_hierarchy()3462 var_diff::chain_into_hierarchy()
3463 {append_child_node(type_diff());}
3464
3465 /// @return the pretty representation for this current instance of
3466 /// @ref var_diff.
3467 const string&
get_pretty_representation() const3468 var_diff::get_pretty_representation() const
3469 {
3470 if (diff::priv_->pretty_representation_.empty())
3471 {
3472 std::ostringstream o;
3473 o << "var_diff["
3474 << first_subject()->get_pretty_representation()
3475 << ", "
3476 << second_subject()->get_pretty_representation()
3477 << "]";
3478 diff::priv_->pretty_representation_ = o.str();
3479 }
3480 return diff::priv_->pretty_representation_;
3481 }
3482 /// Constructor for @ref var_diff.
3483 ///
3484 /// @param first the first instance of @ref var_decl to consider in
3485 /// the diff.
3486 ///
3487 /// @param second the second instance of @ref var_decl to consider in
3488 /// the diff.
3489 ///
3490 /// @param type_diff the diff between types of the instances of
3491 /// var_decl.
3492 ///
3493 /// @param ctxt the diff context to use.
var_diff(var_decl_sptr first,var_decl_sptr second,diff_sptr type_diff,diff_context_sptr ctxt)3494 var_diff::var_diff(var_decl_sptr first,
3495 var_decl_sptr second,
3496 diff_sptr type_diff,
3497 diff_context_sptr ctxt)
3498 : decl_diff_base(first, second, ctxt),
3499 priv_(new priv)
3500 {priv_->type_diff_ = type_diff;}
3501
3502 /// Getter for the first @ref var_decl of the diff.
3503 ///
3504 /// @return the first @ref var_decl of the diff.
3505 var_decl_sptr
first_var() const3506 var_diff::first_var() const
3507 {return dynamic_pointer_cast<var_decl>(first_subject());}
3508
3509 /// Getter for the second @ref var_decl of the diff.
3510 ///
3511 /// @return the second @ref var_decl of the diff.
3512 var_decl_sptr
second_var() const3513 var_diff::second_var() const
3514 {return dynamic_pointer_cast<var_decl>(second_subject());}
3515
3516 /// Getter for the diff of the types of the instances of @ref
3517 /// var_decl.
3518 ///
3519 /// @return the diff of the types of the instances of @ref var_decl.
3520 diff_sptr
type_diff() const3521 var_diff::type_diff() const
3522 {
3523 if (diff_sptr result = priv_->type_diff_.lock())
3524 return result;
3525 else
3526 {
3527 result = compute_diff(first_var()->get_type(),
3528 second_var()->get_type(),
3529 context());
3530 context()->keep_diff_alive(result);
3531 priv_->type_diff_ = result;
3532 return result;
3533 }
3534 }
3535
3536 /// Return true iff the diff node has a change.
3537 ///
3538 /// @return true iff the diff node has a change.
3539 bool
has_changes() const3540 var_diff::has_changes() const
3541 {return *first_var() != *second_var();}
3542
3543 /// @return the kind of local change carried by the current diff node.
3544 /// The value returned is zero if the current node carries no local
3545 /// change.
3546 enum change_kind
has_local_changes() const3547 var_diff::has_local_changes() const
3548 {
3549 ir::change_kind k = ir::NO_CHANGE_KIND;
3550 if (!equals(*first_var(), *second_var(), &k))
3551 return k & ir::ALL_LOCAL_CHANGES_MASK;
3552 return ir::NO_CHANGE_KIND;
3553 }
3554
3555 /// Report the diff in a serialized form.
3556 ///
3557 /// @param out the stream to serialize the diff to.
3558 ///
3559 /// @param indent the prefix to use for the indentation of this
3560 /// serialization.
3561 void
report(ostream & out,const string & indent) const3562 var_diff::report(ostream& out, const string& indent) const
3563 {
3564 context()->get_reporter()->report(*this, out, indent);
3565 }
3566
3567 /// Compute the diff between two instances of @ref var_decl.
3568 ///
3569 /// Note that the two decls must have been created in the same @ref
3570 /// environment, otherwise, this function aborts.
3571 ///
3572 /// @param first the first @ref var_decl to consider for the diff.
3573 ///
3574 /// @param second the second @ref var_decl to consider for the diff.
3575 ///
3576 /// @param ctxt the diff context to use.
3577 ///
3578 /// @return the resulting diff between the two @ref var_decl.
3579 var_diff_sptr
compute_diff(const var_decl_sptr first,const var_decl_sptr second,diff_context_sptr ctxt)3580 compute_diff(const var_decl_sptr first,
3581 const var_decl_sptr second,
3582 diff_context_sptr ctxt)
3583 {
3584 var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3585 ctxt->initialize_canonical_diff(d);
3586
3587 return d;
3588 }
3589
3590 // </var_diff stuff>
3591
3592 // <pointer_type_def stuff>
3593
3594 /// Populate the vector of children node of the @ref diff base type
3595 /// sub-object of this instance of @ref pointer_diff.
3596 ///
3597 /// The children node can then later be retrieved using
3598 /// diff::children_node().
3599 void
chain_into_hierarchy()3600 pointer_diff::chain_into_hierarchy()
3601 {append_child_node(underlying_type_diff());}
3602
3603 /// Constructor for a pointer_diff.
3604 ///
3605 /// @param first the first pointer to consider for the diff.
3606 ///
3607 /// @param second the secon pointer to consider for the diff.
3608 ///
3609 /// @param ctxt the diff context to use.
pointer_diff(pointer_type_def_sptr first,pointer_type_def_sptr second,diff_sptr underlying,diff_context_sptr ctxt)3610 pointer_diff::pointer_diff(pointer_type_def_sptr first,
3611 pointer_type_def_sptr second,
3612 diff_sptr underlying,
3613 diff_context_sptr ctxt)
3614 : type_diff_base(first, second, ctxt),
3615 priv_(new priv(underlying))
3616 {}
3617
3618 /// Getter for the first subject of a pointer diff
3619 ///
3620 /// @return the first pointer considered in this pointer diff.
3621 const pointer_type_def_sptr
first_pointer() const3622 pointer_diff::first_pointer() const
3623 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3624
3625 /// Getter for the second subject of a pointer diff
3626 ///
3627 /// @return the second pointer considered in this pointer diff.
3628 const pointer_type_def_sptr
second_pointer() const3629 pointer_diff::second_pointer() const
3630 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3631
3632 /// @return the pretty represenation for the current instance of @ref
3633 /// pointer_diff.
3634 const string&
get_pretty_representation() const3635 pointer_diff::get_pretty_representation() const
3636 {
3637 if (diff::priv_->pretty_representation_.empty())
3638 {
3639 std::ostringstream o;
3640 o << "pointer_diff["
3641 << first_subject()->get_pretty_representation()
3642 << ", "
3643 << second_subject()->get_pretty_representation()
3644 << "]";
3645 diff::priv_->pretty_representation_ = o.str();
3646 }
3647 return diff::priv_->pretty_representation_;
3648 }
3649
3650 /// Return true iff the current diff node carries a change.
3651 ///
3652 /// @return true iff the current diff node carries a change.
3653 bool
has_changes() const3654 pointer_diff::has_changes() const
3655 {return first_pointer() != second_pointer();}
3656
3657 /// @return the kind of local change carried by the current diff node.
3658 /// The value returned is zero if the current node carries no local
3659 /// change.
3660 enum change_kind
has_local_changes() const3661 pointer_diff::has_local_changes() const
3662 {
3663 ir::change_kind k = ir::NO_CHANGE_KIND;
3664 if (!equals(*first_pointer(), *second_pointer(), &k))
3665 return k & ir::ALL_LOCAL_CHANGES_MASK;
3666 return ir::NO_CHANGE_KIND;
3667 }
3668
3669 /// Getter for the diff between the pointed-to types of the pointers
3670 /// of this diff.
3671 ///
3672 /// @return the diff between the pointed-to types.
3673 diff_sptr
underlying_type_diff() const3674 pointer_diff::underlying_type_diff() const
3675 {return priv_->underlying_type_diff_;}
3676
3677 /// Setter for the diff between the pointed-to types of the pointers
3678 /// of this diff.
3679 ///
3680 /// @param d the new diff between the pointed-to types of the pointers
3681 /// of this diff.
3682 void
underlying_type_diff(const diff_sptr d)3683 pointer_diff::underlying_type_diff(const diff_sptr d)
3684 {priv_->underlying_type_diff_ = d;}
3685
3686 /// Report the diff in a serialized form.
3687 ///
3688 /// @param out the stream to serialize the diff to.
3689 ///
3690 /// @param indent the prefix to use for the indentation of this
3691 /// serialization.
3692 void
report(ostream & out,const string & indent) const3693 pointer_diff::report(ostream& out, const string& indent) const
3694 {
3695 context()->get_reporter()->report(*this, out, indent);
3696 }
3697
3698 /// Compute the diff between between two pointers.
3699 ///
3700 /// Note that the two types must have been created in the same @ref
3701 /// environment, otherwise, this function aborts.
3702 ///
3703 /// @param first the pointer to consider for the diff.
3704 ///
3705 /// @param second the pointer to consider for the diff.
3706 ///
3707 /// @return the resulting diff between the two pointers.
3708 ///
3709 /// @param ctxt the diff context to use.
3710 pointer_diff_sptr
compute_diff(pointer_type_def_sptr first,pointer_type_def_sptr second,diff_context_sptr ctxt)3711 compute_diff(pointer_type_def_sptr first,
3712 pointer_type_def_sptr second,
3713 diff_context_sptr ctxt)
3714 {
3715 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3716 second->get_pointed_to_type(),
3717 ctxt);
3718 pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3719 ctxt->initialize_canonical_diff(result);
3720
3721 return result;
3722 }
3723
3724 // </pointer_type_def>
3725
3726 // <subrange_diff >
3727
3728 /// Constructor of the @ref subrange_diff diff node type.
3729 ///
3730 /// @param first the first subrange type to consider for the diff.
3731 ///
3732 /// @param second the second subrange type to consider for the diff.
3733 ///
3734 /// @param underlying_type_diff the underlying type diff between @p
3735 /// first and @p second.
3736 ///
3737 /// @param ctxt the diff context to use.
subrange_diff(const array_type_def::subrange_sptr & first,const array_type_def::subrange_sptr & second,const diff_sptr & underlying_type_diff,const diff_context_sptr ctxt)3738 subrange_diff::subrange_diff
3739 (const array_type_def::subrange_sptr& first,
3740 const array_type_def::subrange_sptr& second,
3741 const diff_sptr& underlying_type_diff,
3742 const diff_context_sptr ctxt)
3743 : type_diff_base(first, second, ctxt),
3744 priv_(new priv(underlying_type_diff))
3745 {}
3746
3747
3748 /// Getter of the first subrange of the current instance @ref
3749 /// subrange_diff.
3750 ///
3751 /// @return The first subrange of the current instance @ref subrange_diff.
3752 const array_type_def::subrange_sptr
first_subrange() const3753 subrange_diff::first_subrange() const
3754 {return is_subrange_type(first_subject());}
3755
3756 /// Getter of the second subrange of the current instance @ref
3757 /// subrange_diff.
3758 ///
3759 /// @return The second subrange of the current instance @ref
3760 /// subrange_diff.
3761 const array_type_def::subrange_sptr
second_subrange() const3762 subrange_diff::second_subrange() const
3763 {return is_subrange_type(second_subject());}
3764
3765 /// Getter of the diff node of the underlying types of the current
3766 /// @ref subrange_diff diff node.
3767 ///
3768 /// @return The diff node of the underlying types of the current @ref
3769 /// subrange_diff diff node.
3770 const diff_sptr
underlying_type_diff() const3771 subrange_diff::underlying_type_diff() const
3772 {return priv_->underlying_type_diff_;}
3773
3774 /// Getter the pretty representation of the @ref subrange_diff diff
3775 /// node.
3776 ///
3777 /// @return The pretty representation of the @ref subrange_diff diff node.
3778 const string&
get_pretty_representation() const3779 subrange_diff::get_pretty_representation() const
3780 {
3781 if (diff::priv_->pretty_representation_.empty())
3782 {
3783 std::ostringstream o;
3784 o << "subrange_diff["
3785 << first_subject()->get_pretty_representation()
3786 << ","
3787 << second_subject()->get_pretty_representation()
3788 << "]";
3789 diff::priv_->pretty_representation_ = o.str();
3790 }
3791 return diff::priv_->pretty_representation_;
3792 }
3793
3794 /// Test if the current @ref subrange_diff node carries any change.
3795 ///
3796 /// @return true iff the current @ref subrange_diff node carries any
3797 /// change.
3798 bool
has_changes() const3799 subrange_diff::has_changes() const
3800 {return *first_subrange() != *second_subrange();}
3801
3802 /// Test if the current @ref subrange_diff node carries any local
3803 /// change.
3804 ///
3805 /// @return true iff the current @ref subrange_diff node carries any
3806 /// local change.
3807 enum change_kind
has_local_changes() const3808 subrange_diff::has_local_changes() const
3809 {
3810 ir::change_kind k = ir::NO_CHANGE_KIND;
3811 if (!equals(*first_subrange(), *second_subrange(), &k))
3812 return k & ir::ALL_LOCAL_CHANGES_MASK;
3813 return ir::NO_CHANGE_KIND;
3814 }
3815
3816 /// Report about the changes carried by this node.
3817 ///
3818 /// @param out the output stream to send the report to.
3819 ///
3820 /// @param indent the indentation string to use.
3821 void
report(ostream & out,const string & indent) const3822 subrange_diff::report(ostream& out, const string& indent) const
3823 {context()->get_reporter()->report(*this, out, indent);}
3824
3825 /// Populate the vector of children node of the @ref diff base type
3826 /// sub-object of this instance of @ref subrange_diff.
3827 ///
3828 /// The children node can then later be retrieved using
3829 /// diff::children_node().
3830 void
chain_into_hierarchy()3831 subrange_diff::chain_into_hierarchy()
3832 {append_child_node(underlying_type_diff());}
3833
3834 /// Compute the diff between two instances of @ref subrange_diff.
3835 ///
3836 /// Note that the two decls must have been created in the same @ref
3837 /// environment, otherwise, this function aborts.
3838 ///
3839 /// @param first the first @ref subrange_diff to consider for the diff.
3840 ///
3841 /// @param second the second @ref subrange_diff to consider for the diff.
3842 ///
3843 /// @param ctxt the diff context to use.
3844 ///
3845 /// @return the resulting diff between the two @ref subrange_diff.
3846 subrange_diff_sptr
compute_diff(array_type_def::subrange_sptr first,array_type_def::subrange_sptr second,diff_context_sptr ctxt)3847 compute_diff(array_type_def::subrange_sptr first,
3848 array_type_def::subrange_sptr second,
3849 diff_context_sptr ctxt)
3850 {
3851 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3852 second->get_underlying_type(),
3853 ctxt);
3854
3855 subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
3856 ctxt->initialize_canonical_diff(result);
3857 return result;
3858 }
3859
3860 //</subrange_diff >
3861
3862
3863 // <array_type_def>
3864
3865 /// Populate the vector of children node of the @ref diff base type
3866 /// sub-object of this instance of @ref array_diff.
3867 ///
3868 /// The children node can then later be retrieved using
3869 /// diff::children_node().
3870 void
chain_into_hierarchy()3871 array_diff::chain_into_hierarchy()
3872 {append_child_node(element_type_diff());}
3873
3874 /// Constructor for array_diff
3875 ///
3876 /// @param first the first array_type of the diff.
3877 ///
3878 /// @param second the second array_type of the diff.
3879 ///
3880 /// @param element_type_diff the diff between the two array element
3881 /// types.
3882 ///
3883 /// @param ctxt the diff context to use.
array_diff(const array_type_def_sptr first,const array_type_def_sptr second,diff_sptr element_type_diff,diff_context_sptr ctxt)3884 array_diff::array_diff(const array_type_def_sptr first,
3885 const array_type_def_sptr second,
3886 diff_sptr element_type_diff,
3887 diff_context_sptr ctxt)
3888 : type_diff_base(first, second, ctxt),
3889 priv_(new priv(element_type_diff))
3890 {}
3891
3892 /// Getter for the first array of the diff.
3893 ///
3894 /// @return the first array of the diff.
3895 const array_type_def_sptr
first_array() const3896 array_diff::first_array() const
3897 {return dynamic_pointer_cast<array_type_def>(first_subject());}
3898
3899 /// Getter for the second array of the diff.
3900 ///
3901 /// @return for the second array of the diff.
3902 const array_type_def_sptr
second_array() const3903 array_diff::second_array() const
3904 {return dynamic_pointer_cast<array_type_def>(second_subject());}
3905
3906 /// Getter for the diff between the two types of array elements.
3907 ///
3908 /// @return the diff between the two types of array elements.
3909 const diff_sptr&
element_type_diff() const3910 array_diff::element_type_diff() const
3911 {return priv_->element_type_diff_;}
3912
3913 /// Setter for the diff between the two array element types.
3914 ///
3915 /// @param d the new diff betweend the two array element types.
3916 void
element_type_diff(diff_sptr d)3917 array_diff::element_type_diff(diff_sptr d)
3918 {priv_->element_type_diff_ = d;}
3919
3920 /// @return the pretty representation for the current instance of @ref
3921 /// array_diff.
3922 const string&
get_pretty_representation() const3923 array_diff::get_pretty_representation() const
3924 {
3925 if (diff::priv_->pretty_representation_.empty())
3926 {
3927 std::ostringstream o;
3928 o << "array_diff["
3929 << first_subject()->get_pretty_representation()
3930 << ", "
3931 << second_subject()->get_pretty_representation()
3932 << "]";
3933 diff::priv_->pretty_representation_ = o.str();
3934 }
3935 return diff::priv_->pretty_representation_;
3936 }
3937
3938 /// Return true iff the current diff node carries a change.
3939 ///
3940 /// @return true iff the current diff node carries a change.
3941 bool
has_changes() const3942 array_diff::has_changes() const
3943 {
3944 bool l = false;
3945
3946 // the array element types match check for differing dimensions
3947 // etc...
3948 array_type_def_sptr
3949 f = dynamic_pointer_cast<array_type_def>(first_subject()),
3950 s = dynamic_pointer_cast<array_type_def>(second_subject());
3951
3952 if (f->get_name() != s->get_name())
3953 l |= true;
3954 if (f->get_size_in_bits() != s->get_size_in_bits())
3955 l |= true;
3956 if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3957 l |= true;
3958
3959 l |= element_type_diff()
3960 ? element_type_diff()->has_changes()
3961 : false;
3962
3963 return l;
3964 }
3965
3966
3967 /// @return the kind of local change carried by the current diff node.
3968 /// The value returned is zero if the current node carries no local
3969 /// change.
3970 enum change_kind
has_local_changes() const3971 array_diff::has_local_changes() const
3972 {
3973 ir::change_kind k = ir::NO_CHANGE_KIND;
3974 if (!equals(*first_array(), *second_array(), &k))
3975 return k & ir::ALL_LOCAL_CHANGES_MASK;
3976 return ir::NO_CHANGE_KIND;
3977 }
3978
3979 /// Report the diff in a serialized form.
3980 ///
3981 /// @param out the output stream to serialize the dif to.
3982 ///
3983 /// @param indent the string to use for indenting the report.
3984 void
report(ostream & out,const string & indent) const3985 array_diff::report(ostream& out, const string& indent) const
3986 {
3987 context()->get_reporter()->report(*this, out, indent);
3988 }
3989
3990 /// Compute the diff between two arrays.
3991 ///
3992 /// Note that the two types must have been created in the same @ref
3993 /// environment, otherwise, this function aborts.
3994 ///
3995 /// @param first the first array to consider for the diff.
3996 ///
3997 /// @param second the second array to consider for the diff.
3998 ///
3999 /// @param ctxt the diff context to use.
4000 array_diff_sptr
compute_diff(array_type_def_sptr first,array_type_def_sptr second,diff_context_sptr ctxt)4001 compute_diff(array_type_def_sptr first,
4002 array_type_def_sptr second,
4003 diff_context_sptr ctxt)
4004 {
4005 diff_sptr d = compute_diff_for_types(first->get_element_type(),
4006 second->get_element_type(),
4007 ctxt);
4008 array_diff_sptr result(new array_diff(first, second, d, ctxt));
4009 ctxt->initialize_canonical_diff(result);
4010 return result;
4011 }
4012 // </array_type_def>
4013
4014 // <reference_type_def>
4015
4016 /// Populate the vector of children node of the @ref diff base type
4017 /// sub-object of this instance of @ref reference_diff.
4018 ///
4019 /// The children node can then later be retrieved using
4020 /// diff::children_node().
4021 void
chain_into_hierarchy()4022 reference_diff::chain_into_hierarchy()
4023 {append_child_node(underlying_type_diff());}
4024
4025 /// Constructor for reference_diff
4026 ///
4027 /// @param first the first reference_type of the diff.
4028 ///
4029 /// @param second the second reference_type of the diff.
4030 ///
4031 /// @param ctxt the diff context to use.
reference_diff(const reference_type_def_sptr first,const reference_type_def_sptr second,diff_sptr underlying,diff_context_sptr ctxt)4032 reference_diff::reference_diff(const reference_type_def_sptr first,
4033 const reference_type_def_sptr second,
4034 diff_sptr underlying,
4035 diff_context_sptr ctxt)
4036 : type_diff_base(first, second, ctxt),
4037 priv_(new priv(underlying))
4038 {}
4039
4040 /// Getter for the first reference of the diff.
4041 ///
4042 /// @return the first reference of the diff.
4043 reference_type_def_sptr
first_reference() const4044 reference_diff::first_reference() const
4045 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
4046
4047 /// Getter for the second reference of the diff.
4048 ///
4049 /// @return for the second reference of the diff.
4050 reference_type_def_sptr
second_reference() const4051 reference_diff::second_reference() const
4052 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
4053
4054
4055 /// Getter for the diff between the two referred-to types.
4056 ///
4057 /// @return the diff between the two referred-to types.
4058 const diff_sptr&
underlying_type_diff() const4059 reference_diff::underlying_type_diff() const
4060 {return priv_->underlying_type_diff_;}
4061
4062 /// Setter for the diff between the two referred-to types.
4063 ///
4064 /// @param d the new diff betweend the two referred-to types.
4065 diff_sptr&
underlying_type_diff(diff_sptr d)4066 reference_diff::underlying_type_diff(diff_sptr d)
4067 {
4068 priv_->underlying_type_diff_ = d;
4069 return priv_->underlying_type_diff_;
4070 }
4071
4072 /// @return the pretty representation for the current instance of @ref
4073 /// reference_diff.
4074 const string&
get_pretty_representation() const4075 reference_diff::get_pretty_representation() const
4076 {
4077 if (diff::priv_->pretty_representation_.empty())
4078 {
4079 std::ostringstream o;
4080 o << "reference_diff["
4081 << first_subject()->get_pretty_representation()
4082 << ", "
4083 << second_subject()->get_pretty_representation()
4084 << "]";
4085 diff::priv_->pretty_representation_ = o.str();
4086 }
4087 return diff::priv_->pretty_representation_;
4088 }
4089
4090 /// Return true iff the current diff node carries a change.
4091 ///
4092 /// @return true iff the current diff node carries a change.
4093 bool
has_changes() const4094 reference_diff::has_changes() const
4095 {
4096 return first_reference() != second_reference();
4097 }
4098
4099 /// @return the kind of local change carried by the current diff node.
4100 /// The value returned is zero if the current node carries no local
4101 /// change.
4102 enum change_kind
has_local_changes() const4103 reference_diff::has_local_changes() const
4104 {
4105 ir::change_kind k = ir::NO_CHANGE_KIND;
4106 if (!equals(*first_reference(), *second_reference(), &k))
4107 return k & ir::ALL_LOCAL_CHANGES_MASK;
4108 return ir::NO_CHANGE_KIND;
4109 }
4110
4111 /// Report the diff in a serialized form.
4112 ///
4113 /// @param out the output stream to serialize the dif to.
4114 ///
4115 /// @param indent the string to use for indenting the report.
4116 void
report(ostream & out,const string & indent) const4117 reference_diff::report(ostream& out, const string& indent) const
4118 {
4119 context()->get_reporter()->report(*this, out, indent);
4120 }
4121
4122 /// Compute the diff between two references.
4123 ///
4124 /// Note that the two types must have been created in the same @ref
4125 /// environment, otherwise, this function aborts.
4126 ///
4127 /// @param first the first reference to consider for the diff.
4128 ///
4129 /// @param second the second reference to consider for the diff.
4130 ///
4131 /// @param ctxt the diff context to use.
4132 reference_diff_sptr
compute_diff(reference_type_def_sptr first,reference_type_def_sptr second,diff_context_sptr ctxt)4133 compute_diff(reference_type_def_sptr first,
4134 reference_type_def_sptr second,
4135 diff_context_sptr ctxt)
4136 {
4137 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4138 second->get_pointed_to_type(),
4139 ctxt);
4140 reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4141 ctxt->initialize_canonical_diff(result);
4142 return result;
4143 }
4144 // </reference_type_def>
4145
4146 // <qualified_type_diff stuff>
4147
4148 /// Populate the vector of children node of the @ref diff base type
4149 /// sub-object of this instance of @ref qualified_type_diff.
4150 ///
4151 /// The children node can then later be retrieved using
4152 /// diff::children_node().
4153 void
chain_into_hierarchy()4154 qualified_type_diff::chain_into_hierarchy()
4155 {append_child_node(leaf_underlying_type_diff());}
4156
4157 /// Constructor for qualified_type_diff.
4158 ///
4159 /// @param first the first qualified type of the diff.
4160 ///
4161 /// @param second the second qualified type of the diff.
4162 ///
4163 /// @param ctxt the diff context to use.
qualified_type_diff(qualified_type_def_sptr first,qualified_type_def_sptr second,diff_sptr under,diff_context_sptr ctxt)4164 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4165 qualified_type_def_sptr second,
4166 diff_sptr under,
4167 diff_context_sptr ctxt)
4168 : type_diff_base(first, second, ctxt),
4169 priv_(new priv(under))
4170 {}
4171
4172 /// Getter for the first qualified type of the diff.
4173 ///
4174 /// @return the first qualified type of the diff.
4175 const qualified_type_def_sptr
first_qualified_type() const4176 qualified_type_diff::first_qualified_type() const
4177 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4178
4179 /// Getter for the second qualified type of the diff.
4180 ///
4181 /// @return the second qualified type of the diff.
4182 const qualified_type_def_sptr
second_qualified_type() const4183 qualified_type_diff::second_qualified_type() const
4184 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4185
4186 /// Getter for the diff between the underlying types of the two
4187 /// qualified types.
4188 ///
4189 /// @return the diff between the underlying types of the two qualified
4190 /// types.
4191 diff_sptr
underlying_type_diff() const4192 qualified_type_diff::underlying_type_diff() const
4193 {return priv_->underlying_type_diff;}
4194
4195 /// Getter for the diff between the most underlying non-qualified
4196 /// types of two qualified types.
4197 ///
4198 /// @return the diff between the most underlying non-qualified types
4199 /// of two qualified types.
4200 diff_sptr
leaf_underlying_type_diff() const4201 qualified_type_diff::leaf_underlying_type_diff() const
4202 {
4203 if (!priv_->leaf_underlying_type_diff)
4204 priv_->leaf_underlying_type_diff
4205 = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4206 get_leaf_type(second_qualified_type()),
4207 context());
4208
4209 return priv_->leaf_underlying_type_diff;
4210 }
4211
4212 /// Setter for the diff between the underlying types of the two
4213 /// qualified types.
4214 ///
4215 /// @return the diff between the underlying types of the two qualified
4216 /// types.
4217 void
underlying_type_diff(const diff_sptr d)4218 qualified_type_diff::underlying_type_diff(const diff_sptr d)
4219 {priv_->underlying_type_diff = d;}
4220
4221 /// @return the pretty representation of the current instance of @ref
4222 /// qualified_type_diff.
4223 const string&
get_pretty_representation() const4224 qualified_type_diff::get_pretty_representation() const
4225 {
4226 if (diff::priv_->pretty_representation_.empty())
4227 {
4228 std::ostringstream o;
4229 o << "qualified_type_diff["
4230 << first_subject()->get_pretty_representation()
4231 << ", "
4232 << second_subject()->get_pretty_representation()
4233 << "]";
4234 diff::priv_->pretty_representation_ = o.str();
4235 }
4236 return diff::priv_->pretty_representation_;
4237 }
4238
4239 /// Return true iff the current diff node carries a change.
4240 ///
4241 /// @return true iff the current diff node carries a change.
4242 bool
has_changes() const4243 qualified_type_diff::has_changes() const
4244 {return first_qualified_type() != second_qualified_type();}
4245
4246 /// @return the kind of local change carried by the current diff node.
4247 /// The value returned is zero if the current node carries no local
4248 /// change.
4249 enum change_kind
has_local_changes() const4250 qualified_type_diff::has_local_changes() const
4251 {
4252 ir::change_kind k = ir::NO_CHANGE_KIND;
4253 if (!equals(*first_qualified_type(), *second_qualified_type(), &k))
4254 return k & ir::ALL_LOCAL_CHANGES_MASK;
4255 return ir::NO_CHANGE_KIND;
4256 }
4257
4258 /// Report the diff in a serialized form.
4259 ///
4260 /// @param out the output stream to serialize to.
4261 ///
4262 /// @param indent the string to use to indent the lines of the report.
4263 void
report(ostream & out,const string & indent) const4264 qualified_type_diff::report(ostream& out, const string& indent) const
4265 {
4266 context()->get_reporter()->report(*this, out, indent);
4267 }
4268
4269 /// Compute the diff between two qualified types.
4270 ///
4271 /// Note that the two types must have been created in the same @ref
4272 /// environment, otherwise, this function aborts.
4273 ///
4274 /// @param first the first qualified type to consider for the diff.
4275 ///
4276 /// @param second the second qualified type to consider for the diff.
4277 ///
4278 /// @param ctxt the diff context to use.
4279 qualified_type_diff_sptr
compute_diff(const qualified_type_def_sptr first,const qualified_type_def_sptr second,diff_context_sptr ctxt)4280 compute_diff(const qualified_type_def_sptr first,
4281 const qualified_type_def_sptr second,
4282 diff_context_sptr ctxt)
4283 {
4284 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4285 second->get_underlying_type(),
4286 ctxt);
4287 qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4288 d, ctxt));
4289 ctxt->initialize_canonical_diff(result);
4290 return result;
4291 }
4292
4293 // </qualified_type_diff stuff>
4294
4295 // <enum_diff stuff>
4296
4297 /// Clear the lookup tables useful for reporting an enum_diff.
4298 ///
4299 /// This function must be updated each time a lookup table is added or
4300 /// removed from the class_diff::priv.
4301 void
clear_lookup_tables()4302 enum_diff::clear_lookup_tables()
4303 {
4304 priv_->deleted_enumerators_.clear();
4305 priv_->inserted_enumerators_.clear();
4306 priv_->changed_enumerators_.clear();
4307 }
4308
4309 /// Tests if the lookup tables are empty.
4310 ///
4311 /// @return true if the lookup tables are empty, false otherwise.
4312 bool
lookup_tables_empty() const4313 enum_diff::lookup_tables_empty() const
4314 {
4315 return (priv_->deleted_enumerators_.empty()
4316 && priv_->inserted_enumerators_.empty()
4317 && priv_->changed_enumerators_.empty());
4318 }
4319
4320 /// If the lookup tables are not yet built, walk the differences and
4321 /// fill the lookup tables.
4322 void
ensure_lookup_tables_populated()4323 enum_diff::ensure_lookup_tables_populated()
4324 {
4325 if (!lookup_tables_empty())
4326 return;
4327
4328 {
4329 edit_script e = priv_->enumerators_changes_;
4330
4331 for (vector<deletion>::const_iterator it = e.deletions().begin();
4332 it != e.deletions().end();
4333 ++it)
4334 {
4335 unsigned i = it->index();
4336 const enum_type_decl::enumerator& n =
4337 first_enum()->get_enumerators()[i];
4338 const string& name = n.get_name();
4339 ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4340 == priv_->deleted_enumerators_.end());
4341 priv_->deleted_enumerators_[name] = n;
4342 }
4343
4344 for (vector<insertion>::const_iterator it = e.insertions().begin();
4345 it != e.insertions().end();
4346 ++it)
4347 {
4348 for (vector<unsigned>::const_iterator iit =
4349 it->inserted_indexes().begin();
4350 iit != it->inserted_indexes().end();
4351 ++iit)
4352 {
4353 unsigned i = *iit;
4354 const enum_type_decl::enumerator& n =
4355 second_enum()->get_enumerators()[i];
4356 const string& name = n.get_name();
4357 ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4358 == priv_->inserted_enumerators_.end());
4359 string_enumerator_map::const_iterator j =
4360 priv_->deleted_enumerators_.find(name);
4361 if (j == priv_->deleted_enumerators_.end())
4362 priv_->inserted_enumerators_[name] = n;
4363 else
4364 {
4365 if (j->second != n)
4366 priv_->changed_enumerators_[j->first] =
4367 std::make_pair(j->second, n);
4368 priv_->deleted_enumerators_.erase(j);
4369 }
4370 }
4371 }
4372 }
4373 }
4374
4375 /// Populate the vector of children node of the @ref diff base type
4376 /// sub-object of this instance of @ref enum_diff.
4377 ///
4378 /// The children node can then later be retrieved using
4379 /// diff::children_node().
4380 void
chain_into_hierarchy()4381 enum_diff::chain_into_hierarchy()
4382 {append_child_node(underlying_type_diff());}
4383
4384 /// Constructor for enum_diff.
4385 ///
4386 /// @param first the first enum type of the diff.
4387 ///
4388 /// @param second the second enum type of the diff.
4389 ///
4390 /// @param underlying_type_diff the diff of the two underlying types
4391 /// of the two enum types.
4392 ///
4393 /// @param ctxt the diff context to use.
enum_diff(const enum_type_decl_sptr first,const enum_type_decl_sptr second,const diff_sptr underlying_type_diff,const diff_context_sptr ctxt)4394 enum_diff::enum_diff(const enum_type_decl_sptr first,
4395 const enum_type_decl_sptr second,
4396 const diff_sptr underlying_type_diff,
4397 const diff_context_sptr ctxt)
4398 : type_diff_base(first, second, ctxt),
4399 priv_(new priv(underlying_type_diff))
4400 {}
4401
4402 /// @return the first enum of the diff.
4403 const enum_type_decl_sptr
first_enum() const4404 enum_diff::first_enum() const
4405 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4406
4407 /// @return the second enum of the diff.
4408 const enum_type_decl_sptr
second_enum() const4409 enum_diff::second_enum() const
4410 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4411
4412 /// @return the diff of the two underlying enum types.
4413 diff_sptr
underlying_type_diff() const4414 enum_diff::underlying_type_diff() const
4415 {return priv_->underlying_type_diff_;}
4416
4417 /// @return a map of the enumerators that were deleted.
4418 const string_enumerator_map&
deleted_enumerators() const4419 enum_diff::deleted_enumerators() const
4420 {return priv_->deleted_enumerators_;}
4421
4422 /// @return a map of the enumerators that were inserted
4423 const string_enumerator_map&
inserted_enumerators() const4424 enum_diff::inserted_enumerators() const
4425 {return priv_->inserted_enumerators_;}
4426
4427 /// @return a map of the enumerators that were changed
4428 const string_changed_enumerator_map&
changed_enumerators() const4429 enum_diff::changed_enumerators() const
4430 {return priv_->changed_enumerators_;}
4431
4432 /// @return the pretty representation of the current instance of @ref
4433 /// enum_diff.
4434 const string&
get_pretty_representation() const4435 enum_diff::get_pretty_representation() const
4436 {
4437 if (diff::priv_->pretty_representation_.empty())
4438 {
4439 std::ostringstream o;
4440 o << "enum_diff["
4441 << first_subject()->get_pretty_representation()
4442 << ", "
4443 << second_subject()->get_pretty_representation()
4444 << "]";
4445 diff::priv_->pretty_representation_ = o.str();
4446 }
4447 return diff::priv_->pretty_representation_;
4448 }
4449
4450 /// Return true iff the current diff node carries a change.
4451 ///
4452 /// @return true iff the current diff node carries a change.
4453 bool
has_changes() const4454 enum_diff::has_changes() const
4455 {return first_enum() != second_enum();}
4456
4457 /// @return the kind of local change carried by the current diff node.
4458 /// The value returned is zero if the current node carries no local
4459 /// change.
4460 enum change_kind
has_local_changes() const4461 enum_diff::has_local_changes() const
4462 {
4463 ir::change_kind k = ir::NO_CHANGE_KIND;
4464 if (!equals(*first_enum(), *second_enum(), &k))
4465 return k & ir::ALL_LOCAL_CHANGES_MASK;
4466 return ir::NO_CHANGE_KIND;
4467 }
4468
4469 /// Report the differences between the two enums.
4470 ///
4471 /// @param out the output stream to send the report to.
4472 ///
4473 /// @param indent the string to use for indentation.
4474 void
report(ostream & out,const string & indent) const4475 enum_diff::report(ostream& out, const string& indent) const
4476 {
4477 context()->get_reporter()->report(*this, out, indent);
4478 }
4479
4480 /// Compute the set of changes between two instances of @ref
4481 /// enum_type_decl.
4482 ///
4483 /// Note that the two types must have been created in the same @ref
4484 /// environment, otherwise, this function aborts.
4485 ///
4486 /// @param first a pointer to the first enum_type_decl to consider.
4487 ///
4488 /// @param second a pointer to the second enum_type_decl to consider.
4489 ///
4490 /// @return the resulting diff of the two enums @p first and @p
4491 /// second.
4492 ///
4493 /// @param ctxt the diff context to use.
4494 enum_diff_sptr
compute_diff(const enum_type_decl_sptr first,const enum_type_decl_sptr second,diff_context_sptr ctxt)4495 compute_diff(const enum_type_decl_sptr first,
4496 const enum_type_decl_sptr second,
4497 diff_context_sptr ctxt)
4498 {
4499 diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4500 second->get_underlying_type(),
4501 ctxt);
4502 enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4503 if (first != second)
4504 {
4505 compute_diff(first->get_enumerators().begin(),
4506 first->get_enumerators().end(),
4507 second->get_enumerators().begin(),
4508 second->get_enumerators().end(),
4509 d->priv_->enumerators_changes_);
4510 d->ensure_lookup_tables_populated();
4511 }
4512 ctxt->initialize_canonical_diff(d);
4513
4514 return d;
4515 }
4516 // </enum_diff stuff>
4517
4518 // <class_or_union_diff stuff>
4519
4520 /// Test if the current diff node carries a member type change for a
4521 /// member type which name is the same as the name of a given type
4522 /// declaration.
4523 ///
4524 /// @param d the type declaration which name should be equal to the
4525 /// name of the member type that might have changed.
4526 ///
4527 /// @return the member type that has changed, iff there were a member
4528 /// type (which name is the same as the name of @p d) that changed.
4529 /// Note that the member type that is returned is the new value of the
4530 /// member type that changed.
4531 type_or_decl_base_sptr
member_type_has_changed(decl_base_sptr d) const4532 class_or_union_diff::priv::member_type_has_changed(decl_base_sptr d) const
4533 {
4534 string qname = d->get_qualified_name();
4535 string_diff_sptr_map::const_iterator it =
4536 changed_member_types_.find(qname);
4537
4538 return ((it == changed_member_types_.end())
4539 ? type_or_decl_base_sptr()
4540 : it->second->second_subject());
4541 }
4542
4543 /// Test if the current diff node carries a data member change for a
4544 /// data member which name is the same as the name of a given type
4545 /// declaration.
4546 ///
4547 /// @param d the type declaration which name should be equal to the
4548 /// name of the data member that might have changed.
4549 ///
4550 /// @return the data member that has changed, iff there were a data
4551 /// member type (which name is the same as the name of @p d) that
4552 /// changed. Note that the data member that is returned is the new
4553 /// value of the data member that changed.
4554 decl_base_sptr
subtype_changed_dm(decl_base_sptr d) const4555 class_or_union_diff::priv::subtype_changed_dm(decl_base_sptr d) const
4556 {
4557 string qname = d->get_qualified_name();
4558 string_var_diff_sptr_map::const_iterator it =
4559 subtype_changed_dm_.find(qname);
4560
4561 if (it == subtype_changed_dm_.end())
4562 return decl_base_sptr();
4563 return it->second->second_var();
4564 }
4565
4566 /// Test if the current diff node carries a member class template
4567 /// change for a member class template which name is the same as the
4568 /// name of a given type declaration.
4569 ///
4570 /// @param d the type declaration which name should be equal to the
4571 /// name of the member class template that might have changed.
4572 ///
4573 /// @return the member class template that has changed, iff there were
4574 /// a member class template (which name is the same as the name of @p
4575 /// d) that changed. Note that the member class template that is
4576 /// returned is the new value of the member class template that
4577 /// changed.
4578 decl_base_sptr
member_class_tmpl_has_changed(decl_base_sptr d) const4579 class_or_union_diff::priv::member_class_tmpl_has_changed(decl_base_sptr d) const
4580 {
4581 string qname = d->get_qualified_name();
4582 string_diff_sptr_map::const_iterator it =
4583 changed_member_class_tmpls_.find(qname);
4584
4585 return ((it == changed_member_class_tmpls_.end())
4586 ? decl_base_sptr()
4587 : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4588 }
4589
4590 /// Get the number of non static data members that were deleted.
4591 ///
4592 /// @return the number of non static data members that were deleted.
4593 size_t
get_deleted_non_static_data_members_number() const4594 class_or_union_diff::priv::get_deleted_non_static_data_members_number() const
4595 {
4596 size_t result = 0;
4597
4598 for (string_decl_base_sptr_map::const_iterator i =
4599 deleted_data_members_.begin();
4600 i != deleted_data_members_.end();
4601 ++i)
4602 if (is_member_decl(i->second)
4603 && !get_member_is_static(i->second))
4604 ++result;
4605
4606 return result;
4607 }
4608
4609 /// Get the number of non static data members that were inserted.
4610 ///
4611 /// @return the number of non static data members that were inserted.
4612 size_t
get_inserted_non_static_data_members_number() const4613 class_or_union_diff::priv::get_inserted_non_static_data_members_number() const
4614 {
4615 size_t result = 0;
4616
4617 for (string_decl_base_sptr_map::const_iterator i =
4618 inserted_data_members_.begin();
4619 i != inserted_data_members_.end();
4620 ++i)
4621 if (is_member_decl(i->second)
4622 && !get_member_is_static(i->second))
4623 ++result;
4624
4625 return result;
4626 }
4627
4628 /// Get the number of data member sub-type changes carried by the
4629 /// current diff node that were filtered out.
4630 ///
4631 /// @param local_only if true, it means that only (filtered) local
4632 /// changes are considered.
4633 ///
4634 /// @return the number of data member sub-type changes carried by the
4635 /// current diff node that were filtered out.
4636 size_t
count_filtered_subtype_changed_dm(bool local_only)4637 class_or_union_diff::priv::count_filtered_subtype_changed_dm(bool local_only)
4638 {
4639 size_t num_filtered= 0;
4640 for (var_diff_sptrs_type::const_iterator i =
4641 sorted_subtype_changed_dm_.begin();
4642 i != sorted_subtype_changed_dm_.end();
4643 ++i)
4644 {
4645 if (local_only)
4646 {
4647 if ((*i)->has_changes()
4648 && !(*i)->has_local_changes_to_be_reported())
4649 ++num_filtered;
4650 }
4651 else
4652 {
4653 if ((*i)->is_filtered_out())
4654 ++num_filtered;
4655 }
4656 }
4657 return num_filtered;
4658 }
4659
4660 /// Get the number of data member changes carried by the current diff
4661 /// node that were filtered out.
4662 ///
4663 /// @param local_only if true, it means that only (filtered) local
4664 /// changes are considered.
4665 ///
4666 /// @return the number of data member changes carried by the current
4667 /// diff node that were filtered out.
4668 size_t
count_filtered_changed_dm(bool local_only)4669 class_or_union_diff::priv::count_filtered_changed_dm(bool local_only)
4670 {
4671 size_t num_filtered= 0;
4672
4673 for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4674 i != changed_dm_.end();
4675 ++i)
4676 {
4677 diff_sptr diff = i->second;
4678 if (local_only)
4679 {
4680 if ((diff->has_changes() && !diff->has_local_changes_to_be_reported())
4681 || diff->is_filtered_out())
4682 ++num_filtered;
4683 }
4684 else
4685 {
4686 if (diff->is_filtered_out())
4687 ++num_filtered;
4688 }
4689 }
4690 return num_filtered;
4691 }
4692
4693 /// Skip the processing of the current member function if its
4694 /// virtual-ness is disallowed by the user.
4695 ///
4696 /// This is to be used in the member functions below that are used to
4697 /// count the number of filtered inserted, deleted and changed member
4698 /// functions.
4699 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
4700 do { \
4701 if (get_member_function_is_virtual(f) \
4702 || get_member_function_is_virtual(s)) \
4703 { \
4704 if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
4705 continue; \
4706 } \
4707 else \
4708 { \
4709 if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
4710 continue; \
4711 } \
4712 } while (false)
4713
4714 /// Get the number of member functions changes carried by the current
4715 /// diff node that were filtered out.
4716 ///
4717 /// @return the number of member functions changes carried by the
4718 /// current diff node that were filtered out.
4719 size_t
count_filtered_changed_mem_fns(const diff_context_sptr & ctxt)4720 class_or_union_diff::priv::count_filtered_changed_mem_fns
4721 (const diff_context_sptr& ctxt)
4722 {
4723 size_t count = 0;
4724 diff_category allowed_category = ctxt->get_allowed_category();
4725
4726 for (function_decl_diff_sptrs_type::const_iterator i =
4727 sorted_changed_member_functions_.begin();
4728 i != sorted_changed_member_functions_.end();
4729 ++i)
4730 {
4731 method_decl_sptr f =
4732 dynamic_pointer_cast<method_decl>
4733 ((*i)->first_function_decl());
4734 ABG_ASSERT(f);
4735
4736 method_decl_sptr s =
4737 dynamic_pointer_cast<method_decl>
4738 ((*i)->second_function_decl());
4739 ABG_ASSERT(s);
4740
4741 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4742
4743 diff_sptr diff = *i;
4744 ctxt->maybe_apply_filters(diff);
4745
4746 if (diff->is_filtered_out())
4747 ++count;
4748 }
4749
4750 return count;
4751 }
4752
4753 /// Get the number of member functions insertions carried by the current
4754 /// diff node that were filtered out.
4755 ///
4756 /// @return the number of member functions insertions carried by the
4757 /// current diff node that were filtered out.
4758 size_t
count_filtered_inserted_mem_fns(const diff_context_sptr & ctxt)4759 class_or_union_diff::priv::count_filtered_inserted_mem_fns
4760 (const diff_context_sptr& ctxt)
4761 {
4762 size_t count = 0;
4763 diff_category allowed_category = ctxt->get_allowed_category();
4764
4765 for (string_member_function_sptr_map::const_iterator i =
4766 inserted_member_functions_.begin();
4767 i != inserted_member_functions_.end();
4768 ++i)
4769 {
4770 method_decl_sptr f = i->second,
4771 s = i->second;
4772
4773 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4774
4775 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4776 ctxt->maybe_apply_filters(diff);
4777
4778 if (diff->get_category() != NO_CHANGE_CATEGORY
4779 && diff->is_filtered_out())
4780 ++count;
4781 }
4782
4783 return count;
4784 }
4785
4786 /// Get the number of member functions deletions carried by the current
4787 /// diff node that were filtered out.
4788 ///
4789 /// @return the number of member functions deletions carried by the
4790 /// current diff node that were filtered out.
4791 size_t
count_filtered_deleted_mem_fns(const diff_context_sptr & ctxt)4792 class_or_union_diff::priv::count_filtered_deleted_mem_fns
4793 (const diff_context_sptr& ctxt)
4794 {
4795 size_t count = 0;
4796 diff_category allowed_category = ctxt->get_allowed_category();
4797
4798 for (string_member_function_sptr_map::const_iterator i =
4799 deleted_member_functions_.begin();
4800 i != deleted_member_functions_.end();
4801 ++i)
4802 {
4803 method_decl_sptr f = i->second,
4804 s = i->second;
4805
4806 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
4807
4808 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4809 ctxt->maybe_apply_filters(diff);
4810
4811 if (diff->get_category() != NO_CHANGE_CATEGORY
4812 && diff->is_filtered_out())
4813 ++count;
4814 }
4815
4816 return count;
4817 }
4818
4819 /// Clear the lookup tables useful for reporting.
4820 ///
4821 /// This function must be updated each time a lookup table is added or
4822 /// removed from the class_or_union_diff::priv.
4823 void
clear_lookup_tables()4824 class_or_union_diff::clear_lookup_tables()
4825 {
4826 priv_->deleted_member_types_.clear();
4827 priv_->inserted_member_types_.clear();
4828 priv_->changed_member_types_.clear();
4829 priv_->deleted_data_members_.clear();
4830 priv_->inserted_data_members_.clear();
4831 priv_->subtype_changed_dm_.clear();
4832 priv_->deleted_member_functions_.clear();
4833 priv_->inserted_member_functions_.clear();
4834 priv_->changed_member_functions_.clear();
4835 priv_->deleted_member_class_tmpls_.clear();
4836 priv_->inserted_member_class_tmpls_.clear();
4837 priv_->changed_member_class_tmpls_.clear();
4838 }
4839
4840 /// Tests if the lookup tables are empty.
4841 ///
4842 /// @return true if the lookup tables are empty, false otherwise.
4843 bool
lookup_tables_empty(void) const4844 class_or_union_diff::lookup_tables_empty(void) const
4845 {
4846 return (priv_->deleted_member_types_.empty()
4847 && priv_->inserted_member_types_.empty()
4848 && priv_->changed_member_types_.empty()
4849 && priv_->deleted_data_members_.empty()
4850 && priv_->inserted_data_members_.empty()
4851 && priv_->subtype_changed_dm_.empty()
4852 && priv_->inserted_member_functions_.empty()
4853 && priv_->deleted_member_functions_.empty()
4854 && priv_->changed_member_functions_.empty()
4855 && priv_->deleted_member_class_tmpls_.empty()
4856 && priv_->inserted_member_class_tmpls_.empty()
4857 && priv_->changed_member_class_tmpls_.empty());
4858 }
4859
4860 /// If the lookup tables are not yet built, walk the differences and
4861 /// fill them.
4862 void
ensure_lookup_tables_populated(void) const4863 class_or_union_diff::ensure_lookup_tables_populated(void) const
4864 {
4865 {
4866 edit_script& e = priv_->member_types_changes_;
4867
4868 for (vector<deletion>::const_iterator it = e.deletions().begin();
4869 it != e.deletions().end();
4870 ++it)
4871 {
4872 unsigned i = it->index();
4873 decl_base_sptr d =
4874 get_type_declaration(first_class_or_union()->get_member_types()[i]);
4875 class_or_union_sptr record_type = is_class_or_union_type(d);
4876 if (record_type && record_type->get_is_declaration_only())
4877 continue;
4878 string name = d->get_name();
4879 priv_->deleted_member_types_[name] = d;
4880 }
4881
4882 for (vector<insertion>::const_iterator it = e.insertions().begin();
4883 it != e.insertions().end();
4884 ++it)
4885 {
4886 for (vector<unsigned>::const_iterator iit =
4887 it->inserted_indexes().begin();
4888 iit != it->inserted_indexes().end();
4889 ++iit)
4890 {
4891 unsigned i = *iit;
4892 decl_base_sptr d =
4893 get_type_declaration(second_class_or_union()->get_member_types()[i]);
4894 class_or_union_sptr record_type = is_class_or_union_type(d);
4895 if (record_type && record_type->get_is_declaration_only())
4896 continue;
4897 string name = d->get_name();
4898 string_decl_base_sptr_map::const_iterator j =
4899 priv_->deleted_member_types_.find(name);
4900 if (j != priv_->deleted_member_types_.end())
4901 {
4902 if (*j->second != *d)
4903 priv_->changed_member_types_[name] =
4904 compute_diff(j->second, d, context());
4905
4906 priv_->deleted_member_types_.erase(j);
4907 }
4908 else
4909 priv_->inserted_member_types_[name] = d;
4910 }
4911 }
4912 }
4913
4914 {
4915 edit_script& e = priv_->data_members_changes_;
4916
4917 for (vector<deletion>::const_iterator it = e.deletions().begin();
4918 it != e.deletions().end();
4919 ++it)
4920 {
4921 unsigned i = it->index();
4922 var_decl_sptr data_member =
4923 is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
4924 string name = data_member->get_anon_dm_reliable_name();
4925
4926 ABG_ASSERT(priv_->deleted_data_members_.find(name)
4927 == priv_->deleted_data_members_.end());
4928 priv_->deleted_data_members_[name] = data_member;
4929 }
4930
4931 for (vector<insertion>::const_iterator it = e.insertions().begin();
4932 it != e.insertions().end();
4933 ++it)
4934 {
4935 for (vector<unsigned>::const_iterator iit =
4936 it->inserted_indexes().begin();
4937 iit != it->inserted_indexes().end();
4938 ++iit)
4939 {
4940 unsigned i = *iit;
4941 decl_base_sptr d =
4942 second_class_or_union()->get_non_static_data_members()[i];
4943 var_decl_sptr added_dm = is_var_decl(d);
4944 string name = added_dm->get_anon_dm_reliable_name();
4945 ABG_ASSERT(priv_->inserted_data_members_.find(name)
4946 == priv_->inserted_data_members_.end());
4947
4948 bool ignore_added_anonymous_data_member = false;
4949 if (is_anonymous_data_member(added_dm))
4950 {
4951 //
4952 // Handle insertion of anonymous data member to
4953 // replace existing data members.
4954 //
4955 // For instance consider this:
4956 // struct S
4957 // {
4958 // int a;
4959 // int b;
4960 // int c;
4961 // };// end struct S
4962 //
4963 // Where the data members 'a' and 'b' are replaced
4964 // by an anonymous data member without changing the
4965 // effective bit layout of the structure:
4966 //
4967 // struct S
4968 // {
4969 // struct
4970 // {
4971 // union
4972 // {
4973 // int a;
4974 // char a_1;
4975 // };
4976 // union
4977 // {
4978 // int b;
4979 // char b_1;
4980 // };
4981 // };
4982 // int c;
4983 // }; // end struct S
4984 //
4985 var_decl_sptr replaced_dm, replacing_dm;
4986 bool added_anon_dm_changes_dm = false;
4987 // The vector of data members replaced by anonymous
4988 // data members.
4989 vector<var_decl_sptr> dms_replaced_by_anon_dm;
4990
4991 //
4992 // Let's start collecting the set of data members
4993 // which have been replaced by anonymous types in a
4994 // harmless way. These are going to be collected into
4995 // dms_replaced_by_anon_dm and, ultimately, into
4996 // priv_->dms_replaced_by_adms_
4997 //
4998 for (string_decl_base_sptr_map::const_iterator it =
4999 priv_->deleted_data_members_.begin();
5000 it != priv_->deleted_data_members_.end();
5001 ++it)
5002 {
5003 // We don't support this pattern for anonymous
5004 // data members themselves being replaced. If
5005 // that occurs then we'll just report it verbatim.
5006 if (is_anonymous_data_member(it->second))
5007 continue;
5008
5009 string deleted_dm_name = it->second->get_name();
5010 if ((replacing_dm =
5011 find_data_member_from_anonymous_data_member(added_dm,
5012 deleted_dm_name)))
5013 {
5014 // So it looks like replacing_dm might have
5015 // replaced the data member which name is
5016 // 'deleted_dm_name'. Let's look deeper to be
5017 // sure.
5018 //
5019 // Note that replacing_dm is part (member) of
5020 // an anonymous data member that might replace
5021 // replaced_dm.
5022
5023 // So let's get that replaced data member.
5024 replaced_dm = is_var_decl(it->second);
5025 size_t replaced_dm_offset =
5026 get_data_member_offset(replaced_dm),
5027 replacing_dm_offset =
5028 get_absolute_data_member_offset(replacing_dm);
5029
5030 if (replaced_dm_offset != replacing_dm_offset)
5031 {
5032 // So the replacing data member and the
5033 // replaced data member don't have the
5034 // same offset. This is not the pattern we
5035 // are looking for. Rather, it looks like
5036 // the anonymous data member has *changed*
5037 // the data member.
5038 added_anon_dm_changes_dm = true;
5039 break;
5040 }
5041
5042 if (replaced_dm->get_type()->get_size_in_bits()
5043 == replaced_dm->get_type()->get_size_in_bits())
5044 dms_replaced_by_anon_dm.push_back(replaced_dm);
5045 else
5046 {
5047 added_anon_dm_changes_dm = true;
5048 break;
5049 }
5050 }
5051 }
5052
5053 // Now walk dms_replaced_by_anon_dm to fill up
5054 // priv_->dms_replaced_by_adms_ with the set of data
5055 // members replaced by anonymous data members.
5056 if (!added_anon_dm_changes_dm
5057 && !dms_replaced_by_anon_dm.empty())
5058 {
5059 // See if the added data member isn't too big.
5060 type_base_sptr added_dm_type = added_dm->get_type();
5061 ABG_ASSERT(added_dm_type);
5062 var_decl_sptr new_next_dm =
5063 get_next_data_member(second_class_or_union(),
5064 added_dm);
5065 var_decl_sptr old_next_dm =
5066 first_class_or_union()->find_data_member(new_next_dm);
5067
5068 if (!old_next_dm
5069 || (old_next_dm
5070 && (get_absolute_data_member_offset(old_next_dm)
5071 == get_absolute_data_member_offset(new_next_dm))))
5072 {
5073 // None of the data members that are replaced
5074 // by the added union should be considered as
5075 // having been deleted.
5076 ignore_added_anonymous_data_member = true;
5077 for (vector<var_decl_sptr>::const_iterator i =
5078 dms_replaced_by_anon_dm.begin();
5079 i != dms_replaced_by_anon_dm.end();
5080 ++i)
5081 {
5082 string n = (*i)->get_name();
5083 priv_->dms_replaced_by_adms_[n] =
5084 added_dm;
5085 priv_->deleted_data_members_.erase(n);
5086 }
5087 }
5088 }
5089 }
5090
5091 if (!ignore_added_anonymous_data_member)
5092 {
5093 // Detect changed data members.
5094 //
5095 // A changed data member (that we shall name D) is a data
5096 // member that satisfies the conditions below:
5097 //
5098 // 1/ It must have been added.
5099 //
5100 // 2/ It must have been deleted as well.
5101 //
5102 // 3/ It there must be a non-empty difference between the
5103 // deleted D and the added D.
5104 string_decl_base_sptr_map::const_iterator j =
5105 priv_->deleted_data_members_.find(name);
5106 if (j != priv_->deleted_data_members_.end())
5107 {
5108 if (*j->second != *d)
5109 {
5110 var_decl_sptr old_dm = is_var_decl(j->second);
5111 priv_->subtype_changed_dm_[name]=
5112 compute_diff(old_dm, added_dm, context());
5113 }
5114 priv_->deleted_data_members_.erase(j);
5115 }
5116 else
5117 priv_->inserted_data_members_[name] = d;
5118 }
5119 }
5120 }
5121
5122 // Now detect when a data member is deleted from offset N and
5123 // another one is added to offset N. In that case, we want to be
5124 // able to say that the data member at offset N changed.
5125 for (string_decl_base_sptr_map::const_iterator i =
5126 priv_->deleted_data_members_.begin();
5127 i != priv_->deleted_data_members_.end();
5128 ++i)
5129 {
5130 unsigned offset = get_data_member_offset(i->second);
5131 priv_->deleted_dm_by_offset_[offset] = i->second;
5132 }
5133
5134 for (string_decl_base_sptr_map::const_iterator i =
5135 priv_->inserted_data_members_.begin();
5136 i != priv_->inserted_data_members_.end();
5137 ++i)
5138 {
5139 unsigned offset = get_data_member_offset(i->second);
5140 priv_->inserted_dm_by_offset_[offset] = i->second;
5141 }
5142
5143 for (unsigned_decl_base_sptr_map::const_iterator i =
5144 priv_->inserted_dm_by_offset_.begin();
5145 i != priv_->inserted_dm_by_offset_.end();
5146 ++i)
5147 {
5148 unsigned_decl_base_sptr_map::const_iterator j =
5149 priv_->deleted_dm_by_offset_.find(i->first);
5150 if (j != priv_->deleted_dm_by_offset_.end())
5151 {
5152 var_decl_sptr old_dm = is_var_decl(j->second);
5153 var_decl_sptr new_dm = is_var_decl(i->second);
5154 priv_->changed_dm_[i->first] =
5155 compute_diff(old_dm, new_dm, context());
5156 }
5157 }
5158
5159 for (unsigned_var_diff_sptr_map::const_iterator i =
5160 priv_->changed_dm_.begin();
5161 i != priv_->changed_dm_.end();
5162 ++i)
5163 {
5164 priv_->deleted_dm_by_offset_.erase(i->first);
5165 priv_->inserted_dm_by_offset_.erase(i->first);
5166 priv_->deleted_data_members_.erase
5167 (i->second->first_var()->get_anon_dm_reliable_name());
5168 priv_->inserted_data_members_.erase
5169 (i->second->second_var()->get_anon_dm_reliable_name());
5170 }
5171 }
5172 sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5173 priv_->sorted_subtype_changed_dm_);
5174 sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5175 priv_->sorted_changed_dm_);
5176
5177 {
5178 edit_script& e = priv_->member_class_tmpls_changes_;
5179
5180 for (vector<deletion>::const_iterator it = e.deletions().begin();
5181 it != e.deletions().end();
5182 ++it)
5183 {
5184 unsigned i = it->index();
5185 decl_base_sptr d =
5186 first_class_or_union()->get_member_class_templates()[i]->
5187 as_class_tdecl();
5188 string name = d->get_name();
5189 ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5190 == priv_->deleted_member_class_tmpls_.end());
5191 priv_->deleted_member_class_tmpls_[name] = d;
5192 }
5193
5194 for (vector<insertion>::const_iterator it = e.insertions().begin();
5195 it != e.insertions().end();
5196 ++it)
5197 {
5198 for (vector<unsigned>::const_iterator iit =
5199 it->inserted_indexes().begin();
5200 iit != it->inserted_indexes().end();
5201 ++iit)
5202 {
5203 unsigned i = *iit;
5204 decl_base_sptr d =
5205 second_class_or_union()->get_member_class_templates()[i]->
5206 as_class_tdecl();
5207 string name = d->get_name();
5208 ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5209 == priv_->inserted_member_class_tmpls_.end());
5210 string_decl_base_sptr_map::const_iterator j =
5211 priv_->deleted_member_class_tmpls_.find(name);
5212 if (j != priv_->deleted_member_class_tmpls_.end())
5213 {
5214 if (*j->second != *d)
5215 priv_->changed_member_types_[name]=
5216 compute_diff(j->second, d, context());
5217 priv_->deleted_member_class_tmpls_.erase(j);
5218 }
5219 else
5220 priv_->inserted_member_class_tmpls_[name] = d;
5221 }
5222 }
5223 }
5224 sort_string_diff_sptr_map(priv_->changed_member_types_,
5225 priv_->sorted_changed_member_types_);
5226 }
5227
5228 /// Allocate the memory for the priv_ pimpl data member of the @ref
5229 /// class_or_union_diff class.
5230 void
allocate_priv_data()5231 class_or_union_diff::allocate_priv_data()
5232 {
5233 if (!priv_)
5234 priv_.reset(new priv);
5235 }
5236
5237 /// Constructor for the @ref class_or_union_diff class.
5238 ///
5239 /// @param first_scope the first @ref class_or_union of the diff node.
5240 ///
5241 /// @param second_scope the second @ref class_or_union of the diff node.
5242 ///
5243 /// @param ctxt the context of the diff.
class_or_union_diff(class_or_union_sptr first_scope,class_or_union_sptr second_scope,diff_context_sptr ctxt)5244 class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5245 class_or_union_sptr second_scope,
5246 diff_context_sptr ctxt)
5247 : type_diff_base(first_scope, second_scope, ctxt)
5248 //priv_(new priv)
5249 {}
5250
5251 /// Getter of the private data of the @ref class_or_union_diff type.
5252 ///
5253 /// Note that due to an optimization, the private data of @ref
5254 /// class_or_union_diff can be shared among several instances of
5255 /// class_or_union_diff, so you should never try to access
5256 /// class_or_union_diff::priv directly.
5257 ///
5258 /// When class_or_union_diff::priv is shared, this function returns
5259 /// the correct shared one.
5260 ///
5261 /// @return the (possibly) shared private data of the current instance
5262 /// of @ref class_or_union_diff.
5263 const class_or_union_diff::priv_ptr&
get_priv() const5264 class_or_union_diff::get_priv() const
5265 {
5266 if (priv_)
5267 return priv_;
5268
5269 // If the current class_or_union_diff::priv member is empty, then look for
5270 // the shared one, from the canonical type.
5271 class_or_union_diff *canonical =
5272 dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5273 ABG_ASSERT(canonical);
5274 ABG_ASSERT(canonical->priv_);
5275
5276 return canonical->priv_;
5277 }
5278
5279 /// Destructor of class_or_union_diff.
~class_or_union_diff()5280 class_or_union_diff::~class_or_union_diff()
5281 {
5282 }
5283
5284 /// @return the first @ref class_or_union involved in the diff.
5285 class_or_union_sptr
first_class_or_union() const5286 class_or_union_diff::first_class_or_union() const
5287 {return is_class_or_union_type(first_subject());}
5288
5289 /// @return the second @ref class_or_union involved in the diff.
5290 class_or_union_sptr
second_class_or_union() const5291 class_or_union_diff::second_class_or_union() const
5292 {return is_class_or_union_type(second_subject());}
5293
5294 /// @return the edit script of the member types of the two @ref
5295 /// class_or_union.
5296 const edit_script&
member_types_changes() const5297 class_or_union_diff::member_types_changes() const
5298 {return get_priv()->member_types_changes_;}
5299
5300 /// @return the edit script of the member types of the two @ref
5301 /// class_or_union.
5302 edit_script&
member_types_changes()5303 class_or_union_diff::member_types_changes()
5304 {return get_priv()->member_types_changes_;}
5305
5306 /// @return the edit script of the data members of the two @ref
5307 /// class_or_union.
5308 const edit_script&
data_members_changes() const5309 class_or_union_diff::data_members_changes() const
5310 {return get_priv()->data_members_changes_;}
5311
5312 /// @return the edit script of the data members of the two @ref
5313 /// class_or_union.
5314 edit_script&
data_members_changes()5315 class_or_union_diff::data_members_changes()
5316 {return get_priv()->data_members_changes_;}
5317
5318 /// Getter for the data members that got inserted.
5319 ///
5320 /// @return a map of data members that got inserted.
5321 const string_decl_base_sptr_map&
inserted_data_members() const5322 class_or_union_diff::inserted_data_members() const
5323 {return get_priv()->inserted_data_members_;}
5324
5325 /// Getter for the data members that got deleted.
5326 ///
5327 /// @return a map of data members that got deleted.
5328 const string_decl_base_sptr_map&
deleted_data_members() const5329 class_or_union_diff::deleted_data_members() const
5330 {return get_priv()->deleted_data_members_;}
5331
5332 /// @return the edit script of the member functions of the two @ref
5333 /// class_or_union.
5334 const edit_script&
member_fns_changes() const5335 class_or_union_diff::member_fns_changes() const
5336 {return get_priv()->member_fns_changes_;}
5337
5338 /// Getter for the virtual members functions that have had a change in
5339 /// a sub-type, without having a change in their symbol name.
5340 ///
5341 /// @return a sorted vector of virtual member functions that have a
5342 /// sub-type change.
5343 const function_decl_diff_sptrs_type&
changed_member_fns() const5344 class_or_union_diff::changed_member_fns() const
5345 {return get_priv()->sorted_changed_member_functions_;}
5346
5347 /// @return the edit script of the member functions of the two
5348 /// classes.
5349 edit_script&
member_fns_changes()5350 class_or_union_diff::member_fns_changes()
5351 {return get_priv()->member_fns_changes_;}
5352
5353 /// @return a map of member functions that got deleted.
5354 const string_member_function_sptr_map&
deleted_member_fns() const5355 class_or_union_diff::deleted_member_fns() const
5356 {return get_priv()->deleted_member_functions_;}
5357
5358 /// @return a map of member functions that got inserted.
5359 const string_member_function_sptr_map&
inserted_member_fns() const5360 class_or_union_diff::inserted_member_fns() const
5361 {return get_priv()->inserted_member_functions_;}
5362
5363 /// Getter of the map of data members that got replaced by another
5364 /// data member. The key of the map is the offset at which the
5365 /// element got replaced and the value is a pointer to the @ref
5366 /// var_diff representing the replacement of the data member.
5367 ///
5368 /// @return sorted vector of changed data member.
5369 const unsigned_var_diff_sptr_map&
changed_data_members() const5370 class_or_union_diff::changed_data_members() const
5371 {return get_priv()->changed_dm_;}
5372
5373 /// Getter of the sorted vector of data members that got replaced by
5374 /// another data member.
5375 ///
5376 /// @return sorted vector of changed data member.
5377 const var_diff_sptrs_type&
sorted_changed_data_members() const5378 class_or_union_diff::sorted_changed_data_members() const
5379 {return get_priv()->sorted_changed_dm_;}
5380
5381 /// Count the number of /filtered/ data members that got replaced by
5382 /// another data member.
5383 ///
5384 /// @return the number of changed data member that got filtered out.
5385 size_t
count_filtered_changed_data_members(bool local) const5386 class_or_union_diff::count_filtered_changed_data_members(bool local) const
5387 {return get_priv()->count_filtered_changed_dm(local);}
5388
5389 /// Getter of the sorted vector of data members with a (sub-)type change.
5390 ///
5391 /// @return sorted vector of changed data member.
5392 const var_diff_sptrs_type&
sorted_subtype_changed_data_members() const5393 class_or_union_diff::sorted_subtype_changed_data_members() const
5394 {return get_priv()->sorted_subtype_changed_dm_;}
5395
5396 /// Count the number of /filtered/ data members with a sub-type change.
5397 ///
5398 /// @return the number of changed data member that got filtered out.
5399 size_t
count_filtered_subtype_changed_data_members(bool local) const5400 class_or_union_diff::count_filtered_subtype_changed_data_members(bool local) const
5401 {return get_priv()->count_filtered_subtype_changed_dm(local);}
5402
5403 /// Get the map of data members that got replaced by anonymous data
5404 /// members.
5405 ///
5406 /// The key of a map entry is the name of the replaced data member and
5407 /// the value is the anonymous data member that replaces it.
5408 ///
5409 /// @return the map of data members replaced by anonymous data
5410 /// members.
5411 const string_decl_base_sptr_map&
data_members_replaced_by_adms() const5412 class_or_union_diff::data_members_replaced_by_adms() const
5413 {return get_priv()->dms_replaced_by_adms_;}
5414
5415 /// Get an ordered vector of of data members that got replaced by
5416 /// anonymous data members.
5417 ///
5418 /// This returns a vector of pair of two data members: the one that
5419 /// was replaced, and the anonymous data member that replaced it.
5420 ///
5421 /// @return the sorted vector data members replaced by anonymous data members.
5422 const changed_var_sptrs_type&
ordered_data_members_replaced_by_adms() const5423 class_or_union_diff::ordered_data_members_replaced_by_adms() const
5424 {
5425 if (priv_->dms_replaced_by_adms_ordered_.empty())
5426 {
5427 for (string_decl_base_sptr_map::const_iterator it =
5428 priv_->dms_replaced_by_adms_.begin();
5429 it != priv_->dms_replaced_by_adms_.end();
5430 ++it)
5431 {
5432 const var_decl_sptr dm =
5433 first_class_or_union()->find_data_member(it->first);
5434 ABG_ASSERT(dm);
5435 changed_var_sptr changed_dm(dm, is_data_member(it->second));
5436 priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5437 }
5438 sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5439 }
5440
5441 return priv_->dms_replaced_by_adms_ordered_;
5442 }
5443
5444 /// @return the edit script of the member function templates of the two
5445 /// @ref class_or_union.
5446 const edit_script&
member_fn_tmpls_changes() const5447 class_or_union_diff::member_fn_tmpls_changes() const
5448 {return get_priv()->member_fn_tmpls_changes_;}
5449
5450 /// @return the edit script of the member function templates of the
5451 /// two @ref class_or_union.
5452 edit_script&
member_fn_tmpls_changes()5453 class_or_union_diff::member_fn_tmpls_changes()
5454 {return get_priv()->member_fn_tmpls_changes_;}
5455
5456 /// @return the edit script of the member class templates of the two
5457 /// @ref class_or_union.
5458 const edit_script&
member_class_tmpls_changes() const5459 class_or_union_diff::member_class_tmpls_changes() const
5460 {return get_priv()->member_class_tmpls_changes_;}
5461
5462 /// @return the edit script of the member class templates of the two
5463 /// @ref class_or_union.
5464 edit_script&
member_class_tmpls_changes()5465 class_or_union_diff::member_class_tmpls_changes()
5466 {return get_priv()->member_class_tmpls_changes_;}
5467
5468 /// Test if the current diff node carries a change.
5469 bool
has_changes() const5470 class_or_union_diff::has_changes() const
5471 {return first_class_or_union() != second_class_or_union();}
5472
5473 /// @return the kind of local change carried by the current diff node.
5474 /// The value returned is zero if the current node carries no local
5475 /// change.
5476 enum change_kind
has_local_changes() const5477 class_or_union_diff::has_local_changes() const
5478 {
5479 ir::change_kind k = ir::NO_CHANGE_KIND;
5480 if (!equals(*first_class_or_union(), *second_class_or_union(), &k))
5481 return k & ir::ALL_LOCAL_CHANGES_MASK;
5482 return ir::NO_CHANGE_KIND;
5483 }
5484
5485
5486 /// Report the changes carried by the current @ref class_or_union_diff
5487 /// node in a textual format.
5488 ///
5489 /// @param out the output stream to write the textual report to.
5490 ///
5491 /// @param indent the number of white space to use as indentation.
5492 void
report(ostream & out,const string & indent) const5493 class_or_union_diff::report(ostream& out, const string& indent) const
5494 {
5495 context()->get_reporter()->report(*this, out, indent);
5496 }
5497
5498 /// Populate the vector of children node of the @ref diff base type
5499 /// sub-object of this instance of @ref class_or_union_diff.
5500 ///
5501 /// The children node can then later be retrieved using
5502 /// diff::children_node().
5503 void
chain_into_hierarchy()5504 class_or_union_diff::chain_into_hierarchy()
5505 {
5506 // data member changes
5507 for (var_diff_sptrs_type::const_iterator i =
5508 get_priv()->sorted_subtype_changed_dm_.begin();
5509 i != get_priv()->sorted_subtype_changed_dm_.end();
5510 ++i)
5511 if (diff_sptr d = *i)
5512 append_child_node(d);
5513
5514 for (var_diff_sptrs_type::const_iterator i =
5515 get_priv()->sorted_changed_dm_.begin();
5516 i != get_priv()->sorted_changed_dm_.end();
5517 ++i)
5518 if (diff_sptr d = *i)
5519 append_child_node(d);
5520
5521 // member types changes
5522 for (diff_sptrs_type::const_iterator i =
5523 get_priv()->sorted_changed_member_types_.begin();
5524 i != get_priv()->sorted_changed_member_types_.end();
5525 ++i)
5526 if (diff_sptr d = *i)
5527 append_child_node(d);
5528
5529 // member function changes
5530 for (function_decl_diff_sptrs_type::const_iterator i =
5531 get_priv()->sorted_changed_member_functions_.begin();
5532 i != get_priv()->sorted_changed_member_functions_.end();
5533 ++i)
5534 if (diff_sptr d = *i)
5535 append_child_node(d);
5536 }
5537
5538 // </class_or_union_diff stuff>
5539
5540 //<class_diff stuff>
5541
5542 /// Clear the lookup tables useful for reporting.
5543 ///
5544 /// This function must be updated each time a lookup table is added or
5545 /// removed from the class_diff::priv.
5546 void
clear_lookup_tables(void)5547 class_diff::clear_lookup_tables(void)
5548 {
5549 priv_->deleted_bases_.clear();
5550 priv_->inserted_bases_.clear();
5551 priv_->changed_bases_.clear();
5552 }
5553
5554 /// Tests if the lookup tables are empty.
5555 ///
5556 /// @return true if the lookup tables are empty, false otherwise.
5557 bool
lookup_tables_empty(void) const5558 class_diff::lookup_tables_empty(void) const
5559 {
5560 return (priv_->deleted_bases_.empty()
5561 && priv_->inserted_bases_.empty()
5562 && priv_->changed_bases_.empty());
5563 }
5564
5565 /// Find a virtual destructor in a map of member functions
5566 ///
5567 /// @param map the map of member functions. Note that the key of the
5568 /// map is the member function name. The key is the member function.
5569 ///
5570 /// @return an iterator to the destructor found or, if no virtual destructor
5571 /// was found, return map.end()
5572 static string_member_function_sptr_map::const_iterator
find_virtual_dtor_in_map(const string_member_function_sptr_map & map)5573 find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
5574 {
5575 for (string_member_function_sptr_map::const_iterator i = map.begin();
5576 i !=map.end();
5577 ++i)
5578 {
5579 if (get_member_function_is_dtor(i->second)
5580 && get_member_function_is_virtual(i->second))
5581 return i;
5582 }
5583 return map.end();
5584 }
5585
5586 /// If the lookup tables are not yet built, walk the differences and
5587 /// fill them.
5588 void
ensure_lookup_tables_populated(void) const5589 class_diff::ensure_lookup_tables_populated(void) const
5590 {
5591 class_or_union_diff::ensure_lookup_tables_populated();
5592
5593 if (!lookup_tables_empty())
5594 return;
5595
5596 {
5597 edit_script& e = get_priv()->base_changes_;
5598
5599 for (vector<deletion>::const_iterator it = e.deletions().begin();
5600 it != e.deletions().end();
5601 ++it)
5602 {
5603 unsigned i = it->index();
5604 class_decl::base_spec_sptr b =
5605 first_class_decl()->get_base_specifiers()[i];
5606 string name = b->get_base_class()->get_qualified_name();
5607 ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5608 == get_priv()->deleted_bases_.end());
5609 get_priv()->deleted_bases_[name] = b;
5610 }
5611
5612 for (vector<insertion>::const_iterator it = e.insertions().begin();
5613 it != e.insertions().end();
5614 ++it)
5615 {
5616 for (vector<unsigned>::const_iterator iit =
5617 it->inserted_indexes().begin();
5618 iit != it->inserted_indexes().end();
5619 ++iit)
5620 {
5621 unsigned i = *iit;
5622 class_decl::base_spec_sptr b =
5623 second_class_decl()->get_base_specifiers()[i];
5624 string name = b->get_base_class()->get_qualified_name();
5625 ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5626 == get_priv()->inserted_bases_.end());
5627 string_base_sptr_map::const_iterator j =
5628 get_priv()->deleted_bases_.find(name);
5629 if (j != get_priv()->deleted_bases_.end())
5630 {
5631 if (j->second != b)
5632 get_priv()->changed_bases_[name] =
5633 compute_diff(j->second, b, context());
5634 else
5635 // The base class changed place. IOW, the base
5636 // classes got re-arranged. Let's keep track of the
5637 // base classes that moved.
5638 get_priv()->moved_bases_.push_back(b);
5639 get_priv()->deleted_bases_.erase(j);
5640 }
5641 else
5642 get_priv()->inserted_bases_[name] = b;
5643 }
5644 }
5645 }
5646
5647 sort_string_base_sptr_map(get_priv()->deleted_bases_,
5648 get_priv()->sorted_deleted_bases_);
5649 sort_string_base_sptr_map(get_priv()->inserted_bases_,
5650 get_priv()->sorted_inserted_bases_);
5651 sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5652 get_priv()->sorted_changed_bases_);
5653
5654 {
5655 const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5656
5657 edit_script& e = p->member_fns_changes_;
5658
5659 for (vector<deletion>::const_iterator it = e.deletions().begin();
5660 it != e.deletions().end();
5661 ++it)
5662 {
5663 unsigned i = it->index();
5664 method_decl_sptr mem_fn =
5665 first_class_decl()->get_virtual_mem_fns()[i];
5666 string name = mem_fn->get_linkage_name();
5667 if (name.empty())
5668 name = mem_fn->get_pretty_representation();
5669 ABG_ASSERT(!name.empty());
5670 if (p->deleted_member_functions_.find(name)
5671 != p->deleted_member_functions_.end())
5672 continue;
5673 p->deleted_member_functions_[name] = mem_fn;
5674 }
5675
5676 for (vector<insertion>::const_iterator it = e.insertions().begin();
5677 it != e.insertions().end();
5678 ++it)
5679 {
5680 for (vector<unsigned>::const_iterator iit =
5681 it->inserted_indexes().begin();
5682 iit != it->inserted_indexes().end();
5683 ++iit)
5684 {
5685 unsigned i = *iit;
5686
5687 method_decl_sptr mem_fn =
5688 second_class_decl()->get_virtual_mem_fns()[i];
5689 string name = mem_fn->get_linkage_name();
5690 if (name.empty())
5691 name = mem_fn->get_pretty_representation();
5692 ABG_ASSERT(!name.empty());
5693 if (p->inserted_member_functions_.find(name)
5694 != p->inserted_member_functions_.end())
5695 continue;
5696 string_member_function_sptr_map::const_iterator j =
5697 p->deleted_member_functions_.find(name);
5698
5699 if (j != p->deleted_member_functions_.end())
5700 {
5701 if (*j->second != *mem_fn)
5702 p->changed_member_functions_[name] =
5703 compute_diff(static_pointer_cast<function_decl>(j->second),
5704 static_pointer_cast<function_decl>(mem_fn),
5705 context());
5706 p->deleted_member_functions_.erase(j);
5707 }
5708 else
5709 p->inserted_member_functions_[name] = mem_fn;
5710 }
5711 }
5712
5713 // Now walk the allegedly deleted member functions; check if their
5714 // underlying symbols are deleted as well; otherwise, consider
5715 // that the member function in question hasn't been deleted.
5716
5717 // Also, while walking the deleted member functions, we attend at
5718 // a particular cleanup business related to (virtual) C++
5719 // destructors:
5720 //
5721 // In the binary, there can be at least three types of
5722 // destructors, defined in the document
5723 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
5724 //
5725 // 1/ Base object destructor (aka D2 destructor):
5726 //
5727 // "A function that runs the destructors for non-static data
5728 // members of T and non-virtual direct base classes of T. "
5729 //
5730 // 2/ Complete object destructor (aka D1 destructor):
5731 //
5732 // "A function that, in addition to the actions required of a
5733 // base object destructor, runs the destructors for the
5734 // virtual base classes of T."
5735 //
5736 // 3/ Deleting destructor (aka D0 destructor):
5737 //
5738 // "A function that, in addition to the actions required of a
5739 // complete object destructor, calls the appropriate
5740 // deallocation function (i.e,. operator delete) for T."
5741 //
5742 // With binaries generated by GCC, these destructors might be ELF
5743 // clones of each others, meaning, their ELF symbols can be
5744 // aliases.
5745 //
5746 // Also, note that because the actual destructor invoked by user
5747 // code is virtual, it's invoked through the vtable. So the
5748 // presence of the underlying D0, D1, D2 in the binary might vary
5749 // without that variation being an ABI issue, provided that the
5750 // destructor invoked through the vtable is present.
5751 //
5752 // So, a particular virtual destructor implementation for a class
5753 // might disapear and be replaced by another one in a subsequent
5754 // version of the binary. If all versions of the binary have an
5755 // actual virtual destructor, things might be considered fine.
5756 vector<string> to_delete;
5757 corpus_sptr f = context()->get_first_corpus(),
5758 s = context()->get_second_corpus();
5759 if (s)
5760 for (string_member_function_sptr_map::const_iterator i =
5761 deleted_member_fns().begin();
5762 i != deleted_member_fns().end();
5763 ++i)
5764 {
5765 if (get_member_function_is_virtual(i->second))
5766 {
5767 if (get_member_function_is_dtor(i->second))
5768 {
5769 // If a particular virtual destructor is deleted,
5770 // but the new binary still have a virtual
5771 // destructor for that class we consider that things
5772 // are fine. For instance, in the
5773 // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
5774 // test, a new D4 destructor replaces the old ones.
5775 // But because the virtual destructor is still
5776 // there, this is not an ABI issue. So let's detect
5777 // this case.
5778 auto it =
5779 find_virtual_dtor_in_map(p->inserted_member_functions_);
5780 if (it != p->inserted_member_functions_.end())
5781 {
5782 // So the deleted virtual destructor is not
5783 // really deleted, because a proper virtual
5784 // destructor was added to the new version.
5785 // Let's remove the deleted/added virtual
5786 // destructor then.
5787 string name =
5788 (!i->second->get_linkage_name().empty())
5789 ? i->second->get_linkage_name()
5790 : i->second->get_pretty_representation();
5791 to_delete.push_back(name);
5792 p->inserted_member_functions_.erase(it);
5793 }
5794 }
5795 continue;
5796 }
5797 // We assume that all non-virtual member functions functions
5798 // we look at here have ELF symbols.
5799 if (!i->second->get_symbol()
5800 || s->lookup_function_symbol(*i->second->get_symbol()))
5801 to_delete.push_back(i->first);
5802 }
5803
5804
5805 for (vector<string>::const_iterator i = to_delete.begin();
5806 i != to_delete.end();
5807 ++i)
5808 p->deleted_member_functions_.erase(*i);
5809
5810 // Do something similar for added functions.
5811 to_delete.clear();
5812 if (f)
5813 for (string_member_function_sptr_map::const_iterator i =
5814 inserted_member_fns().begin();
5815 i != inserted_member_fns().end();
5816 ++i)
5817 {
5818 if (get_member_function_is_virtual(i->second))
5819 continue;
5820 // We assume that all non-virtual member functions functions
5821 // we look at here have ELF symbols.
5822 if (!i->second->get_symbol()
5823 || f->lookup_function_symbol(*i->second->get_symbol()))
5824 to_delete.push_back(i->first);
5825 }
5826
5827 for (vector<string>::const_iterator i = to_delete.begin();
5828 i != to_delete.end();
5829 ++i)
5830 p->inserted_member_functions_.erase(*i);
5831
5832 sort_string_member_function_sptr_map(p->deleted_member_functions_,
5833 p->sorted_deleted_member_functions_);
5834
5835 sort_string_member_function_sptr_map(p->inserted_member_functions_,
5836 p->sorted_inserted_member_functions_);
5837
5838 sort_string_virtual_member_function_diff_sptr_map
5839 (p->changed_member_functions_,
5840 p->sorted_changed_member_functions_);
5841 }
5842 }
5843
5844 /// Allocate the memory for the priv_ pimpl data member of the @ref
5845 /// class_diff class.
5846 void
allocate_priv_data()5847 class_diff::allocate_priv_data()
5848 {
5849 class_or_union_diff::allocate_priv_data();
5850 if (!priv_)
5851 priv_.reset(new priv);
5852 }
5853
5854 /// Test whether a given base class has changed. A base class has
5855 /// changed if it's in both in deleted *and* inserted bases.
5856 ///
5857 ///@param d the declaration for the base class to consider.
5858 ///
5859 /// @return the new base class if the given base class has changed, or
5860 /// NULL if it hasn't.
5861 class_decl::base_spec_sptr
base_has_changed(class_decl::base_spec_sptr d) const5862 class_diff::priv::base_has_changed(class_decl::base_spec_sptr d) const
5863 {
5864 string qname = d->get_base_class()->get_qualified_name();
5865 string_base_diff_sptr_map::const_iterator it =
5866 changed_bases_.find(qname);
5867
5868 return (it == changed_bases_.end())
5869 ? class_decl::base_spec_sptr()
5870 : it->second->second_base();
5871
5872 }
5873
5874 /// Count the number of bases classes whose changes got filtered out.
5875 ///
5876 /// @return the number of bases classes whose changes got filtered
5877 /// out.
5878 size_t
count_filtered_bases()5879 class_diff::priv::count_filtered_bases()
5880 {
5881 size_t num_filtered = 0;
5882 for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
5883 i != sorted_changed_bases_.end();
5884 ++i)
5885 {
5886 diff_sptr diff = *i;
5887 if (diff && diff->is_filtered_out())
5888 ++num_filtered;
5889 }
5890 return num_filtered;
5891 }
5892
5893 /// Populate the vector of children node of the @ref diff base type
5894 /// sub-object of this instance of @ref class_diff.
5895 ///
5896 /// The children node can then later be retrieved using
5897 /// diff::children_node().
5898 void
chain_into_hierarchy()5899 class_diff::chain_into_hierarchy()
5900 {
5901 class_or_union_diff::chain_into_hierarchy();
5902
5903 // base class changes.
5904 for (base_diff_sptrs_type::const_iterator i =
5905 get_priv()->sorted_changed_bases_.begin();
5906 i != get_priv()->sorted_changed_bases_.end();
5907 ++i)
5908 if (diff_sptr d = *i)
5909 append_child_node(d);
5910 }
5911
5912 /// Constructor of class_diff
5913 ///
5914 /// @param first_scope the first class of the diff.
5915 ///
5916 /// @param second_scope the second class of the diff.
5917 ///
5918 /// @param ctxt the diff context to use.
class_diff(class_decl_sptr first_scope,class_decl_sptr second_scope,diff_context_sptr ctxt)5919 class_diff::class_diff(class_decl_sptr first_scope,
5920 class_decl_sptr second_scope,
5921 diff_context_sptr ctxt)
5922 : class_or_union_diff(first_scope, second_scope, ctxt)
5923 // We don't initialize the priv_ data member here. This is an
5924 // optimization to reduce memory consumption (and also execution
5925 // time) for cases where there are a lot of instances of
5926 // class_diff in the same equivalence class. In compute_diff(),
5927 // the priv_ is set to the priv_ of the canonical diff node.
5928 // See PR libabigail/17948.
5929 {}
5930
~class_diff()5931 class_diff::~class_diff()
5932 {}
5933
5934 /// Getter of the private data of the @ref class_diff type.
5935 ///
5936 /// Note that due to an optimization, the private data of @ref
5937 /// class_diff can be shared among several instances of class_diff, so
5938 /// you should never try to access class_diff::priv directly.
5939 ///
5940 /// When class_diff::priv is shared, this function returns the correct
5941 /// shared one.
5942 ///
5943 /// @return the (possibly) shared private data of the current instance
5944 /// of class_diff.
5945 const class_diff::priv_ptr&
get_priv() const5946 class_diff::get_priv() const
5947 {
5948 if (priv_)
5949 return priv_;
5950
5951 // If the current class_diff::priv member is empty, then look for
5952 // the shared one, from the canonical type.
5953 class_diff *canonical =
5954 dynamic_cast<class_diff*>(get_canonical_diff());
5955 ABG_ASSERT(canonical);
5956 ABG_ASSERT(canonical->priv_);
5957
5958 return canonical->priv_;
5959 }
5960
5961 /// @return the pretty representation of the current instance of @ref
5962 /// class_diff.
5963 const string&
get_pretty_representation() const5964 class_diff::get_pretty_representation() const
5965 {
5966 if (diff::priv_->pretty_representation_.empty())
5967 {
5968 std::ostringstream o;
5969 o << "class_diff["
5970 << first_subject()->get_pretty_representation()
5971 << ", "
5972 << second_subject()->get_pretty_representation()
5973 << "]";
5974 diff::priv_->pretty_representation_ = o.str();
5975 }
5976 return diff::priv_->pretty_representation_;
5977 }
5978
5979 /// Return true iff the current diff node carries a change.
5980 ///
5981 /// @return true iff the current diff node carries a change.
5982 bool
has_changes() const5983 class_diff::has_changes() const
5984 {return (first_class_decl() != second_class_decl());}
5985
5986 /// @return the kind of local change carried by the current diff node.
5987 /// The value returned is zero if the current node carries no local
5988 /// change.
5989 enum change_kind
has_local_changes() const5990 class_diff::has_local_changes() const
5991 {
5992 ir::change_kind k = ir::NO_CHANGE_KIND;
5993 if (!equals(*first_class_decl(), *second_class_decl(), &k))
5994 return k & ir::ALL_LOCAL_CHANGES_MASK;
5995 return ir::NO_CHANGE_KIND;
5996 }
5997
5998 /// @return the first class invoveld in the diff.
5999 shared_ptr<class_decl>
first_class_decl() const6000 class_diff::first_class_decl() const
6001 {return dynamic_pointer_cast<class_decl>(first_subject());}
6002
6003 /// Getter of the second class involved in the diff.
6004 ///
6005 /// @return the second class invoveld in the diff
6006 shared_ptr<class_decl>
second_class_decl() const6007 class_diff::second_class_decl() const
6008 {return dynamic_pointer_cast<class_decl>(second_subject());}
6009
6010 /// @return the edit script of the bases of the two classes.
6011 const edit_script&
base_changes() const6012 class_diff::base_changes() const
6013 {return get_priv()->base_changes_;}
6014
6015 /// Getter for the deleted base classes of the diff.
6016 ///
6017 /// @return a map containing the deleted base classes, keyed with
6018 /// their pretty representation.
6019 const string_base_sptr_map&
deleted_bases() const6020 class_diff::deleted_bases() const
6021 {return get_priv()->deleted_bases_;}
6022
6023 /// Getter for the inserted base classes of the diff.
6024 ///
6025 /// @return a map containing the inserted base classes, keyed with
6026 /// their pretty representation.
6027 const string_base_sptr_map&
inserted_bases() const6028 class_diff::inserted_bases() const
6029 {return get_priv()->inserted_bases_;}
6030
6031 /// Getter for the changed base classes of the diff.
6032 ///
6033 /// @return a sorted vector containing the changed base classes
6034 const base_diff_sptrs_type&
changed_bases()6035 class_diff::changed_bases()
6036 {return get_priv()->sorted_changed_bases_;}
6037
6038 /// Getter for the vector of bases that "moved".
6039 /// That is, the vector of base types which position changed. If this
6040 /// vector is not empty, it means the bases of the underlying class
6041 /// type got re-ordered.
6042 ///
6043 /// @return the vector of bases that moved.
6044 const vector<class_decl::base_spec_sptr>&
moved_bases() const6045 class_diff::moved_bases() const
6046 {return get_priv()->moved_bases_;}
6047
6048 /// @return the edit script of the bases of the two classes.
6049 edit_script&
base_changes()6050 class_diff::base_changes()
6051 {return get_priv()->base_changes_;}
6052
6053 /// Produce a basic report about the changes between two class_decl.
6054 ///
6055 /// @param out the output stream to report the changes to.
6056 ///
6057 /// @param indent the string to use as an indentation prefix in the
6058 /// report.
6059 void
report(ostream & out,const string & indent) const6060 class_diff::report(ostream& out, const string& indent) const
6061 {
6062 context()->get_reporter()->report(*this, out, indent);
6063 }
6064
6065 /// Compute the set of changes between two instances of class_decl.
6066 ///
6067 /// Note that the two types must have been created in the same @ref
6068 /// environment, otherwise, this function aborts.
6069 ///
6070 /// @param first the first class_decl to consider.
6071 ///
6072 /// @param second the second class_decl to consider.
6073 ///
6074 /// @return changes the resulting changes.
6075 ///
6076 /// @param ctxt the diff context to use.
6077 class_diff_sptr
compute_diff(const class_decl_sptr first,const class_decl_sptr second,diff_context_sptr ctxt)6078 compute_diff(const class_decl_sptr first,
6079 const class_decl_sptr second,
6080 diff_context_sptr ctxt)
6081 {
6082 class_decl_sptr f = is_class_type(look_through_decl_only_class(first)),
6083 s = is_class_type(look_through_decl_only_class(second));
6084
6085 class_diff_sptr changes(new class_diff(f, s, ctxt));
6086
6087 ctxt->initialize_canonical_diff(changes);
6088 ABG_ASSERT(changes->get_canonical_diff());
6089
6090 if (!ctxt->get_canonical_diff_for(first, second))
6091 {
6092 // Either first or second is a decl-only class; let's set the
6093 // canonical diff here in that case.
6094 diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6095 ABG_ASSERT(canonical_diff);
6096 ctxt->set_canonical_diff_for(first, second, canonical_diff);
6097 }
6098
6099 // Ok, so this is an optimization. Do not freak out if it looks
6100 // weird, because, well, it does look weird. This speeds up
6101 // greatly, for instance, the test case given at PR
6102 // libabigail/17948.
6103 //
6104 // We are setting the private data of the new instance of class_diff
6105 // (which is 'changes') to the private data of its canonical
6106 // instance. That is, we are sharing the private data of 'changes'
6107 // with the private data of its canonical instance to consume less
6108 // memory in cases where the equivalence class of 'changes' is huge.
6109 //
6110 // But if changes is its own canonical instance, then we initialize
6111 // its private data properly
6112 if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6113 // changes is its own canonical instance, so it gets a brand new
6114 // private data.
6115 changes->allocate_priv_data();
6116 else
6117 {
6118 // changes has a non-empty equivalence class so it's going to
6119 // share its private data with its canonical instance. Next
6120 // time class_diff::get_priv() is invoked, it's going to return
6121 // the shared private data of the canonical instance.
6122 return changes;
6123 }
6124
6125 // Compare base specs
6126 compute_diff(f->get_base_specifiers().begin(),
6127 f->get_base_specifiers().end(),
6128 s->get_base_specifiers().begin(),
6129 s->get_base_specifiers().end(),
6130 changes->base_changes());
6131
6132 // Do *not* compare member types because it generates lots of noise
6133 // and I doubt it's really useful.
6134 #if 0
6135 compute_diff(f->get_member_types().begin(),
6136 f->get_member_types().end(),
6137 s->get_member_types().begin(),
6138 s->get_member_types().end(),
6139 changes->member_types_changes());
6140 #endif
6141
6142 // Compare data member
6143 compute_diff(f->get_non_static_data_members().begin(),
6144 f->get_non_static_data_members().end(),
6145 s->get_non_static_data_members().begin(),
6146 s->get_non_static_data_members().end(),
6147 changes->data_members_changes());
6148
6149 // Compare virtual member functions
6150 compute_diff(f->get_virtual_mem_fns().begin(),
6151 f->get_virtual_mem_fns().end(),
6152 s->get_virtual_mem_fns().begin(),
6153 s->get_virtual_mem_fns().end(),
6154 changes->member_fns_changes());
6155
6156 // Compare member function templates
6157 compute_diff(f->get_member_function_templates().begin(),
6158 f->get_member_function_templates().end(),
6159 s->get_member_function_templates().begin(),
6160 s->get_member_function_templates().end(),
6161 changes->member_fn_tmpls_changes());
6162
6163 // Likewise, do not compare member class templates
6164 #if 0
6165 compute_diff(f->get_member_class_templates().begin(),
6166 f->get_member_class_templates().end(),
6167 s->get_member_class_templates().begin(),
6168 s->get_member_class_templates().end(),
6169 changes->member_class_tmpls_changes());
6170 #endif
6171
6172 changes->ensure_lookup_tables_populated();
6173
6174 return changes;
6175 }
6176
6177 //</class_diff stuff>
6178
6179 // <base_diff stuff>
6180
6181 /// Populate the vector of children node of the @ref diff base type
6182 /// sub-object of this instance of @ref base_diff.
6183 ///
6184 /// The children node can then later be retrieved using
6185 /// diff::children_node().
6186 void
chain_into_hierarchy()6187 base_diff::chain_into_hierarchy()
6188 {append_child_node(get_underlying_class_diff());}
6189
6190 /// @param first the first base spec to consider.
6191 ///
6192 /// @param second the second base spec to consider.
6193 ///
6194 /// @param ctxt the context of the diff. Note that this context
6195 /// object must stay alive at least during the life time of the
6196 /// current instance of @ref base_diff. Otherwise memory corruption
6197 /// issues occur.
base_diff(class_decl::base_spec_sptr first,class_decl::base_spec_sptr second,class_diff_sptr underlying,diff_context_sptr ctxt)6198 base_diff::base_diff(class_decl::base_spec_sptr first,
6199 class_decl::base_spec_sptr second,
6200 class_diff_sptr underlying,
6201 diff_context_sptr ctxt)
6202 : diff(first, second, ctxt),
6203 priv_(new priv(underlying))
6204 {}
6205
6206 /// Getter for the first base spec of the diff object.
6207 ///
6208 /// @return the first base specifier for the diff object.
6209 class_decl::base_spec_sptr
first_base() const6210 base_diff::first_base() const
6211 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6212
6213 /// Getter for the second base spec of the diff object.
6214 ///
6215 /// @return the second base specifier for the diff object.
6216 class_decl::base_spec_sptr
second_base() const6217 base_diff::second_base() const
6218 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6219
6220 /// Getter for the diff object for the diff of the underlying base
6221 /// classes.
6222 ///
6223 /// @return the diff object for the diff of the underlying base
6224 /// classes.
6225 const class_diff_sptr
get_underlying_class_diff() const6226 base_diff::get_underlying_class_diff() const
6227 {return priv_->underlying_class_diff_;}
6228
6229 /// Setter for the diff object for the diff of the underlyng base
6230 /// classes.
6231 ///
6232 /// @param d the new diff object for the diff of the underlying base
6233 /// classes.
6234 void
set_underlying_class_diff(class_diff_sptr d)6235 base_diff::set_underlying_class_diff(class_diff_sptr d)
6236 {priv_->underlying_class_diff_ = d;}
6237
6238 /// @return the pretty representation for the current instance of @ref
6239 /// base_diff.
6240 const string&
get_pretty_representation() const6241 base_diff::get_pretty_representation() const
6242 {
6243 if (diff::priv_->pretty_representation_.empty())
6244 {
6245 std::ostringstream o;
6246 o << "base_diff["
6247 << first_subject()->get_pretty_representation()
6248 << ", "
6249 << second_subject()->get_pretty_representation()
6250 << "]";
6251 diff::priv_->pretty_representation_ = o.str();
6252 }
6253 return diff::priv_->pretty_representation_;
6254 }
6255
6256 /// Return true iff the current diff node carries a change.
6257 ///
6258 /// Return true iff the current diff node carries a change.
6259 bool
has_changes() const6260 base_diff::has_changes() const
6261 {return first_base() != second_base();}
6262
6263 /// @return the kind of local change carried by the current diff node.
6264 /// The value returned is zero if the current node carries no local
6265 /// change.
6266 enum change_kind
has_local_changes() const6267 base_diff::has_local_changes() const
6268 {
6269 ir::change_kind k = ir::NO_CHANGE_KIND;
6270 if (!equals(*first_base(), *second_base(), &k))
6271 return k & ir::ALL_LOCAL_CHANGES_MASK;
6272 return ir::NO_CHANGE_KIND;
6273 }
6274
6275 /// Generates a report for the current instance of base_diff.
6276 ///
6277 /// @param out the output stream to send the report to.
6278 ///
6279 /// @param indent the string to use for indentation.
6280 void
report(ostream & out,const string & indent) const6281 base_diff::report(ostream& out, const string& indent) const
6282 {
6283 context()->get_reporter()->report(*this, out, indent);
6284 }
6285
6286 /// Constructs the diff object representing a diff between two base
6287 /// class specifications.
6288 ///
6289 /// Note that the two artifacts must have been created in the same
6290 /// @ref environment, otherwise, this function aborts.
6291 ///
6292 /// @param first the first base class specification.
6293 ///
6294 /// @param second the second base class specification.
6295 ///
6296 /// @param ctxt the content of the diff.
6297 ///
6298 /// @return the resulting diff object.
6299 base_diff_sptr
compute_diff(const class_decl::base_spec_sptr first,const class_decl::base_spec_sptr second,diff_context_sptr ctxt)6300 compute_diff(const class_decl::base_spec_sptr first,
6301 const class_decl::base_spec_sptr second,
6302 diff_context_sptr ctxt)
6303 {
6304 class_diff_sptr cl = compute_diff(first->get_base_class(),
6305 second->get_base_class(),
6306 ctxt);
6307 base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6308
6309 ctxt->initialize_canonical_diff(changes);
6310
6311 return changes;
6312 }
6313
6314 // </base_diff stuff>
6315
6316
6317 // <union_diff stuff>
6318
6319 /// Clear the lookup tables useful for reporting.
6320 ///
6321 /// This function must be updated each time a lookup table is added or
6322 /// removed from the union_diff::priv.
6323 void
clear_lookup_tables(void)6324 union_diff::clear_lookup_tables(void)
6325 {class_or_union_diff::clear_lookup_tables();}
6326
6327 /// Tests if the lookup tables are empty.
6328 ///
6329 /// @return true if the lookup tables are empty, false otherwise.
6330 bool
lookup_tables_empty(void) const6331 union_diff::lookup_tables_empty(void) const
6332 {return class_or_union_diff::lookup_tables_empty();}
6333
6334 /// If the lookup tables are not yet built, walk the differences and
6335 /// fill them.
6336 void
ensure_lookup_tables_populated(void) const6337 union_diff::ensure_lookup_tables_populated(void) const
6338 {class_or_union_diff::ensure_lookup_tables_populated();}
6339
6340 /// Allocate the memory for the priv_ pimpl data member of the @ref
6341 /// union_diff class.
6342 void
allocate_priv_data()6343 union_diff::allocate_priv_data()
6344 {
6345 class_or_union_diff::allocate_priv_data();
6346 }
6347
6348 /// Constructor for the @ref union_diff type.
6349 ///
6350 /// @param first_union the first object of the comparison.
6351 ///
6352 /// @param second_union the second object of the comparison.
6353 ///
6354 /// @param ctxt the context of the comparison.
union_diff(union_decl_sptr first_union,union_decl_sptr second_union,diff_context_sptr ctxt)6355 union_diff::union_diff(union_decl_sptr first_union,
6356 union_decl_sptr second_union,
6357 diff_context_sptr ctxt)
6358 : class_or_union_diff(first_union, second_union, ctxt)
6359 {}
6360
6361 /// Destructor of the union_diff node.
~union_diff()6362 union_diff::~union_diff()
6363 {}
6364
6365 /// @return the first object of the comparison.
6366 union_decl_sptr
first_union_decl() const6367 union_diff::first_union_decl() const
6368 {return is_union_type(first_subject());}
6369
6370 /// @return the second object of the comparison.
6371 union_decl_sptr
second_union_decl() const6372 union_diff::second_union_decl() const
6373 {return is_union_type(second_subject());}
6374
6375 /// @return the pretty representation of the current diff node.
6376 const string&
get_pretty_representation() const6377 union_diff::get_pretty_representation() const
6378 {
6379 if (diff::priv_->pretty_representation_.empty())
6380 {
6381 std::ostringstream o;
6382 o << "union_diff["
6383 << first_subject()->get_pretty_representation()
6384 << ", "
6385 << second_subject()->get_pretty_representation()
6386 << "]";
6387 diff::priv_->pretty_representation_ = o.str();
6388 }
6389 return diff::priv_->pretty_representation_;
6390 }
6391
6392 /// Report the changes carried by the current @ref union_diff node in
6393 /// a textual format.
6394 ///
6395 /// @param out the output stream to write the textual report to.
6396 ///
6397 /// @param indent the number of white space to use as indentation.
6398 void
report(ostream & out,const string & indent) const6399 union_diff::report(ostream& out, const string& indent) const
6400 {
6401 context()->get_reporter()->report(*this, out, indent);
6402 }
6403
6404 /// Compute the difference between two @ref union_decl types.
6405 ///
6406 /// Note that the two types must hav been created in the same
6407 /// environment, otherwise, this function aborts.
6408 ///
6409 /// @param first the first @ref union_decl to consider.
6410 ///
6411 /// @param second the second @ref union_decl to consider.
6412 ///
6413 /// @param ctxt the context of the diff to use.
6414 union_diff_sptr
compute_diff(const union_decl_sptr first,const union_decl_sptr second,diff_context_sptr ctxt)6415 compute_diff(const union_decl_sptr first,
6416 const union_decl_sptr second,
6417 diff_context_sptr ctxt)
6418 {
6419 union_diff_sptr changes(new union_diff(first, second, ctxt));
6420
6421 ctxt->initialize_canonical_diff(changes);
6422 ABG_ASSERT(changes->get_canonical_diff());
6423
6424 // Ok, so this is an optimization. Do not freak out if it looks
6425 // weird, because, well, it does look weird. This speeds up
6426 // greatly, for instance, the test case given at PR
6427 // libabigail/17948.
6428 //
6429 // We are setting the private data of the new instance of class_diff
6430 // (which is 'changes') to the private data of its canonical
6431 // instance. That is, we are sharing the private data of 'changes'
6432 // with the private data of its canonical instance to consume less
6433 // memory in cases where the equivalence class of 'changes' is huge.
6434 //
6435 // But if changes is its own canonical instance, then we initialize
6436 // its private data properly.
6437 if (is_union_diff(changes->get_canonical_diff()) == changes.get())
6438 // changes is its own canonical instance, so it gets a brand new
6439 // private data.
6440 changes->allocate_priv_data();
6441 else
6442 {
6443 // changes has a non-empty equivalence class so it's going to
6444 // share its private data with its canonical instance. Next
6445 // time class_diff::get_priv() is invoked, it's going to return
6446 // the shared private data of the canonical instance.
6447 return changes;
6448 }
6449
6450 // Compare data member
6451 compute_diff(first->get_non_static_data_members().begin(),
6452 first->get_non_static_data_members().end(),
6453 second->get_non_static_data_members().begin(),
6454 second->get_non_static_data_members().end(),
6455 changes->data_members_changes());
6456
6457 #if 0
6458 // Compare member functions
6459 compute_diff(first->get_mem_fns().begin(),
6460 first->get_mem_fns().end(),
6461 second->get_mem_fns().begin(),
6462 second->get_mem_fns().end(),
6463 changes->member_fns_changes());
6464
6465 // Compare member function templates
6466 compute_diff(first->get_member_function_templates().begin(),
6467 first->get_member_function_templates().end(),
6468 second->get_member_function_templates().begin(),
6469 second->get_member_function_templates().end(),
6470 changes->member_fn_tmpls_changes());
6471 #endif
6472
6473 changes->ensure_lookup_tables_populated();
6474
6475 return changes;
6476 }
6477
6478 // </union_diff stuff>
6479
6480 //<scope_diff stuff>
6481
6482 /// Clear the lookup tables that are useful for reporting.
6483 ///
6484 /// This function must be updated each time a lookup table is added or
6485 /// removed.
6486 void
clear_lookup_tables()6487 scope_diff::clear_lookup_tables()
6488 {
6489 priv_->deleted_types_.clear();
6490 priv_->deleted_decls_.clear();
6491 priv_->inserted_types_.clear();
6492 priv_->inserted_decls_.clear();
6493 priv_->changed_types_.clear();
6494 priv_->changed_decls_.clear();
6495 priv_->removed_types_.clear();
6496 priv_->removed_decls_.clear();
6497 priv_->added_types_.clear();
6498 priv_->added_decls_.clear();
6499 }
6500
6501 /// Tests if the lookup tables are empty.
6502 ///
6503 /// This function must be updated each time a lookup table is added or
6504 /// removed.
6505 ///
6506 /// @return true iff all the lookup tables are empty.
6507 bool
lookup_tables_empty() const6508 scope_diff::lookup_tables_empty() const
6509 {
6510 return (priv_->deleted_types_.empty()
6511 && priv_->deleted_decls_.empty()
6512 && priv_->inserted_types_.empty()
6513 && priv_->inserted_decls_.empty()
6514 && priv_->changed_types_.empty()
6515 && priv_->changed_decls_.empty()
6516 && priv_->removed_types_.empty()
6517 && priv_->removed_decls_.empty()
6518 && priv_->added_types_.empty()
6519 && priv_->added_decls_.empty());
6520 }
6521
6522 /// If the lookup tables are not yet built, walk the member_changes_
6523 /// member and fill the lookup tables.
6524 void
ensure_lookup_tables_populated()6525 scope_diff::ensure_lookup_tables_populated()
6526 {
6527 if (!lookup_tables_empty())
6528 return;
6529
6530 edit_script& e = priv_->member_changes_;
6531
6532 // Populate deleted types & decls lookup tables.
6533 for (const auto& deletion : e.deletions())
6534 {
6535 unsigned i = deletion.index();
6536 decl_base_sptr decl = deleted_member_at(i);
6537 string qname = decl->get_qualified_name();
6538 if (is_type(decl))
6539 {
6540 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6541 if (klass_decl && klass_decl->get_is_declaration_only())
6542 continue;
6543
6544 // Unique types are artifically put in a scope because they
6545 // have to belong somewhere, but they should not be
6546 // considered added/removed from any scope because they are
6547 // artificial and always present in the system.
6548 if (is_unique_type(is_type(decl)))
6549 continue;
6550
6551 ABG_ASSERT(priv_->deleted_types_.find(qname)
6552 == priv_->deleted_types_.end());
6553 priv_->deleted_types_[qname] = decl;
6554 }
6555 else
6556 {
6557 ABG_ASSERT(priv_->deleted_decls_.find(qname)
6558 == priv_->deleted_decls_.end());
6559 priv_->deleted_decls_[qname] = decl;
6560 }
6561 }
6562
6563 // Populate inserted types & decls as well as chagned types & decls
6564 // lookup tables.
6565 for (vector<insertion>::const_iterator it = e.insertions().begin();
6566 it != e.insertions().end();
6567 ++it)
6568 {
6569 for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6570 i != it->inserted_indexes().end();
6571 ++i)
6572 {
6573 decl_base_sptr decl = inserted_member_at(i);
6574 string qname = decl->get_qualified_name();
6575 if (is_type(decl))
6576 {
6577 class_decl_sptr klass_decl =
6578 dynamic_pointer_cast<class_decl>(decl);
6579 if (klass_decl && klass_decl->get_is_declaration_only())
6580 continue;
6581
6582 // Unique types are artifically put in a scope because they
6583 // have to belong somewhere, but they should not be
6584 // considered added/removed from any scope because they are
6585 // artificial and always present in the system.
6586 if (is_unique_type(is_type(decl)))
6587 continue;
6588
6589 ABG_ASSERT(priv_->inserted_types_.find(qname)
6590 == priv_->inserted_types_.end());
6591 string_decl_base_sptr_map::const_iterator j =
6592 priv_->deleted_types_.find(qname);
6593 if (j != priv_->deleted_types_.end())
6594 {
6595 if (*j->second != *decl)
6596 priv_->changed_types_[qname] =
6597 compute_diff(j->second, decl, context());
6598 priv_->deleted_types_.erase(j);
6599 }
6600 else
6601 priv_->inserted_types_[qname] = decl;
6602 }
6603 else
6604 {
6605 ABG_ASSERT(priv_->inserted_decls_.find(qname)
6606 == priv_->inserted_decls_.end());
6607 string_decl_base_sptr_map::const_iterator j =
6608 priv_->deleted_decls_.find(qname);
6609 if (j != priv_->deleted_decls_.end())
6610 {
6611 if (*j->second != *decl)
6612 priv_->changed_decls_[qname] =
6613 compute_diff(j->second, decl, context());
6614 priv_->deleted_decls_.erase(j);
6615 }
6616 else
6617 priv_->inserted_decls_[qname] = decl;
6618 }
6619 }
6620 }
6621
6622 sort_string_diff_sptr_map(priv_->changed_decls_,
6623 priv_->sorted_changed_decls_);
6624 sort_string_diff_sptr_map(priv_->changed_types_,
6625 priv_->sorted_changed_types_);
6626
6627 // Populate removed types/decls lookup tables
6628 for (string_decl_base_sptr_map::const_iterator i =
6629 priv_->deleted_types_.begin();
6630 i != priv_->deleted_types_.end();
6631 ++i)
6632 {
6633 string_decl_base_sptr_map::const_iterator r =
6634 priv_->inserted_types_.find(i->first);
6635 if (r == priv_->inserted_types_.end())
6636 priv_->removed_types_[i->first] = i->second;
6637 }
6638 for (string_decl_base_sptr_map::const_iterator i =
6639 priv_->deleted_decls_.begin();
6640 i != priv_->deleted_decls_.end();
6641 ++i)
6642 {
6643 string_decl_base_sptr_map::const_iterator r =
6644 priv_->inserted_decls_.find(i->first);
6645 if (r == priv_->inserted_decls_.end())
6646 priv_->removed_decls_[i->first] = i->second;
6647 }
6648
6649 // Populate added types/decls.
6650 for (string_decl_base_sptr_map::const_iterator i =
6651 priv_->inserted_types_.begin();
6652 i != priv_->inserted_types_.end();
6653 ++i)
6654 {
6655 string_decl_base_sptr_map::const_iterator r =
6656 priv_->deleted_types_.find(i->first);
6657 if (r == priv_->deleted_types_.end())
6658 priv_->added_types_[i->first] = i->second;
6659 }
6660 for (string_decl_base_sptr_map::const_iterator i =
6661 priv_->inserted_decls_.begin();
6662 i != priv_->inserted_decls_.end();
6663 ++i)
6664 {
6665 string_decl_base_sptr_map::const_iterator r =
6666 priv_->deleted_decls_.find(i->first);
6667 if (r == priv_->deleted_decls_.end())
6668 priv_->added_decls_[i->first] = i->second;
6669 }
6670 }
6671
6672 /// Populate the vector of children node of the @ref diff base type
6673 /// sub-object of this instance of @ref scope_diff.
6674 ///
6675 /// The children node can then later be retrieved using
6676 /// diff::children_node().
6677 void
chain_into_hierarchy()6678 scope_diff::chain_into_hierarchy()
6679 {
6680 for (diff_sptrs_type::const_iterator i = changed_types().begin();
6681 i != changed_types().end();
6682 ++i)
6683 if (*i)
6684 append_child_node(*i);
6685
6686 for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6687 i != changed_decls().end();
6688 ++i)
6689 if (*i)
6690 append_child_node(*i);
6691 }
6692
6693 /// Constructor for scope_diff
6694 ///
6695 /// @param first_scope the first scope to consider for the diff.
6696 ///
6697 /// @param second_scope the second scope to consider for the diff.
6698 ///
6699 /// @param ctxt the diff context to use. Note that this context
6700 /// object must stay alive at least during the life time of the
6701 /// current instance of @ref scope_diff. Otherwise memory corruption
6702 /// issues occur.
scope_diff(scope_decl_sptr first_scope,scope_decl_sptr second_scope,diff_context_sptr ctxt)6703 scope_diff::scope_diff(scope_decl_sptr first_scope,
6704 scope_decl_sptr second_scope,
6705 diff_context_sptr ctxt)
6706 : diff(first_scope, second_scope, ctxt),
6707 priv_(new priv)
6708 {}
6709
6710 /// Getter for the first scope of the diff.
6711 ///
6712 /// @return the first scope of the diff.
6713 const scope_decl_sptr
first_scope() const6714 scope_diff::first_scope() const
6715 {return dynamic_pointer_cast<scope_decl>(first_subject());}
6716
6717 /// Getter for the second scope of the diff.
6718 ///
6719 /// @return the second scope of the diff.
6720 const scope_decl_sptr
second_scope() const6721 scope_diff::second_scope() const
6722 {return dynamic_pointer_cast<scope_decl>(second_subject());}
6723
6724 /// Accessor of the edit script of the members of a scope.
6725 ///
6726 /// This edit script is computed using the equality operator that
6727 /// applies to shared_ptr<decl_base>.
6728 ///
6729 /// That has interesting consequences. For instance, consider two
6730 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
6731 /// S0'. C0 and C0' have the same qualified name, but have different
6732 /// members. The edit script will consider that C0 has been deleted
6733 /// from S0 and that S0' has been inserted. This is a low level
6734 /// canonical representation of the changes; a higher level
6735 /// representation would give us a simpler way to say "the class C0
6736 /// has been modified into C0'". But worry not. We do have such
6737 /// higher representation as well; that is what changed_types() and
6738 /// changed_decls() is for.
6739 ///
6740 /// @return the edit script of the changes encapsulatd in this
6741 /// instance of scope_diff.
6742 const edit_script&
member_changes() const6743 scope_diff::member_changes() const
6744 {return priv_->member_changes_;}
6745
6746 /// Accessor of the edit script of the members of a scope.
6747 ///
6748 /// This edit script is computed using the equality operator that
6749 /// applies to shared_ptr<decl_base>.
6750 ///
6751 /// That has interesting consequences. For instance, consider two
6752 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
6753 /// S0'. C0 and C0' have the same qualified name, but have different
6754 /// members. The edit script will consider that C0 has been deleted
6755 /// from S0 and that S0' has been inserted. This is a low level
6756 /// canonical representation of the changes; a higher level
6757 /// representation would give us a simpler way to say "the class C0
6758 /// has been modified into C0'". But worry not. We do have such
6759 /// higher representation as well; that is what changed_types() and
6760 /// changed_decls() is for.
6761 ///
6762 /// @return the edit script of the changes encapsulatd in this
6763 /// instance of scope_diff.
6764 edit_script&
member_changes()6765 scope_diff::member_changes()
6766 {return priv_->member_changes_;}
6767
6768 /// Accessor that eases the manipulation of the edit script associated
6769 /// to this instance. It returns the scope member that is reported
6770 /// (in the edit script) as deleted at a given index.
6771 ///
6772 /// @param i the index (in the edit script) of an element of the first
6773 /// scope that has been reported as being delete.
6774 ///
6775 /// @return the scope member that has been reported by the edit script
6776 /// as being deleted at index i.
6777 const decl_base_sptr
deleted_member_at(unsigned i) const6778 scope_diff::deleted_member_at(unsigned i) const
6779 {
6780 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
6781 return scope->get_member_decls()[i];
6782 }
6783
6784 /// Accessor that eases the manipulation of the edit script associated
6785 /// to this instance. It returns the scope member (of the first scope
6786 /// of this diff instance) that is reported (in the edit script) as
6787 /// deleted at a given iterator.
6788 ///
6789 /// @param i the iterator of an element of the first scope that has
6790 /// been reported as being delete.
6791 ///
6792 /// @return the scope member of the first scope of this diff that has
6793 /// been reported by the edit script as being deleted at iterator i.
6794 const decl_base_sptr
deleted_member_at(vector<deletion>::const_iterator i) const6795 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
6796 {return deleted_member_at(i->index());}
6797
6798 /// Accessor that eases the manipulation of the edit script associated
6799 /// to this instance. It returns the scope member (of the second
6800 /// scope of this diff instance) that is reported as being inserted
6801 /// from a given index.
6802 ///
6803 /// @param i the index of an element of the second scope this diff
6804 /// that has been reported by the edit script as being inserted.
6805 ///
6806 /// @return the scope member of the second scope of this diff that has
6807 /// been reported as being inserted from index i.
6808 const decl_base_sptr
inserted_member_at(unsigned i)6809 scope_diff::inserted_member_at(unsigned i)
6810 {
6811 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
6812 return scope->get_member_decls()[i];
6813 }
6814
6815 /// Accessor that eases the manipulation of the edit script associated
6816 /// to this instance. It returns the scope member (of the second
6817 /// scope of this diff instance) that is reported as being inserted
6818 /// from a given iterator.
6819 ///
6820 /// @param i the iterator of an element of the second scope this diff
6821 /// that has been reported by the edit script as being inserted.
6822 ///
6823 /// @return the scope member of the second scope of this diff that has
6824 /// been reported as being inserted from iterator i.
6825 const decl_base_sptr
inserted_member_at(vector<unsigned>::const_iterator i)6826 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
6827 {return inserted_member_at(*i);}
6828
6829 /// @return a sorted vector of the types which content has changed
6830 /// from the first scope to the other.
6831 const diff_sptrs_type&
changed_types() const6832 scope_diff::changed_types() const
6833 {return priv_->sorted_changed_types_;}
6834
6835 /// @return a sorted vector of the decls which content has changed
6836 /// from the first scope to the other.
6837 const diff_sptrs_type&
changed_decls() const6838 scope_diff::changed_decls() const
6839 {return priv_->sorted_changed_decls_;}
6840
6841 const string_decl_base_sptr_map&
removed_types() const6842 scope_diff::removed_types() const
6843 {return priv_->removed_types_;}
6844
6845 const string_decl_base_sptr_map&
removed_decls() const6846 scope_diff::removed_decls() const
6847 {return priv_->removed_decls_;}
6848
6849 const string_decl_base_sptr_map&
added_types() const6850 scope_diff::added_types() const
6851 {return priv_->added_types_;}
6852
6853 const string_decl_base_sptr_map&
added_decls() const6854 scope_diff::added_decls() const
6855 {return priv_->added_decls_;}
6856
6857 /// @return the pretty representation for the current instance of @ref
6858 /// scope_diff.
6859 const string&
get_pretty_representation() const6860 scope_diff::get_pretty_representation() const
6861 {
6862 if (diff::priv_->pretty_representation_.empty())
6863 {
6864 std::ostringstream o;
6865 o << "scope_diff["
6866 << first_subject()->get_pretty_representation()
6867 << ", "
6868 << second_subject()->get_pretty_representation()
6869 << "]";
6870 diff::priv_->pretty_representation_ = o.str();
6871 }
6872 return diff::priv_->pretty_representation_;
6873 }
6874
6875 /// Return true iff the current diff node carries a change.
6876 ///
6877 /// Return true iff the current diff node carries a change.
6878 bool
has_changes() const6879 scope_diff::has_changes() const
6880 {
6881 // TODO: add the number of really removed/added stuff.
6882 return changed_types().size() + changed_decls().size();
6883 }
6884
6885 /// @return the kind of local change carried by the current diff node.
6886 /// The value returned is zero if the current node carries no local
6887 /// change.
6888 enum change_kind
has_local_changes() const6889 scope_diff::has_local_changes() const
6890 {
6891 ir::change_kind k = ir::NO_CHANGE_KIND;
6892 if (!equals(*first_scope(), *second_scope(), &k))
6893 return k & ir::ALL_LOCAL_CHANGES_MASK;
6894 return ir::NO_CHANGE_KIND;
6895 }
6896
6897 /// Report the changes of one scope against another.
6898 ///
6899 /// @param out the out stream to report the changes to.
6900 ///
6901 /// @param indent the string to use for indentation.
6902 void
report(ostream & out,const string & indent) const6903 scope_diff::report(ostream& out, const string& indent) const
6904 {
6905 context()->get_reporter()->report(*this, out, indent);
6906 }
6907
6908 /// Compute the diff between two scopes.
6909 ///
6910 /// Note that the two decls must have been created in the same @ref
6911 /// environment, otherwise, this function aborts.
6912 ///
6913 /// @param first the first scope to consider in computing the diff.
6914 ///
6915 /// @param second the second scope to consider in the diff
6916 /// computation. The second scope is diffed against the first scope.
6917 ///
6918 /// @param d a pointer to the diff object to populate with the
6919 /// computed diff.
6920 ///
6921 /// @return return the populated \a d parameter passed to this
6922 /// function.
6923 ///
6924 /// @param ctxt the diff context to use.
6925 scope_diff_sptr
compute_diff(const scope_decl_sptr first,const scope_decl_sptr second,scope_diff_sptr d,diff_context_sptr ctxt)6926 compute_diff(const scope_decl_sptr first,
6927 const scope_decl_sptr second,
6928 scope_diff_sptr d,
6929 diff_context_sptr ctxt)
6930 {
6931 ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
6932
6933 compute_diff(first->get_member_decls().begin(),
6934 first->get_member_decls().end(),
6935 second->get_member_decls().begin(),
6936 second->get_member_decls().end(),
6937 d->member_changes());
6938
6939 d->ensure_lookup_tables_populated();
6940 d->context(ctxt);
6941
6942 return d;
6943 }
6944
6945 /// Compute the diff between two scopes.
6946 ///
6947 /// Note that the two decls must have been created in the same @ref
6948 /// environment, otherwise, this function aborts.
6949 ///
6950 /// @param first_scope the first scope to consider in computing the diff.
6951 ///
6952 /// @param second_scope the second scope to consider in the diff
6953 /// computation. The second scope is diffed against the first scope.
6954 ///
6955 /// @param ctxt the diff context to use.
6956 ///
6957 /// @return return the resulting diff
6958 scope_diff_sptr
compute_diff(const scope_decl_sptr first_scope,const scope_decl_sptr second_scope,diff_context_sptr ctxt)6959 compute_diff(const scope_decl_sptr first_scope,
6960 const scope_decl_sptr second_scope,
6961 diff_context_sptr ctxt)
6962 {
6963 scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
6964 d = compute_diff(first_scope, second_scope, d, ctxt);
6965 ctxt->initialize_canonical_diff(d);
6966 return d;
6967 }
6968
6969 //</scope_diff stuff>
6970
6971 // <fn_parm_diff stuff>
6972
6973 /// Constructor for the fn_parm_diff type.
6974 ///
6975 /// @param first the first subject of the diff.
6976 ///
6977 /// @param second the second subject of the diff.
6978 ///
6979 /// @param ctxt the context of the diff. Note that this context
6980 /// object must stay alive at least during the life time of the
6981 /// current instance of @ref fn_parm_diff. Otherwise memory
6982 /// corruption issues occur.
fn_parm_diff(const function_decl::parameter_sptr first,const function_decl::parameter_sptr second,diff_context_sptr ctxt)6983 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
6984 const function_decl::parameter_sptr second,
6985 diff_context_sptr ctxt)
6986 : decl_diff_base(first, second, ctxt),
6987 priv_(new priv)
6988 {
6989 ABG_ASSERT(first->get_index() == second->get_index());
6990 priv_->type_diff = compute_diff(first->get_type(),
6991 second->get_type(),
6992 ctxt);
6993 ABG_ASSERT(priv_->type_diff);
6994 }
6995
6996 /// Getter for the first subject of this diff node.
6997 ///
6998 /// @return the first function_decl::parameter_sptr subject of this
6999 /// diff node.
7000 const function_decl::parameter_sptr
first_parameter() const7001 fn_parm_diff::first_parameter() const
7002 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
7003
7004 /// Getter for the second subject of this diff node.
7005 ///
7006 /// @return the second function_decl::parameter_sptr subject of this
7007 /// diff node.
7008 const function_decl::parameter_sptr
second_parameter() const7009 fn_parm_diff::second_parameter() const
7010 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7011
7012 /// Getter for the diff representing the changes on the type of the
7013 /// function parameter involved in the current instance of @ref
7014 /// fn_parm_diff.
7015 ///
7016 /// @return a diff_sptr representing the changes on the type of the
7017 /// function parameter we are interested in.
7018 diff_sptr
type_diff() const7019 fn_parm_diff::type_diff() const
7020 {return priv_->type_diff;}
7021
7022 /// Build and return a textual representation of the current instance
7023 /// of @ref fn_parm_diff.
7024 ///
7025 /// @return the string representing the current instance of
7026 /// fn_parm_diff.
7027 const string&
get_pretty_representation() const7028 fn_parm_diff::get_pretty_representation() const
7029 {
7030 if (diff::priv_->pretty_representation_.empty())
7031 {
7032 std::ostringstream o;
7033 o << "function_parameter_diff["
7034 << first_subject()->get_pretty_representation()
7035 << ", "
7036 << second_subject()->get_pretty_representation()
7037 << "]";
7038 diff::priv_->pretty_representation_ = o.str();
7039 }
7040 return diff::priv_->pretty_representation_;
7041 }
7042
7043 /// Return true iff the current diff node carries a change.
7044 ///
7045 /// @return true iff the current diff node carries a change.
7046 bool
has_changes() const7047 fn_parm_diff::has_changes() const
7048 {return *first_parameter() != *second_parameter();}
7049
7050 /// Check if the current diff node carries a local change.
7051 ///
7052 /// @return the kind of local change carried by the current diff node.
7053 /// The value returned is zero if the current node carries no local
7054 /// change.
7055 enum change_kind
has_local_changes() const7056 fn_parm_diff::has_local_changes() const
7057 {
7058 ir::change_kind k = ir::NO_CHANGE_KIND;
7059 if (!equals(*first_parameter(), *second_parameter(), &k))
7060 return k & ir::ALL_LOCAL_CHANGES_MASK;
7061 return ir::NO_CHANGE_KIND;
7062 }
7063
7064 /// Emit a textual report about the current fn_parm_diff instance.
7065 ///
7066 /// @param out the output stream to emit the textual report to.
7067 ///
7068 /// @param indent the indentation string to use in the report.
7069 void
report(ostream & out,const string & indent) const7070 fn_parm_diff::report(ostream& out, const string& indent) const
7071 {
7072 context()->get_reporter()->report(*this, out, indent);
7073 }
7074
7075 /// Populate the vector of children nodes of the @ref diff base type
7076 /// sub-object of this instance of @ref fn_parm_diff.
7077 ///
7078 /// The children nodes can then later be retrieved using
7079 /// diff::children_nodes()
7080 void
chain_into_hierarchy()7081 fn_parm_diff::chain_into_hierarchy()
7082 {
7083 if (type_diff())
7084 append_child_node(type_diff());
7085 }
7086
7087 /// Compute the difference between two function_decl::parameter_sptr;
7088 /// that is, between two function parameters. Return a resulting
7089 /// fn_parm_diff_sptr that represents the changes.
7090 ///
7091 /// Note that the two decls must have been created in the same @ref
7092 /// environment, otherwise, this function aborts.
7093 ///
7094 /// @param first the first subject of the diff.
7095 ///
7096 /// @param second the second subject of the diff.
7097 ///
7098 /// @param ctxt the context of the diff.
7099 ///
7100 /// @return fn_parm_diff_sptr the resulting diff node.
7101 fn_parm_diff_sptr
compute_diff(const function_decl::parameter_sptr first,const function_decl::parameter_sptr second,diff_context_sptr ctxt)7102 compute_diff(const function_decl::parameter_sptr first,
7103 const function_decl::parameter_sptr second,
7104 diff_context_sptr ctxt)
7105 {
7106 if (!first || !second)
7107 return fn_parm_diff_sptr();
7108
7109 fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7110 ctxt->initialize_canonical_diff(result);
7111
7112 return result;
7113 }
7114 // </fn_parm_diff stuff>
7115
7116 // <function_type_diff stuff>
7117
7118 void
ensure_lookup_tables_populated()7119 function_type_diff::ensure_lookup_tables_populated()
7120 {
7121 priv_->return_type_diff_ =
7122 compute_diff(first_function_type()->get_return_type(),
7123 second_function_type()->get_return_type(),
7124 context());
7125
7126 string parm_name;
7127 function_decl::parameter_sptr parm;
7128 for (vector<deletion>::const_iterator i =
7129 priv_->parm_changes_.deletions().begin();
7130 i != priv_->parm_changes_.deletions().end();
7131 ++i)
7132 {
7133 parm = *(first_function_type()->get_first_parm()
7134 + i->index());
7135 parm_name = parm->get_name_id();
7136 // If for a reason the type name is empty we want to know and
7137 // fix that.
7138 ABG_ASSERT(!parm_name.empty());
7139 priv_->deleted_parms_[parm_name] = parm;
7140 priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7141 }
7142
7143 for (vector<insertion>::const_iterator i =
7144 priv_->parm_changes_.insertions().begin();
7145 i != priv_->parm_changes_.insertions().end();
7146 ++i)
7147 {
7148 for (vector<unsigned>::const_iterator j =
7149 i->inserted_indexes().begin();
7150 j != i->inserted_indexes().end();
7151 ++j)
7152 {
7153 parm = *(second_function_type()->get_first_parm() + *j);
7154 parm_name = parm->get_name_id();
7155 // If for a reason the type name is empty we want to know and
7156 // fix that.
7157 ABG_ASSERT(!parm_name.empty());
7158 {
7159 string_parm_map::const_iterator k =
7160 priv_->deleted_parms_.find(parm_name);
7161 if (k != priv_->deleted_parms_.end())
7162 {
7163 if (*k->second != *parm)
7164 priv_->subtype_changed_parms_[parm_name] =
7165 compute_diff(k->second, parm, context());
7166 priv_->deleted_parms_.erase(parm_name);
7167 }
7168 else
7169 priv_->added_parms_[parm_name] = parm;
7170 }
7171 {
7172 unsigned_parm_map::const_iterator k =
7173 priv_->deleted_parms_by_id_.find(parm->get_index());
7174 if (k != priv_->deleted_parms_by_id_.end())
7175 {
7176 if (*k->second != *parm
7177 && (k->second->get_name_id() != parm_name))
7178 priv_->changed_parms_by_id_[parm->get_index()] =
7179 compute_diff(k->second, parm, context());
7180 priv_->added_parms_.erase(parm_name);
7181 priv_->deleted_parms_.erase(k->second->get_name_id());
7182 priv_->deleted_parms_by_id_.erase(parm->get_index());
7183 }
7184 else
7185 priv_->added_parms_by_id_[parm->get_index()] = parm;
7186 }
7187 }
7188 }
7189
7190 sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7191 priv_->sorted_subtype_changed_parms_);
7192 sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7193 priv_->sorted_changed_parms_by_id_);
7194 sort_string_parm_map(priv_->deleted_parms_,
7195 priv_->sorted_deleted_parms_);
7196
7197 sort_string_parm_map(priv_->added_parms_,
7198 priv_->sorted_added_parms_);
7199 }
7200
7201 /// In the vector of deleted parameters, get the one that is at a given
7202 /// index.
7203 ///
7204 /// @param i the index of the deleted parameter to get.
7205 ///
7206 /// @return the parameter returned.
7207 const function_decl::parameter_sptr
deleted_parameter_at(int i) const7208 function_type_diff::deleted_parameter_at(int i) const
7209 {return first_function_type()->get_parameters()[i];}
7210
7211 /// Getter for the sorted vector of deleted parameters.
7212 ///
7213 /// @return the sorted vector of deleted parameters.
7214 const vector<function_decl::parameter_sptr>&
sorted_deleted_parms() const7215 function_type_diff::sorted_deleted_parms() const
7216 {return priv_->sorted_deleted_parms_;}
7217
7218 /// Getter for the sorted vector of added parameters .
7219 ///
7220 /// @return the sorted vector of added parameters.
7221 const vector<function_decl::parameter_sptr>&
sorted_added_parms() const7222 function_type_diff::sorted_added_parms() const
7223 {return priv_->sorted_added_parms_;}
7224
7225 /// In the vector of inserted parameters, get the one that is at a
7226 /// given index.
7227 ///
7228 /// @param i the index of the inserted parameter to get.
7229 ///
7230 /// @return the parameter returned.
7231 const function_decl::parameter_sptr
inserted_parameter_at(int i) const7232 function_type_diff::inserted_parameter_at(int i) const
7233 {return second_function_type()->get_parameters()[i];}
7234
7235 /// Consutrctor of the @ref function_type type.
7236 ///
7237 /// @param first the first @ref function_type subject of the diff to
7238 /// create.
7239 ///
7240 /// @param second the second @ref function_type subject of the diff to
7241 /// create.
7242 ///
7243 /// @param ctxt the diff context to be used by the newly created
7244 /// instance of function_type_diff. Note that this context object
7245 /// must stay alive at least during the life time of the current
7246 /// instance of @ref function_type_diff. Otherwise memory corruption
7247 /// issues occur.
function_type_diff(const function_type_sptr first,const function_type_sptr second,diff_context_sptr ctxt)7248 function_type_diff::function_type_diff(const function_type_sptr first,
7249 const function_type_sptr second,
7250 diff_context_sptr ctxt)
7251 : type_diff_base(first, second, ctxt),
7252 priv_(new priv)
7253 {}
7254
7255 /// Getter for the first subject of the diff.
7256 ///
7257 /// @return the first function type involved in the diff.
7258 const function_type_sptr
first_function_type() const7259 function_type_diff::first_function_type() const
7260 {return dynamic_pointer_cast<function_type>(first_subject());}
7261
7262 /// Getter for the second subject of the diff.
7263 ///
7264 /// @return the second function type involved in the diff.
7265 const function_type_sptr
second_function_type() const7266 function_type_diff::second_function_type() const
7267 {return dynamic_pointer_cast<function_type>(second_subject());}
7268
7269 /// Getter for the diff of the return types of the two function types
7270 /// of the current diff.
7271 ///
7272 /// @return the diff of the return types of the two function types of
7273 /// the current diff.
7274 const diff_sptr
return_type_diff() const7275 function_type_diff::return_type_diff() const
7276 {return priv_->return_type_diff_;}
7277
7278 /// Getter for the map of function parameter changes of the current diff.
7279 ///
7280 /// @return a map of function parameter changes of the current diff.
7281 const string_fn_parm_diff_sptr_map&
subtype_changed_parms() const7282 function_type_diff::subtype_changed_parms() const
7283 {return priv_->subtype_changed_parms_;}
7284
7285 /// Getter for the map of parameters that got removed.
7286 ///
7287 /// @return the map of parameters that got removed.
7288 const string_parm_map&
removed_parms() const7289 function_type_diff::removed_parms() const
7290 {return priv_->deleted_parms_;}
7291
7292 /// Getter for the map of parameters that got added.
7293 ///
7294 /// @return the map of parameters that got added.
7295 const string_parm_map&
added_parms() const7296 function_type_diff::added_parms() const
7297 {return priv_->added_parms_;}
7298
7299 /// Build and return a copy of a pretty representation of the current
7300 /// instance of @ref function_type_diff.
7301 ///
7302 /// @return a copy of the pretty representation of the current
7303 /// instance of @ref function_type_diff.
7304 const string&
get_pretty_representation() const7305 function_type_diff::get_pretty_representation() const
7306 {
7307 if (diff::priv_->pretty_representation_.empty())
7308 {
7309 std::ostringstream o;
7310 o << "function_type_diff["
7311 << abigail::ir::get_pretty_representation(first_function_type())
7312 << ", "
7313 << abigail::ir::get_pretty_representation(second_function_type())
7314 << "]";
7315 diff::priv_->pretty_representation_ = o.str();
7316 }
7317 return diff::priv_->pretty_representation_;
7318 }
7319
7320 /// Test if the current diff node carries changes.
7321 ///
7322 /// @return true iff the current diff node carries changes.
7323 bool
has_changes() const7324 function_type_diff::has_changes() const
7325 {return *first_function_type() != *second_function_type();}
7326
7327 /// Test if the current diff node carries local changes.
7328 ///
7329 /// A local change is a change that is carried by this diff node, not
7330 /// by any of its children nodes.
7331 ///
7332 /// @return the kind of local change carried by the current diff node.
7333 /// The value returned is zero if the current node carries no local
7334 /// change.
7335 enum change_kind
has_local_changes() const7336 function_type_diff::has_local_changes() const
7337 {
7338 ir::change_kind k = ir::NO_CHANGE_KIND;
7339 if (!equals(*first_function_type(), *second_function_type(), &k))
7340 return k & ir::ALL_LOCAL_CHANGES_MASK;
7341 return ir::NO_CHANGE_KIND;
7342 }
7343
7344 /// Build and emit a textual report about the current @ref
7345 /// function_type_diff instance.
7346 ///
7347 /// @param out the output stream.
7348 ///
7349 /// @param indent the indentation string to use.
7350 void
report(ostream & out,const string & indent) const7351 function_type_diff::report(ostream& out, const string& indent) const
7352 {
7353 context()->get_reporter()->report(*this, out, indent);
7354 }
7355
7356 /// Populate the vector of children node of the @ref diff base type
7357 /// sub-object of this instance of @ref function_type_diff.
7358 ///
7359 /// The children node can then later be retrieved using
7360 /// diff::children_node().
7361 void
chain_into_hierarchy()7362 function_type_diff::chain_into_hierarchy()
7363 {
7364 if (diff_sptr d = return_type_diff())
7365 append_child_node(d);
7366
7367 for (vector<fn_parm_diff_sptr>::const_iterator i =
7368 priv_->sorted_subtype_changed_parms_.begin();
7369 i != priv_->sorted_subtype_changed_parms_.end();
7370 ++i)
7371 if (diff_sptr d = *i)
7372 append_child_node(d);
7373
7374 for (vector<fn_parm_diff_sptr>::const_iterator i =
7375 priv_->sorted_changed_parms_by_id_.begin();
7376 i != priv_->sorted_changed_parms_by_id_.end();
7377 ++i)
7378 if (diff_sptr d = *i)
7379 append_child_node(d);
7380 }
7381
7382 /// Compute the diff between two instances of @ref function_type.
7383 ///
7384 /// Note that the two types must have been created in the same @ref
7385 /// environment, otherwise, this function aborts.
7386 ///
7387 /// @param first the first @ref function_type to consider for the diff.
7388 ///
7389 /// @param second the second @ref function_type to consider for the diff.
7390 ///
7391 /// @param ctxt the diff context to use.
7392 ///
7393 /// @return the resulting diff between the two @ref function_type.
7394 function_type_diff_sptr
compute_diff(const function_type_sptr first,const function_type_sptr second,diff_context_sptr ctxt)7395 compute_diff(const function_type_sptr first,
7396 const function_type_sptr second,
7397 diff_context_sptr ctxt)
7398 {
7399 if (!first || !second)
7400 {
7401 // TODO: implement this for either first or second being NULL.
7402 return function_type_diff_sptr();
7403 }
7404
7405 function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7406
7407 diff_utils::compute_diff(first->get_first_parm(),
7408 first->get_parameters().end(),
7409 second->get_first_parm(),
7410 second->get_parameters().end(),
7411 result->priv_->parm_changes_);
7412
7413 result->ensure_lookup_tables_populated();
7414
7415 ctxt->initialize_canonical_diff(result);
7416
7417 return result;
7418 }
7419 // </function_type_diff stuff>
7420
7421 // <function_decl_diff stuff>
7422
7423 /// Build the lookup tables of the diff, if necessary.
7424 void
ensure_lookup_tables_populated()7425 function_decl_diff::ensure_lookup_tables_populated()
7426 {
7427 }
7428
7429 /// Populate the vector of children node of the @ref diff base type
7430 /// sub-object of this instance of @ref function_decl_diff.
7431 ///
7432 /// The children node can then later be retrieved using
7433 /// diff::children_node().
7434 void
chain_into_hierarchy()7435 function_decl_diff::chain_into_hierarchy()
7436 {
7437 if (diff_sptr d = type_diff())
7438 append_child_node(d);
7439 }
7440
7441 /// Constructor for function_decl_diff
7442 ///
7443 /// @param first the first function considered by the diff.
7444 ///
7445 /// @param second the second function considered by the diff.
7446 ///
7447 /// @param ctxt the context of the diff. Note that this context
7448 /// object must stay alive at least during the life time of the
7449 /// current instance of @ref function_decl_diff. Otherwise memory
7450 /// corruption issues occur.
function_decl_diff(const function_decl_sptr first,const function_decl_sptr second,diff_context_sptr ctxt)7451 function_decl_diff::function_decl_diff(const function_decl_sptr first,
7452 const function_decl_sptr second,
7453 diff_context_sptr ctxt)
7454 : decl_diff_base(first, second, ctxt),
7455 priv_(new priv)
7456 {
7457 }
7458
7459 /// @return the first function considered by the diff.
7460 const function_decl_sptr
first_function_decl() const7461 function_decl_diff::first_function_decl() const
7462 {return dynamic_pointer_cast<function_decl>(first_subject());}
7463
7464 /// @return the second function considered by the diff.
7465 const function_decl_sptr
second_function_decl() const7466 function_decl_diff::second_function_decl() const
7467 {return dynamic_pointer_cast<function_decl>(second_subject());}
7468
7469 const function_type_diff_sptr
type_diff() const7470 function_decl_diff::type_diff() const
7471 {return priv_->type_diff_;}
7472
7473 /// @return the pretty representation for the current instance of @ref
7474 /// function_decl_diff.
7475 const string&
get_pretty_representation() const7476 function_decl_diff::get_pretty_representation() const
7477 {
7478 if (diff::priv_->pretty_representation_.empty())
7479 {
7480 std::ostringstream o;
7481 o << "function_diff["
7482 << first_subject()->get_pretty_representation()
7483 << ", "
7484 << second_subject()->get_pretty_representation()
7485 << "]";
7486 diff::priv_->pretty_representation_ = o.str();
7487 }
7488 return diff::priv_->pretty_representation_;
7489 }
7490
7491 /// Return true iff the current diff node carries a change.
7492 ///
7493 /// @return true iff the current diff node carries a change.
7494 bool
has_changes() const7495 function_decl_diff::has_changes() const
7496 {return *first_function_decl() != *second_function_decl();}
7497
7498 /// @return the kind of local change carried by the current diff node.
7499 /// The value returned is zero if the current node carries no local
7500 /// change.
7501 enum change_kind
has_local_changes() const7502 function_decl_diff::has_local_changes() const
7503 {
7504 ir::change_kind k = ir::NO_CHANGE_KIND;
7505 if (!equals(*first_function_decl(), *second_function_decl(), &k))
7506 return k & ir::ALL_LOCAL_CHANGES_MASK;
7507 return ir::NO_CHANGE_KIND;
7508 }
7509
7510 /// Serialize a report of the changes encapsulated in the current
7511 /// instance of @ref function_decl_diff over to an output stream.
7512 ///
7513 /// @param out the output stream to serialize the report to.
7514 ///
7515 /// @param indent the string to use an an indentation prefix.
7516 void
report(ostream & out,const string & indent) const7517 function_decl_diff::report(ostream& out, const string& indent) const
7518 {
7519 context()->get_reporter()->report(*this, out, indent);
7520 }
7521
7522 /// Compute the diff between two function_decl.
7523 ///
7524 /// Note that the two decls must have been created in the same @ref
7525 /// environment, otherwise, this function aborts.
7526 ///
7527 /// @param first the first function_decl to consider for the diff
7528 ///
7529 /// @param second the second function_decl to consider for the diff
7530 ///
7531 /// @param ctxt the diff context to use.
7532 ///
7533 /// @return the computed diff
7534 function_decl_diff_sptr
compute_diff(const function_decl_sptr first,const function_decl_sptr second,diff_context_sptr ctxt)7535 compute_diff(const function_decl_sptr first,
7536 const function_decl_sptr second,
7537 diff_context_sptr ctxt)
7538 {
7539 if (!first || !second)
7540 {
7541 // TODO: implement this for either first or second being NULL.
7542 return function_decl_diff_sptr();
7543 }
7544
7545 function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7546 second->get_type(),
7547 ctxt);
7548
7549 function_decl_diff_sptr result(new function_decl_diff(first, second,
7550 ctxt));
7551 result->priv_->type_diff_ = type_diff;
7552
7553 result->ensure_lookup_tables_populated();
7554
7555 ctxt->initialize_canonical_diff(result);
7556
7557 return result;
7558 }
7559
7560 // </function_decl_diff stuff>
7561
7562 // <type_decl_diff stuff>
7563
7564 /// Constructor for type_decl_diff.
7565 ///
7566 /// @param first the first subject of the diff.
7567 ///
7568 /// @param second the second subject of the diff.
7569 ///
7570 /// @param ctxt the context of the diff. Note that this context
7571 /// object must stay alive at least during the life time of the
7572 /// current instance of @ref type_decl_diff. Otherwise memory
7573 /// corruption issues occur.
type_decl_diff(const type_decl_sptr first,const type_decl_sptr second,diff_context_sptr ctxt)7574 type_decl_diff::type_decl_diff(const type_decl_sptr first,
7575 const type_decl_sptr second,
7576 diff_context_sptr ctxt)
7577 : type_diff_base(first, second, ctxt)
7578 {}
7579
7580 /// Getter for the first subject of the type_decl_diff.
7581 ///
7582 /// @return the first type_decl involved in the diff.
7583 const type_decl_sptr
first_type_decl() const7584 type_decl_diff::first_type_decl() const
7585 {return dynamic_pointer_cast<type_decl>(first_subject());}
7586
7587 /// Getter for the second subject of the type_decl_diff.
7588 ///
7589 /// @return the second type_decl involved in the diff.
7590 const type_decl_sptr
second_type_decl() const7591 type_decl_diff::second_type_decl() const
7592 {return dynamic_pointer_cast<type_decl>(second_subject());}
7593
7594 /// @return the pretty representation for the current instance of @ref
7595 /// type_decl_diff.
7596 const string&
get_pretty_representation() const7597 type_decl_diff::get_pretty_representation() const
7598 {
7599 if (diff::priv_->pretty_representation_.empty())
7600 {
7601 std::ostringstream o;
7602 o << "type_decl_diff["
7603 << first_subject()->get_pretty_representation()
7604 << ", "
7605 << second_subject()->get_pretty_representation()
7606 << "]";
7607 diff::priv_->pretty_representation_ = o.str();
7608 }
7609 return diff::priv_->pretty_representation_;
7610 }
7611 /// Return true iff the current diff node carries a change.
7612 ///
7613 /// @return true iff the current diff node carries a change.
7614 bool
has_changes() const7615 type_decl_diff::has_changes() const
7616 {return first_type_decl() != second_type_decl();}
7617
7618 /// @return the kind of local change carried by the current diff node.
7619 /// The value returned is zero if the current node carries no local
7620 /// change.
7621 enum change_kind
has_local_changes() const7622 type_decl_diff::has_local_changes() const
7623 {
7624 ir::change_kind k = ir::NO_CHANGE_KIND;
7625 if (!equals(*first_type_decl(), *second_type_decl(), &k))
7626 return k & ir::ALL_LOCAL_CHANGES_MASK;
7627 return ir::NO_CHANGE_KIND;
7628 }
7629 /// Ouputs a report of the differences between of the two type_decl
7630 /// involved in the type_decl_diff.
7631 ///
7632 /// @param out the output stream to emit the report to.
7633 ///
7634 /// @param indent the string to use for indentatino indent.
7635 void
report(ostream & out,const string & indent) const7636 type_decl_diff::report(ostream& out, const string& indent) const
7637 {
7638 context()->get_reporter()->report(*this, out, indent);
7639 }
7640
7641 /// Compute a diff between two type_decl.
7642 ///
7643 /// Note that the two types must have been created in the same @ref
7644 /// environment, otherwise, this function aborts.
7645 ///
7646 /// This function doesn't actually compute a diff. As a type_decl is
7647 /// very simple (unlike compound constructs like function_decl or
7648 /// class_decl) it's easy to just compare the components of the
7649 /// type_decl to know what has changed. Thus this function just
7650 /// builds and return a type_decl_diff object. The
7651 /// type_decl_diff::report function will just compare the components
7652 /// of the the two type_decl and display where and how they differ.
7653 ///
7654 /// @param first a pointer to the first type_decl to
7655 /// consider.
7656 ///
7657 /// @param second a pointer to the second type_decl to consider.
7658 ///
7659 /// @param ctxt the diff context to use.
7660 ///
7661 /// @return a pointer to the resulting type_decl_diff.
7662 type_decl_diff_sptr
compute_diff(const type_decl_sptr first,const type_decl_sptr second,diff_context_sptr ctxt)7663 compute_diff(const type_decl_sptr first,
7664 const type_decl_sptr second,
7665 diff_context_sptr ctxt)
7666 {
7667 type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7668
7669 // We don't need to actually compute a diff here as a type_decl
7670 // doesn't have complicated sub-components. type_decl_diff::report
7671 // just walks the members of the type_decls and display information
7672 // about the ones that have changed. On a similar note,
7673 // type_decl_diff::length returns 0 if the two type_decls are equal,
7674 // and 1 otherwise.
7675
7676 ctxt->initialize_canonical_diff(result);
7677
7678 return result;
7679 }
7680
7681 // </type_decl_diff stuff>
7682
7683 // <typedef_diff stuff>
7684
7685 /// Populate the vector of children node of the @ref diff base type
7686 /// sub-object of this instance of @ref typedef_diff.
7687 ///
7688 /// The children node can then later be retrieved using
7689 /// diff::children_node().
7690 void
chain_into_hierarchy()7691 typedef_diff::chain_into_hierarchy()
7692 {append_child_node(underlying_type_diff());}
7693
7694 /// Constructor for typedef_diff.
7695 ///
7696 /// @param first the first subject of the diff.
7697 ///
7698 /// @param second the second subject of the diff.
7699 ///
7700 /// @param underlying the underlying diff of the @ref typedef_diff.
7701 /// That is the diff between the underlying types of @p first and @p
7702 /// second.
7703 ///
7704 /// @param ctxt the context of the diff. Note that this context
7705 /// object must stay alive at least during the life time of the
7706 /// current instance of @ref typedef_diff. Otherwise memory
7707 /// corruption issues occur.
typedef_diff(const typedef_decl_sptr first,const typedef_decl_sptr second,const diff_sptr underlying,diff_context_sptr ctxt)7708 typedef_diff::typedef_diff(const typedef_decl_sptr first,
7709 const typedef_decl_sptr second,
7710 const diff_sptr underlying,
7711 diff_context_sptr ctxt)
7712 : type_diff_base(first, second, ctxt),
7713 priv_(new priv(underlying))
7714 {}
7715
7716 /// Getter for the firt typedef_decl involved in the diff.
7717 ///
7718 /// @return the first subject of the diff.
7719 const typedef_decl_sptr
first_typedef_decl() const7720 typedef_diff::first_typedef_decl() const
7721 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
7722
7723 /// Getter for the second typedef_decl involved in the diff.
7724 ///
7725 /// @return the second subject of the diff.
7726 const typedef_decl_sptr
second_typedef_decl() const7727 typedef_diff::second_typedef_decl() const
7728 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
7729
7730 /// Getter for the diff between the two underlying types of the
7731 /// typedefs.
7732 ///
7733 /// @return the diff object reprensenting the difference between the
7734 /// two underlying types of the typedefs.
7735 const diff_sptr
underlying_type_diff() const7736 typedef_diff::underlying_type_diff() const
7737 {return priv_->underlying_type_diff_;}
7738
7739 /// Setter for the diff between the two underlying types of the
7740 /// typedefs.
7741 ///
7742 /// @param d the new diff object reprensenting the difference between
7743 /// the two underlying types of the typedefs.
7744 void
underlying_type_diff(const diff_sptr d)7745 typedef_diff::underlying_type_diff(const diff_sptr d)
7746 {priv_->underlying_type_diff_ = d;}
7747
7748 /// @return the pretty representation for the current instance of @ref
7749 /// typedef_diff.
7750 const string&
get_pretty_representation() const7751 typedef_diff::get_pretty_representation() const
7752 {
7753 if (diff::priv_->pretty_representation_.empty())
7754 {
7755 std::ostringstream o;
7756 o << "typedef_diff["
7757 << first_subject()->get_pretty_representation()
7758 << ", "
7759 << second_subject()->get_pretty_representation()
7760 << "]";
7761 diff::priv_->pretty_representation_ = o.str();
7762 }
7763 return diff::priv_->pretty_representation_;
7764 }
7765
7766 /// Return true iff the current diff node carries a change.
7767 ///
7768 /// @return true iff the current diff node carries a change.
7769 bool
has_changes() const7770 typedef_diff::has_changes() const
7771 {
7772 decl_base_sptr second = second_typedef_decl();
7773 return !(*first_typedef_decl() == *second);
7774 }
7775
7776 /// @return the kind of local change carried by the current diff node.
7777 /// The value returned is zero if the current node carries no local
7778 /// change.
7779 enum change_kind
has_local_changes() const7780 typedef_diff::has_local_changes() const
7781 {
7782 ir::change_kind k = ir::NO_CHANGE_KIND;
7783 if (!equals(*first_typedef_decl(), *second_typedef_decl(), &k))
7784 return k & ir::ALL_LOCAL_CHANGES_MASK;
7785 return ir::NO_CHANGE_KIND;
7786 }
7787
7788 /// Reports the difference between the two subjects of the diff in a
7789 /// serialized form.
7790 ///
7791 /// @param out the output stream to emit the report to.
7792 ///
7793 /// @param indent the indentation string to use.
7794 void
report(ostream & out,const string & indent) const7795 typedef_diff::report(ostream& out, const string& indent) const
7796 {
7797 context()->get_reporter()->report(*this, out, indent);
7798 }
7799
7800 /// Compute a diff between two typedef_decl.
7801 ///
7802 /// Note that the two types must have been created in the same @ref
7803 /// environment, otherwise, this function aborts.
7804 ///
7805 /// @param first a pointer to the first typedef_decl to consider.
7806 ///
7807 /// @param second a pointer to the second typedef_decl to consider.
7808 ///
7809 /// @param ctxt the diff context to use.
7810 ///
7811 /// @return a pointer to the the resulting typedef_diff.
7812 typedef_diff_sptr
compute_diff(const typedef_decl_sptr first,const typedef_decl_sptr second,diff_context_sptr ctxt)7813 compute_diff(const typedef_decl_sptr first,
7814 const typedef_decl_sptr second,
7815 diff_context_sptr ctxt)
7816 {
7817 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
7818 second->get_underlying_type(),
7819 ctxt);
7820 typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
7821
7822 ctxt->initialize_canonical_diff(result);
7823
7824 return result;
7825 }
7826
7827 /// Return the leaf underlying diff node of a @ref typedef_diff node.
7828 ///
7829 /// If the underlying diff node of a @ref typedef_diff node is itself
7830 /// a @ref typedef_diff node, then recursively look at the underlying
7831 /// diff nodes to get the first one that is not a a @ref typedef_diff
7832 /// node. This is what a leaf underlying diff node means.
7833 ///
7834 /// Otherwise, if the underlying diff node of @ref typedef_diff is
7835 /// *NOT* a @ref typedef_diff node, then just return the underlying
7836 /// diff node.
7837 ///
7838 /// And if the diff node considered is not a @ref typedef_diff node,
7839 /// then just return it.
7840 ///
7841 /// @return the leaf underlying diff node of a @p diff.
7842 const diff*
get_typedef_diff_underlying_type_diff(const diff * diff)7843 get_typedef_diff_underlying_type_diff(const diff* diff)
7844 {
7845 const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
7846 if (!d)
7847 return diff;
7848
7849 if (const typedef_diff* deef =
7850 dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
7851 return get_typedef_diff_underlying_type_diff(deef);
7852
7853 return d->underlying_type_diff().get();
7854 }
7855
7856 // </typedef_diff stuff>
7857
7858 // <translation_unit_diff stuff>
7859
7860 /// Constructor for translation_unit_diff.
7861 ///
7862 /// @param first the first translation unit to consider for this diff.
7863 ///
7864 /// @param second the second translation unit to consider for this diff.
7865 ///
7866 /// @param ctxt the context of the diff. Note that this context
7867 /// object must stay alive at least during the life time of the
7868 /// current instance of @ref translation_unit_diff. Otherwise memory
7869 /// corruption issues occur.
translation_unit_diff(translation_unit_sptr first,translation_unit_sptr second,diff_context_sptr ctxt)7870 translation_unit_diff::translation_unit_diff(translation_unit_sptr first,
7871 translation_unit_sptr second,
7872 diff_context_sptr ctxt)
7873 : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
7874 priv_(new priv(first, second))
7875 {
7876 }
7877
7878 /// Getter for the first translation unit of this diff.
7879 ///
7880 /// @return the first translation unit of this diff.
7881 const translation_unit_sptr
first_translation_unit() const7882 translation_unit_diff::first_translation_unit() const
7883 {return priv_->first_;}
7884
7885 /// Getter for the second translation unit of this diff.
7886 ///
7887 /// @return the second translation unit of this diff.
7888 const translation_unit_sptr
second_translation_unit() const7889 translation_unit_diff::second_translation_unit() const
7890 {return priv_->second_;}
7891
7892 /// Return true iff the current diff node carries a change.
7893 ///
7894 /// @return true iff the current diff node carries a change.
7895 bool
has_changes() const7896 translation_unit_diff::has_changes() const
7897 {return scope_diff::has_changes();}
7898
7899 /// @return the kind of local change carried by the current diff node.
7900 /// The value returned is zero if the current node carries no local
7901 /// change.
7902 enum change_kind
has_local_changes() const7903 translation_unit_diff::has_local_changes() const
7904 {return ir::NO_CHANGE_KIND;}
7905
7906 /// Report the diff in a serialized form.
7907 ///
7908 /// @param out the output stream to serialize the report to.
7909 ///
7910 /// @param indent the prefix to use as indentation for the report.
7911 void
report(ostream & out,const string & indent) const7912 translation_unit_diff::report(ostream& out, const string& indent) const
7913 {scope_diff::report(out, indent);}
7914
7915 /// Compute the diff between two translation_units.
7916 ///
7917 /// Note that the two translation units must have been created in the
7918 /// same @ref environment, otherwise, this function aborts.
7919 ///
7920 /// @param first the first translation_unit to consider.
7921 ///
7922 /// @param second the second translation_unit to consider.
7923 ///
7924 /// @param ctxt the diff context to use. If null, this function will
7925 /// create a new context and set to the diff object returned.
7926 ///
7927 /// @return the newly created diff object.
7928 translation_unit_diff_sptr
compute_diff(const translation_unit_sptr first,const translation_unit_sptr second,diff_context_sptr ctxt)7929 compute_diff(const translation_unit_sptr first,
7930 const translation_unit_sptr second,
7931 diff_context_sptr ctxt)
7932 {
7933 ABG_ASSERT(first && second);
7934
7935 if (!ctxt)
7936 ctxt.reset(new diff_context);
7937
7938 // TODO: handle first or second having empty contents.
7939 translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
7940 ctxt));
7941 scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
7942
7943 compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
7944 static_pointer_cast<scope_decl>(second->get_global_scope()),
7945 sc_diff,
7946 ctxt);
7947
7948 ctxt->initialize_canonical_diff(tu_diff);
7949
7950 return tu_diff;
7951 }
7952
7953 // </translation_unit_diff stuff>
7954
7955 // <diff_maps stuff>
7956
7957 /// The private data of the @ref diff_maps type.
7958 struct diff_maps::priv
7959 {
7960 string_diff_ptr_map type_decl_diff_map_;
7961 string_diff_ptr_map enum_diff_map_;
7962 string_diff_ptr_map class_diff_map_;
7963 string_diff_ptr_map union_diff_map_;
7964 string_diff_ptr_map typedef_diff_map_;
7965 string_diff_ptr_map subrange_diff_map_;
7966 string_diff_ptr_map array_diff_map_;
7967 string_diff_ptr_map reference_diff_map_;
7968 string_diff_ptr_map function_type_diff_map_;
7969 string_diff_ptr_map function_decl_diff_map_;
7970 string_diff_ptr_map var_decl_diff_map_;
7971 string_diff_ptr_map distinct_diff_map_;
7972 string_diff_ptr_map fn_parm_diff_map_;
7973 diff_artifact_set_map_type impacted_artifacts_map_;
7974 }; // end struct diff_maps::priv
7975
7976 /// Default constructor of the @ref diff_maps type.
diff_maps()7977 diff_maps::diff_maps()
7978 : priv_(new diff_maps::priv())
7979 {}
7980
7981 diff_maps::~diff_maps() = default;
7982
7983 /// Getter of the map that contains basic type diffs.
7984 ///
7985 /// @return the map that contains basic type diffs.
7986 const string_diff_ptr_map&
get_type_decl_diff_map() const7987 diff_maps::get_type_decl_diff_map() const
7988 {return priv_->type_decl_diff_map_;}
7989
7990 /// Getter of the map that contains basic type diffs.
7991 ///
7992 /// @return the map that contains basic type diffs.
7993 string_diff_ptr_map&
get_type_decl_diff_map()7994 diff_maps::get_type_decl_diff_map()
7995 {return priv_->type_decl_diff_map_;}
7996
7997 /// Getter of the map that contains enum type diffs.
7998 ///
7999 /// @return the map that contains enum type diffs.
8000 const string_diff_ptr_map&
get_enum_diff_map() const8001 diff_maps::get_enum_diff_map() const
8002 {return priv_->enum_diff_map_;}
8003
8004 /// Getter of the map that contains enum type diffs.
8005 ///
8006 /// @return the map that contains enum type diffs.
8007 string_diff_ptr_map&
get_enum_diff_map()8008 diff_maps::get_enum_diff_map()
8009 {return priv_->enum_diff_map_;}
8010
8011 /// Getter of the map that contains class type diffs.
8012 ///
8013 /// @return the map that contains class type diffs.
8014 const string_diff_ptr_map&
get_class_diff_map() const8015 diff_maps::get_class_diff_map() const
8016 {return priv_->class_diff_map_;}
8017
8018 /// Getter of the map that contains class type diffs.
8019 ///
8020 /// @return the map that contains class type diffs.
8021 string_diff_ptr_map&
get_class_diff_map()8022 diff_maps::get_class_diff_map()
8023 {return priv_->class_diff_map_;}
8024
8025 /// Getter of the map that contains union type diffs.
8026 ///
8027 /// @return the map that contains union type diffs.
8028 const string_diff_ptr_map&
get_union_diff_map() const8029 diff_maps::get_union_diff_map() const
8030 {return priv_->union_diff_map_;}
8031
8032 /// Getter of the map that contains union type diffs.
8033 ///
8034 /// @return the map that contains union type diffs.
8035 string_diff_ptr_map&
get_union_diff_map()8036 diff_maps::get_union_diff_map()
8037 {return priv_->union_diff_map_;}
8038
8039 /// Getter of the map that contains typedef type diffs.
8040 ///
8041 /// @return the map that contains typedef type diffs.
8042 const string_diff_ptr_map&
get_typedef_diff_map() const8043 diff_maps::get_typedef_diff_map() const
8044 {return priv_->typedef_diff_map_;}
8045
8046 /// Getter of the map that contains typedef type diffs.
8047 ///
8048 /// @return the map that contains typedef type diffs.
8049 string_diff_ptr_map&
get_typedef_diff_map()8050 diff_maps::get_typedef_diff_map()
8051 {return priv_->typedef_diff_map_;}
8052
8053 /// Getter of the map that contains subrange type diffs.
8054 ///
8055 /// @return the map that contains subrange type diffs.
8056 const string_diff_ptr_map&
get_subrange_diff_map() const8057 diff_maps::get_subrange_diff_map() const
8058 {return priv_->subrange_diff_map_;}
8059
8060 /// Getter of the map that contains subrange type diffs.
8061 ///
8062 /// @return the map that contains subrange type diffs.
8063 string_diff_ptr_map&
get_subrange_diff_map()8064 diff_maps::get_subrange_diff_map()
8065 {return priv_->subrange_diff_map_;}
8066
8067 /// Getter of the map that contains array type diffs.
8068 ///
8069 /// @return the map that contains array type diffs.
8070 const string_diff_ptr_map&
get_array_diff_map() const8071 diff_maps::get_array_diff_map() const
8072 {return priv_->array_diff_map_;}
8073
8074 /// Getter of the map that contains array type diffs.
8075 ///
8076 /// @return the map that contains array type diffs.
8077 string_diff_ptr_map&
get_array_diff_map()8078 diff_maps::get_array_diff_map()
8079 {return priv_->array_diff_map_;}
8080
8081 /// Getter of the map that contains reference type diffs.
8082 ///
8083 /// @return the map that contains reference type diffs.
8084 const string_diff_ptr_map&
get_reference_diff_map() const8085 diff_maps::get_reference_diff_map() const
8086 {return priv_->reference_diff_map_;}
8087
8088 /// Getter of the map that contains reference type diffs.
8089 ///
8090 /// @return the map that contains reference type diffs.
8091 string_diff_ptr_map&
get_reference_diff_map()8092 diff_maps::get_reference_diff_map()
8093 {{return priv_->reference_diff_map_;}}
8094
8095 /// Getter of the map that contains function parameter diffs.
8096 ///
8097 /// @return the map that contains function parameter diffs.
8098 const string_diff_ptr_map&
get_fn_parm_diff_map() const8099 diff_maps::get_fn_parm_diff_map() const
8100 {return priv_->fn_parm_diff_map_;}
8101
8102 /// Getter of the map that contains function parameter diffs.
8103 ///
8104 /// @return the map that contains function parameter diffs.
8105 string_diff_ptr_map&
get_fn_parm_diff_map()8106 diff_maps::get_fn_parm_diff_map()
8107 {return priv_->fn_parm_diff_map_;}
8108
8109 /// Getter of the map that contains function type diffs.
8110 ///
8111 /// @return the map that contains function type diffs.
8112 const string_diff_ptr_map&
get_function_type_diff_map() const8113 diff_maps::get_function_type_diff_map() const
8114 {return priv_->function_type_diff_map_;}
8115
8116 /// Getter of the map that contains function type diffs.
8117 ///
8118 /// @return the map that contains function type diffs.
8119 string_diff_ptr_map&
get_function_type_diff_map()8120 diff_maps::get_function_type_diff_map()
8121 {return priv_->function_type_diff_map_;}
8122
8123 /// Getter of the map that contains function decl diffs.
8124 ///
8125 /// @return the map that contains function decl diffs.
8126 const string_diff_ptr_map&
get_function_decl_diff_map() const8127 diff_maps::get_function_decl_diff_map() const
8128 {return priv_->function_decl_diff_map_;}
8129
8130 /// Getter of the map that contains function decl diffs.
8131 ///
8132 /// @return the map that contains function decl diffs.
8133 string_diff_ptr_map&
get_function_decl_diff_map()8134 diff_maps::get_function_decl_diff_map()
8135 {return priv_->function_decl_diff_map_;}
8136
8137 /// Getter of the map that contains var decl diffs.
8138 ///
8139 /// @return the map that contains var decl diffs.
8140 const string_diff_ptr_map&
get_var_decl_diff_map() const8141 diff_maps::get_var_decl_diff_map() const
8142 {return priv_->var_decl_diff_map_;}
8143
8144 /// Getter of the map that contains var decl diffs.
8145 ///
8146 /// @return the map that contains var decl diffs.
8147 string_diff_ptr_map&
get_var_decl_diff_map()8148 diff_maps::get_var_decl_diff_map()
8149 {return priv_->var_decl_diff_map_;}
8150
8151 /// Getter of the map that contains distinct diffs.
8152 ///
8153 /// @return the map that contains distinct diffs.
8154 const string_diff_ptr_map&
get_distinct_diff_map() const8155 diff_maps::get_distinct_diff_map() const
8156 {return priv_->distinct_diff_map_;}
8157
8158 /// Getter of the map that contains distinct diffs.
8159 ///
8160 /// @return the map that contains distinct diffs.
8161 string_diff_ptr_map&
get_distinct_diff_map()8162 diff_maps::get_distinct_diff_map()
8163 {return priv_->distinct_diff_map_;}
8164
8165 /// Insert a new diff node into the current instance of @ref diff_maps.
8166 ///
8167 /// @param dif the new diff node to insert into the @ref diff_maps.
8168 ///
8169 /// @param impacted_iface the interface (global function or variable)
8170 /// currently being analysed that led to analysing the diff node @p
8171 /// dif. In other words, this is the interface impacted by the diff
8172 /// node @p dif. Note that this can be nil in cases where we are
8173 /// directly analysing changes to a type that is not reachable from
8174 /// any global function or variable.
8175 ///
8176 /// @return true iff the diff node could be added to the current
8177 /// instance of @ref diff_maps.
8178 bool
insert_diff_node(const diff * dif,const type_or_decl_base_sptr & impacted_iface)8179 diff_maps::insert_diff_node(const diff *dif,
8180 const type_or_decl_base_sptr& impacted_iface)
8181 {
8182 string n = get_pretty_representation(dif->first_subject(),
8183 /*internal=*/true);
8184 if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8185 get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8186 else if (const enum_diff *d = is_enum_diff(dif))
8187 get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8188 else if (const class_diff *d = is_class_diff(dif))
8189 get_class_diff_map()[n] = const_cast<class_diff*>(d);
8190 else if (const union_diff *d = is_union_diff(dif))
8191 get_union_diff_map()[n] = const_cast<union_diff*>(d);
8192 else if (const typedef_diff *d = is_typedef_diff(dif))
8193 get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8194 else if (const subrange_diff *d = is_subrange_diff(dif))
8195 get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8196 else if (const array_diff *d = is_array_diff(dif))
8197 get_array_diff_map()[n] = const_cast<array_diff*>(d);
8198 else if (const reference_diff *d = is_reference_diff(dif))
8199 get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8200 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8201 get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8202 else if (const function_type_diff *d = is_function_type_diff(dif))
8203 get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8204 else if (const var_diff *d = is_var_diff(dif))
8205 get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8206 else if (const function_decl_diff *d = is_function_decl_diff(dif))
8207 get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8208 else if (const distinct_diff *d = is_distinct_diff(dif))
8209 get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8210 else if (is_base_diff(dif))
8211 // we silently drop this case.
8212 return true;
8213 else
8214 ABG_ASSERT_NOT_REACHED;
8215
8216 // Update the map that associates this diff node to the set of
8217 // interfaces it impacts.
8218
8219 if (impacted_iface)
8220 {
8221 diff_artifact_set_map_type::iterator i =
8222 priv_->impacted_artifacts_map_.find(dif);
8223
8224 if (i == priv_->impacted_artifacts_map_.end())
8225 {
8226 artifact_sptr_set_type set;
8227 set.insert(impacted_iface);
8228 priv_->impacted_artifacts_map_[dif] = set;
8229 }
8230 else
8231 i->second.insert(impacted_iface);
8232 }
8233
8234 return true;
8235 }
8236
8237 /// Lookup the interfaces that are impacted by a given leaf diff node.
8238 ///
8239 /// @param d the diff node to consider.
8240 ///
8241 /// @return the set of artifacts impacted by @p d.
8242 artifact_sptr_set_type*
lookup_impacted_interfaces(const diff * d) const8243 diff_maps::lookup_impacted_interfaces(const diff *d) const
8244 {
8245 diff_artifact_set_map_type::iterator i =
8246 priv_->impacted_artifacts_map_.find(d);
8247
8248 if (i == priv_->impacted_artifacts_map_.end())
8249 return 0;
8250
8251 return &i->second;
8252 }
8253
8254 //
8255 // </diff_maps stuff>
8256
8257 /// Constructor for the @ref diff_stat type.
8258 ///
8259 /// @param ctxt the context of the corpus diff. Note that this
8260 /// context object must stay alive at least during the life time of
8261 /// the current instance of @ref corpus_diff::diff_stats. Otherwise
8262 /// memory corruption issues occur.
diff_stats(diff_context_sptr ctxt)8263 corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8264 : priv_(new priv(ctxt))
8265 {}
8266
8267 /// Getter for the number of functions removed.
8268 ///
8269 /// @return the number of functions removed.
8270 size_t
num_func_removed() const8271 corpus_diff::diff_stats::num_func_removed() const
8272 {return priv_->num_func_removed;}
8273
8274 /// Setter for the number of functions removed.
8275 ///
8276 /// @param n the new number of functions removed.
8277 void
num_func_removed(size_t n)8278 corpus_diff::diff_stats::num_func_removed(size_t n)
8279 {priv_->num_func_removed = n;}
8280
8281 /// Getter for the number of removed functions that have been filtered
8282 /// out.
8283 ///
8284 /// @return the number of removed functions that have been filtered
8285 /// out.
8286 size_t
num_removed_func_filtered_out() const8287 corpus_diff::diff_stats::num_removed_func_filtered_out() const
8288 {
8289 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8290 return num_func_removed();
8291 return priv_->num_removed_func_filtered_out;
8292 }
8293
8294 /// Setter for the number of removed functions that have been filtered
8295 /// out.
8296 ///
8297 /// @param t the new value.
8298 void
num_removed_func_filtered_out(size_t t)8299 corpus_diff::diff_stats::num_removed_func_filtered_out(size_t t)
8300 {priv_->num_removed_func_filtered_out = t;}
8301
8302 /// Getter for the net number of function removed.
8303 ///
8304 /// This is the difference between the number of functions removed and
8305 /// the number of functons removed that have been filtered out.
8306 ///
8307 /// @return the net number of function removed.
8308 size_t
net_num_func_removed() const8309 corpus_diff::diff_stats::net_num_func_removed() const
8310 {
8311 ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8312 return num_func_removed() - num_removed_func_filtered_out();
8313 }
8314
8315 /// Getter for the number of functions added.
8316 ///
8317 /// @return the number of functions added.
8318 size_t
num_func_added() const8319 corpus_diff::diff_stats::num_func_added() const
8320 {return priv_->num_func_added;}
8321
8322 /// Setter for the number of functions added.
8323 ///
8324 /// @param n the new number of functions added.
8325 void
num_func_added(size_t n)8326 corpus_diff::diff_stats::num_func_added(size_t n)
8327 {priv_->num_func_added = n;}
8328
8329 /// Getter for the number of added function that have been filtered out.
8330 ///
8331 /// @return the number of added function that have been filtered out.
8332 size_t
num_added_func_filtered_out() const8333 corpus_diff::diff_stats::num_added_func_filtered_out() const
8334 {
8335 if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8336 return num_func_added();
8337 return priv_->num_added_func_filtered_out;
8338 }
8339
8340 /// Setter for the number of added function that have been filtered
8341 /// out.
8342 ///
8343 /// @param n the new value.
8344 void
num_added_func_filtered_out(size_t n)8345 corpus_diff::diff_stats::num_added_func_filtered_out(size_t n)
8346 {priv_->num_added_func_filtered_out = n;}
8347
8348 /// Getter for the net number of added functions.
8349 ///
8350 /// The net number of added functions is the difference between the
8351 /// number of added functions and the number of added functions that
8352 /// have been filtered out.
8353 ///
8354 /// @return the net number of added functions.
8355 size_t
net_num_func_added() const8356 corpus_diff::diff_stats::net_num_func_added() const
8357 {
8358 ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8359 return num_func_added() - num_added_func_filtered_out();
8360 }
8361
8362 /// Getter for the number of functions that have a change in one of
8363 /// their sub-types.
8364 ///
8365 /// @return the number of functions that have a change in one of their
8366 /// sub-types.
8367 size_t
num_func_changed() const8368 corpus_diff::diff_stats::num_func_changed() const
8369 {return priv_->num_func_changed;}
8370
8371 /// Setter for the number of functions that have a change in one of
8372 /// their sub-types.
8373 ///
8374 /// @@param n the new number of functions that have a change in one of
8375 /// their sub-types.
8376 void
num_func_changed(size_t n)8377 corpus_diff::diff_stats::num_func_changed(size_t n)
8378 {priv_->num_func_changed = n;}
8379
8380 /// Getter for the number of functions that have a change in one of
8381 /// their sub-types, and that have been filtered out.
8382 ///
8383 /// @return the number of functions that have a change in one of their
8384 /// sub-types, and that have been filtered out.
8385 size_t
num_changed_func_filtered_out() const8386 corpus_diff::diff_stats::num_changed_func_filtered_out() const
8387 {return priv_->num_changed_func_filtered_out;}
8388
8389 /// Setter for the number of functions that have a change in one of
8390 /// their sub-types, and that have been filtered out.
8391 ///
8392 /// @param n the new number of functions that have a change in one of their
8393 /// sub-types, and that have been filtered out.
8394 void
num_changed_func_filtered_out(size_t n)8395 corpus_diff::diff_stats::num_changed_func_filtered_out(size_t n)
8396 {priv_->num_changed_func_filtered_out = n;}
8397
8398 /// Getter for the number of functions that carry virtual member
8399 /// offset changes.
8400 ///
8401 /// @return the number of functions that carry virtual member changes.
8402 size_t
num_func_with_virtual_offset_changes() const8403 corpus_diff::diff_stats::num_func_with_virtual_offset_changes() const
8404 {return priv_->num_func_with_virt_offset_changes;}
8405
8406 /// Setter for the number of functions that carry virtual member
8407 /// offset changes.
8408 ///
8409 /// @param n the new number of functions that carry virtual member
8410 /// offset. changes.
8411 void
num_func_with_virtual_offset_changes(size_t n)8412 corpus_diff::diff_stats::num_func_with_virtual_offset_changes(size_t n)
8413 {priv_->num_func_with_virt_offset_changes = n;}
8414
8415 /// Getter for the number of functions that have a change in their
8416 /// sub-types, minus the number of these functions that got filtered
8417 /// out from the diff.
8418 ///
8419 /// @return for the the number of functions that have a change in
8420 /// their sub-types, minus the number of these functions that got
8421 /// filtered out from the diff.
8422 size_t
net_num_func_changed() const8423 corpus_diff::diff_stats::net_num_func_changed() const
8424 {return num_func_changed() - num_changed_func_filtered_out();}
8425
8426 /// Getter for the number of variables removed.
8427 ///
8428 /// @return the number of variables removed.
8429 size_t
num_vars_removed() const8430 corpus_diff::diff_stats::num_vars_removed() const
8431 {return priv_->num_vars_removed;}
8432
8433 /// Setter for the number of variables removed.
8434 ///
8435 /// @param n the new number of variables removed.
8436 void
num_vars_removed(size_t n)8437 corpus_diff::diff_stats::num_vars_removed(size_t n)
8438 {priv_->num_vars_removed = n;}
8439
8440 /// Getter for the number removed variables that have been filtered
8441 /// out.
8442 ///
8443 /// @return the number removed variables that have been filtered out.
8444 size_t
num_removed_vars_filtered_out() const8445 corpus_diff::diff_stats::num_removed_vars_filtered_out() const
8446 {
8447 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
8448 return num_vars_removed();
8449 return priv_->num_removed_vars_filtered_out;
8450 }
8451
8452 /// Setter for the number of removed variables that have been filtered
8453 /// out.
8454 ///
8455 /// @param n the new value.
8456 void
num_removed_vars_filtered_out(size_t n) const8457 corpus_diff::diff_stats::num_removed_vars_filtered_out(size_t n) const
8458 {priv_->num_removed_vars_filtered_out = n;}
8459
8460 /// Getter for the net number of removed variables.
8461 ///
8462 /// The net number of removed variables is the difference between the
8463 /// number of removed variables and the number of removed variables
8464 /// that have been filtered out.
8465 ///
8466 /// @return the net number of removed variables.
8467 size_t
net_num_vars_removed() const8468 corpus_diff::diff_stats::net_num_vars_removed() const
8469 {
8470 ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
8471 return num_vars_removed() - num_removed_vars_filtered_out();
8472 }
8473
8474 /// Getter for the number of variables added.
8475 ///
8476 /// @return the number of variables added.
8477 size_t
num_vars_added() const8478 corpus_diff::diff_stats::num_vars_added() const
8479 {return priv_->num_vars_added;}
8480
8481 /// Setter for the number of variables added.
8482 ///
8483 /// @param n the new number of variables added.
8484 void
num_vars_added(size_t n)8485 corpus_diff::diff_stats::num_vars_added(size_t n)
8486 {priv_->num_vars_added = n;}
8487
8488 /// Getter for the number of added variables that have been filtered
8489 /// out.
8490 ///
8491 /// @return the number of added variables that have been filtered out.
8492 size_t
num_added_vars_filtered_out() const8493 corpus_diff::diff_stats::num_added_vars_filtered_out() const
8494 {
8495 if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8496 return num_vars_added();
8497 return priv_->num_added_vars_filtered_out;
8498 }
8499
8500 /// Setter for the number of added variables that have been filtered
8501 /// out.
8502 ///
8503 /// @param n the new value.
8504 void
num_added_vars_filtered_out(size_t n)8505 corpus_diff::diff_stats::num_added_vars_filtered_out(size_t n)
8506 {priv_->num_added_vars_filtered_out = n;}
8507
8508 /// Getter for the net number of added variables.
8509 ///
8510 /// The net number of added variables is the difference between the
8511 /// number of added variables and the number of added variables that
8512 /// have been filetered out.
8513 ///
8514 /// @return the net number of added variables.
8515 size_t
net_num_vars_added() const8516 corpus_diff::diff_stats::net_num_vars_added() const
8517 {
8518 ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8519 return num_vars_added() - num_added_vars_filtered_out();
8520 }
8521
8522 /// Getter for the number of variables that have a change in one of
8523 /// their sub-types.
8524 ///
8525 /// @return the number of variables that have a change in one of their
8526 /// sub-types.
8527 size_t
num_vars_changed() const8528 corpus_diff::diff_stats::num_vars_changed() const
8529 {return priv_->num_vars_changed;}
8530
8531 /// Setter for the number of variables that have a change in one of
8532 /// their sub-types.
8533 ///
8534 /// @param n the new number of variables that have a change in one of
8535 /// their sub-types.
8536 void
num_vars_changed(size_t n)8537 corpus_diff::diff_stats::num_vars_changed(size_t n)
8538 {priv_->num_vars_changed = n;}
8539
8540 /// Getter for the number of variables that have a change in one of
8541 /// their sub-types, and that have been filtered out.
8542 ///
8543 /// @return the number of functions that have a change in one of their
8544 /// sub-types, and that have been filtered out.
8545 size_t
num_changed_vars_filtered_out() const8546 corpus_diff::diff_stats::num_changed_vars_filtered_out() const
8547 {return priv_->num_changed_vars_filtered_out;}
8548
8549 /// Setter for the number of variables that have a change in one of
8550 /// their sub-types, and that have been filtered out.
8551 ///
8552 /// @param n the new number of variables that have a change in one of their
8553 /// sub-types, and that have been filtered out.
8554 void
num_changed_vars_filtered_out(size_t n)8555 corpus_diff::diff_stats::num_changed_vars_filtered_out(size_t n)
8556 {priv_->num_changed_vars_filtered_out = n;}
8557
8558 /// Getter for the number of variables that have a change in their
8559 /// sub-types, minus the number of these variables that got filtered
8560 /// out from the diff.
8561 ///
8562 /// @return for the the number of variables that have a change in
8563 /// their sub-types, minus the number of these variables that got
8564 /// filtered out from the diff.
8565 size_t
net_num_vars_changed() const8566 corpus_diff::diff_stats::net_num_vars_changed() const
8567 {return num_vars_changed() - num_changed_vars_filtered_out();}
8568
8569 /// Getter for the number of function symbols (not referenced by any
8570 /// debug info) that got removed.
8571 ///
8572 /// @return the number of function symbols (not referenced by any
8573 /// debug info) that got removed.
8574 size_t
num_func_syms_removed() const8575 corpus_diff::diff_stats::num_func_syms_removed() const
8576 {return priv_->num_func_syms_removed;}
8577
8578 /// Setter for the number of function symbols (not referenced by any
8579 /// debug info) that got removed.
8580 ///
8581 /// @param n the number of function symbols (not referenced by any
8582 /// debug info) that got removed.
8583 void
num_func_syms_removed(size_t n)8584 corpus_diff::diff_stats::num_func_syms_removed(size_t n)
8585 {priv_->num_func_syms_removed = n;}
8586
8587 /// Getter for the number of removed function symbols, not referenced
8588 /// by debug info, that have been filtered out.
8589 ///
8590 /// @return the number of removed function symbols, not referenced by
8591 /// debug info, that have been filtered out.
8592 size_t
num_removed_func_syms_filtered_out() const8593 corpus_diff::diff_stats::num_removed_func_syms_filtered_out() const
8594 {
8595 if (priv_->ctxt()
8596 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8597 return num_func_syms_removed();
8598 return priv_->num_removed_func_syms_filtered_out;
8599 }
8600
8601 /// Setter for the number of removed function symbols, not referenced
8602 /// by debug info, that have been filtered out.
8603 ///
8604 /// @param n the new the number of removed function symbols, not
8605 /// referenced by debug info, that have been filtered out.
8606 void
num_removed_func_syms_filtered_out(size_t n)8607 corpus_diff::diff_stats::num_removed_func_syms_filtered_out(size_t n)
8608 {priv_->num_removed_func_syms_filtered_out = n;}
8609
8610 /// Getter of the net number of removed function symbols that are not
8611 /// referenced by any debug info.
8612 ///
8613 /// This is the difference between the total number of removed
8614 /// function symbols and the number of removed function symbols that
8615 /// have been filteted out. Both numbers are for symbols not
8616 /// referenced by debug info.
8617 ///
8618 /// return the net number of removed function symbols that are not
8619 /// referenced by any debug info.
8620 size_t
net_num_removed_func_syms() const8621 corpus_diff::diff_stats::net_num_removed_func_syms() const
8622 {
8623 ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8624 return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8625 }
8626
8627 /// Getter for the number of function symbols (not referenced by any
8628 /// debug info) that got added.
8629 ///
8630 /// @return the number of function symbols (not referenced by any
8631 /// debug info) that got added.
8632 size_t
num_func_syms_added() const8633 corpus_diff::diff_stats::num_func_syms_added() const
8634 {return priv_->num_func_syms_added;}
8635
8636 /// Setter for the number of function symbols (not referenced by any
8637 /// debug info) that got added.
8638 ///
8639 /// @param n the new number of function symbols (not referenced by any
8640 /// debug info) that got added.
8641 void
num_func_syms_added(size_t n)8642 corpus_diff::diff_stats::num_func_syms_added(size_t n)
8643 {priv_->num_func_syms_added = n;}
8644
8645 /// Getter for the number of added function symbols, not referenced by
8646 /// any debug info, that have been filtered out.
8647 ///
8648 /// @return the number of added function symbols, not referenced by
8649 /// any debug info, that have been filtered out.
8650 size_t
num_added_func_syms_filtered_out() const8651 corpus_diff::diff_stats::num_added_func_syms_filtered_out() const
8652 {
8653 if (priv_->ctxt()
8654 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8655 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8656 return num_func_syms_added();
8657 return priv_->num_added_func_syms_filtered_out;
8658 }
8659
8660 /// Setter for the number of added function symbols, not referenced by
8661 /// any debug info, that have been filtered out.
8662 ///
8663 /// @param n the new number of added function symbols, not referenced
8664 /// by any debug info, that have been filtered out.
8665 void
num_added_func_syms_filtered_out(size_t n)8666 corpus_diff::diff_stats::num_added_func_syms_filtered_out(size_t n)
8667 {priv_->num_added_func_syms_filtered_out = n;}
8668
8669 /// Getter of the net number of added function symbols that are not
8670 /// referenced by any debug info.
8671 ///
8672 /// This is the difference between the total number of added
8673 /// function symbols and the number of added function symbols that
8674 /// have been filteted out. Both numbers are for symbols not
8675 /// referenced by debug info.
8676 ///
8677 /// return the net number of added function symbols that are not
8678 /// referenced by any debug info.
8679 size_t
net_num_added_func_syms() const8680 corpus_diff::diff_stats::net_num_added_func_syms() const
8681 {
8682 ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8683 return num_func_syms_added()- num_added_func_syms_filtered_out();
8684 }
8685
8686 /// Getter for the number of variable symbols (not referenced by any
8687 /// debug info) that got removed.
8688 ///
8689 /// @return the number of variable symbols (not referenced by any
8690 /// debug info) that got removed.
8691 size_t
num_var_syms_removed() const8692 corpus_diff::diff_stats::num_var_syms_removed() const
8693 {return priv_->num_var_syms_removed;}
8694
8695 /// Setter for the number of variable symbols (not referenced by any
8696 /// debug info) that got removed.
8697 ///
8698 /// @param n the number of variable symbols (not referenced by any
8699 /// debug info) that got removed.
8700 void
num_var_syms_removed(size_t n)8701 corpus_diff::diff_stats::num_var_syms_removed(size_t n)
8702 {priv_->num_var_syms_removed = n;}
8703
8704 /// Getter for the number of removed variable symbols, not referenced
8705 /// by any debug info, that have been filtered out.
8706 ///
8707 /// @return the number of removed variable symbols, not referenced
8708 /// by any debug info, that have been filtered out.
8709 size_t
num_removed_var_syms_filtered_out() const8710 corpus_diff::diff_stats::num_removed_var_syms_filtered_out() const
8711 {
8712 if (priv_->ctxt()
8713 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8714 return num_var_syms_removed();
8715 return priv_->num_removed_var_syms_filtered_out;
8716 }
8717
8718 /// Setter for the number of removed variable symbols, not referenced
8719 /// by any debug info, that have been filtered out.
8720 ///
8721 /// @param n the number of removed variable symbols, not referenced by
8722 /// any debug info, that have been filtered out.
8723 void
num_removed_var_syms_filtered_out(size_t n)8724 corpus_diff::diff_stats::num_removed_var_syms_filtered_out(size_t n)
8725 {priv_->num_removed_var_syms_filtered_out = n;}
8726
8727 /// Getter of the net number of removed variable symbols that are not
8728 /// referenced by any debug info.
8729 ///
8730 /// This is the difference between the total number of removed
8731 /// variable symbols and the number of removed variable symbols that
8732 /// have been filteted out. Both numbers are for symbols not
8733 /// referenced by debug info.
8734 ///
8735 /// return the net number of removed variable symbols that are not
8736 /// referenced by any debug info.
8737 size_t
net_num_removed_var_syms() const8738 corpus_diff::diff_stats::net_num_removed_var_syms() const
8739 {
8740 ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
8741 return num_var_syms_removed() - num_removed_var_syms_filtered_out();
8742 }
8743
8744 /// Getter for the number of variable symbols (not referenced by any
8745 /// debug info) that got added.
8746 ///
8747 /// @return the number of variable symbols (not referenced by any
8748 /// debug info) that got added.
8749 size_t
num_var_syms_added() const8750 corpus_diff::diff_stats::num_var_syms_added() const
8751 {return priv_->num_var_syms_added;}
8752
8753 /// Setter for the number of variable symbols (not referenced by any
8754 /// debug info) that got added.
8755 ///
8756 /// @param n the new number of variable symbols (not referenced by any
8757 /// debug info) that got added.
8758 void
num_var_syms_added(size_t n)8759 corpus_diff::diff_stats::num_var_syms_added(size_t n)
8760 {priv_->num_var_syms_added = n;}
8761
8762 /// Getter for the number of added variable symbols, not referenced by
8763 /// any debug info, that have been filtered out.
8764 ///
8765 /// @return the number of added variable symbols, not referenced by
8766 /// any debug info, that have been filtered out.
8767 size_t
num_added_var_syms_filtered_out() const8768 corpus_diff::diff_stats::num_added_var_syms_filtered_out() const
8769 {
8770 if (priv_->ctxt()
8771 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8772 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8773 return num_var_syms_added();
8774 return priv_->num_added_var_syms_filtered_out;
8775 }
8776
8777 /// Setter for the number of added variable symbols, not referenced by
8778 /// any debug info, that have been filtered out.
8779 ///
8780 /// @param n the new number of added variable symbols, not referenced
8781 /// by any debug info, that have been filtered out.
8782 void
num_added_var_syms_filtered_out(size_t n)8783 corpus_diff::diff_stats::num_added_var_syms_filtered_out(size_t n)
8784 {priv_->num_added_var_syms_filtered_out = n;}
8785
8786 /// Getter of the net number of added variable symbols that are not
8787 /// referenced by any debug info.
8788 ///
8789 /// This is the difference between the total number of added
8790 /// variable symbols and the number of added variable symbols that
8791 /// have been filteted out. Both numbers are for symbols not
8792 /// referenced by debug info.
8793 ///
8794 /// return the net number of added variable symbols that are not
8795 /// referenced by any debug info.
8796 size_t
net_num_added_var_syms() const8797 corpus_diff::diff_stats::net_num_added_var_syms() const
8798 {
8799 ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
8800 return num_var_syms_added() - num_added_var_syms_filtered_out();
8801 }
8802
8803 /// Getter of the number of leaf type change diff nodes.
8804 ///
8805 /// @return the number of leaf type change diff nodes.
8806 size_t
num_leaf_changes() const8807 corpus_diff::diff_stats::num_leaf_changes() const
8808 {return priv_->num_leaf_changes;}
8809
8810 /// Setter of the number of leaf type change diff nodes.
8811 ///
8812 /// @param n the new number of leaf type change diff nodes.
8813 void
num_leaf_changes(size_t n)8814 corpus_diff::diff_stats::num_leaf_changes(size_t n)
8815 {priv_->num_leaf_changes = n;}
8816
8817 /// Getter of the number of leaf type change diff nodes that have been
8818 /// filtered out.
8819 ///
8820 /// @return the number of leaf type change diff nodes that have been
8821 size_t
num_leaf_changes_filtered_out() const8822 corpus_diff::diff_stats::num_leaf_changes_filtered_out() const
8823 {return priv_->num_leaf_changes_filtered_out;}
8824
8825 /// Setter of the number of leaf type change diff nodes that have been
8826 /// filtered out.
8827 ///
8828 /// @param n the new number of leaf type change diff nodes that have
8829 /// been filtered out.
8830 void
num_leaf_changes_filtered_out(size_t n)8831 corpus_diff::diff_stats::num_leaf_changes_filtered_out(size_t n)
8832 {priv_->num_leaf_changes_filtered_out = n;}
8833
8834 /// Getter of the net number of leaf change diff nodes.
8835 ///
8836 /// This is the difference between the total number of leaf change
8837 /// diff nodes, and the number of the leaf change diff nodes that have
8838 /// been filtered out.
8839 ///
8840 /// A leaf change is either a type change, a function change or a
8841 /// variable change.
8842 size_t
net_num_leaf_changes() const8843 corpus_diff::diff_stats::net_num_leaf_changes() const
8844 {
8845 ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
8846 return num_leaf_changes() - num_leaf_changes_filtered_out();
8847 }
8848
8849 /// Getter for the number of leaf type change diff nodes.
8850 ///
8851 /// @return the number of leaf type changes diff nodes.
8852 size_t
num_leaf_type_changes() const8853 corpus_diff::diff_stats::num_leaf_type_changes() const
8854 {return priv_->num_leaf_type_changes;}
8855
8856 /// Setter for the number of leaf type change diff nodes.
8857 ///
8858 /// @param n the new number of leaf type change diff nodes.
8859 void
num_leaf_type_changes(size_t n)8860 corpus_diff::diff_stats::num_leaf_type_changes(size_t n)
8861 {priv_->num_leaf_type_changes = n;}
8862
8863 /// Getter for the number of filtered out leaf type change diff nodes.
8864 ///
8865 /// @return the number of filtered out leaf type change diff nodes.
8866 size_t
num_leaf_type_changes_filtered_out() const8867 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out() const
8868 {return priv_->num_leaf_type_changes_filtered_out;}
8869
8870 /// Setter for the number of filtered out leaf type change diff nodes.
8871 /// @param n the new number of filtered out leaf type change diff nodes.
8872 void
num_leaf_type_changes_filtered_out(size_t n)8873 corpus_diff::diff_stats::num_leaf_type_changes_filtered_out(size_t n)
8874 {priv_->num_leaf_type_changes_filtered_out = n;}
8875
8876 /// Getter for the net number of leaf type change diff nodes.
8877 ///
8878 /// This is the difference between the number of leaf type changes and
8879 /// the number of filtered out leaf type changes.
8880 ///
8881 /// @return the net number of leaf type change diff nodes.
8882 size_t
net_num_leaf_type_changes() const8883 corpus_diff::diff_stats::net_num_leaf_type_changes() const
8884 {return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
8885
8886 /// Getter for the number of leaf function change diff nodes.
8887 ///
8888 /// @return the number of leaf function change diff nodes.
8889 size_t
num_leaf_func_changes() const8890 corpus_diff::diff_stats::num_leaf_func_changes() const
8891 {return priv_->num_leaf_func_changes;}
8892
8893 /// Setter for the number of leaf function change diff nodes.
8894 ///
8895 /// @param n the new number of leaf function change diff nodes.
8896 void
num_leaf_func_changes(size_t n)8897 corpus_diff::diff_stats::num_leaf_func_changes(size_t n)
8898 {priv_->num_leaf_func_changes = n;}
8899
8900 /// Getter for the number of leaf function change diff nodes that were
8901 /// filtered out.
8902 ///
8903 /// @return the number of leaf function change diff nodes that were
8904 /// filtered out.
8905 size_t
num_leaf_func_changes_filtered_out() const8906 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out() const
8907 {return priv_->num_leaf_func_changes_filtered_out;}
8908
8909 /// Setter for the number of leaf function change diff nodes that were
8910 /// filtered out.
8911 ///
8912 /// @param n the new number of leaf function change diff nodes that
8913 /// were filtered out.
8914 void
num_leaf_func_changes_filtered_out(size_t n)8915 corpus_diff::diff_stats::num_leaf_func_changes_filtered_out(size_t n)
8916 {priv_->num_leaf_func_changes_filtered_out = n;}
8917
8918 /// Getter for the net number of leaf function change diff nodes.
8919 ///
8920 /// This is the difference between the number of leaf function change
8921 /// diff nodes and the number of filtered out leaf function change
8922 /// diff nodes.
8923 ///
8924 /// @return the net number of leaf function change diff nodes.
8925 size_t
net_num_leaf_func_changes() const8926 corpus_diff::diff_stats::net_num_leaf_func_changes() const
8927 {return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
8928
8929 /// Getter for the number of leaf variable change diff nodes.
8930 ///
8931 /// @return the number of leaf variable change diff nodes.
8932 size_t
num_leaf_var_changes() const8933 corpus_diff::diff_stats::num_leaf_var_changes() const
8934 {return priv_->num_leaf_var_changes;}
8935
8936 /// Setter for the number of leaf variable change diff nodes.
8937 ///
8938 /// @param n the number of leaf variable change diff nodes.
8939 void
num_leaf_var_changes(size_t n)8940 corpus_diff::diff_stats::num_leaf_var_changes(size_t n)
8941 {priv_->num_leaf_var_changes = n;}
8942
8943 /// Getter of the number of added types that are unreachable from the
8944 /// public interface of the ABI corpus.
8945 ///
8946 /// Public interface means the set of defined and publicly exported
8947 /// functions and variables of the ABI corpus.
8948 ///
8949 /// @return the number of added types that are unreachable from the
8950 /// public interface of the ABI corpus.
8951 size_t
num_added_unreachable_types() const8952 corpus_diff::diff_stats::num_added_unreachable_types() const
8953 {return priv_->num_added_unreachable_types;}
8954
8955 /// Setter of the number of added types that are unreachable from the
8956 /// public interface (global functions or variables) of the ABI
8957 /// corpus.
8958 ///
8959 /// Public interface means the set of defined and publicly exported
8960 /// functions and variables of the ABI corpus.
8961 ///
8962 /// @param n the new number of added types that are unreachable from
8963 /// the public interface of the ABI corpus.
8964 void
num_added_unreachable_types(size_t n)8965 corpus_diff::diff_stats::num_added_unreachable_types(size_t n)
8966 {priv_->num_added_unreachable_types = n;}
8967
8968 /// Getter of the number of added types that are unreachable from
8969 /// public interfaces and that are filtered out by suppression
8970 /// specifications.
8971 ///
8972 /// @return the number of added types that are unreachable from public
8973 /// interfaces and that are filtered out by suppression
8974 /// specifications.
8975 size_t
num_added_unreachable_types_filtered_out() const8976 corpus_diff::diff_stats::num_added_unreachable_types_filtered_out() const
8977 {return priv_->num_added_unreachable_types_filtered_out;}
8978
8979 /// Setter of the number of added types that are unreachable from
8980 /// public interfaces and that are filtered out by suppression
8981 /// specifications.
8982 ///
8983 /// @param n the new number of added types that are unreachable from
8984 /// public interfaces and that are filtered out by suppression
8985 /// specifications.
8986 void
num_added_unreachable_types_filtered_out(size_t n)8987 corpus_diff::diff_stats::num_added_unreachable_types_filtered_out(size_t n)
8988 {priv_->num_added_unreachable_types_filtered_out = n;}
8989
8990 /// Getter of the number of added types that are unreachable from
8991 /// public interfaces and that are *NOT* filtered out by suppression
8992 /// specifications.
8993 ///
8994 /// @return the number of added types that are unreachable from public
8995 /// interfaces and that are *NOT* filtered out by suppression
8996 /// specifications.
8997 size_t
net_num_added_unreachable_types() const8998 corpus_diff::diff_stats::net_num_added_unreachable_types() const
8999 {
9000 ABG_ASSERT(num_added_unreachable_types()
9001 >=
9002 num_added_unreachable_types_filtered_out());
9003
9004 return (num_added_unreachable_types()
9005 -
9006 num_added_unreachable_types_filtered_out());
9007 }
9008
9009 /// Getter of the number of removed types that are unreachable from
9010 /// the public interface of the ABI corpus.
9011 ///
9012 /// Public interface means the set of defined and publicly exported
9013 /// functions and variables of the ABI corpus.
9014 ///
9015 /// @return the number of removed types that are unreachable from
9016 /// the public interface of the ABI corpus.
9017 size_t
num_removed_unreachable_types() const9018 corpus_diff::diff_stats::num_removed_unreachable_types() const
9019 {return priv_->num_removed_unreachable_types;}
9020
9021 /// Setter of the number of removed types that are unreachable from
9022 /// the public interface of the ABI corpus.
9023 ///
9024 /// Public interface means the set of defined and publicly exported
9025 /// functions and variables of the ABI corpus.
9026 ///
9027 ///@param n the new number of removed types that are unreachable from
9028 /// the public interface of the ABI corpus.
9029 void
num_removed_unreachable_types(size_t n)9030 corpus_diff::diff_stats::num_removed_unreachable_types(size_t n)
9031 {priv_->num_removed_unreachable_types = n;}
9032
9033 /// Getter of the number of removed types that are not reachable from
9034 /// public interfaces and that have been filtered out by suppression
9035 /// specifications.
9036 ///
9037 /// @return the number of removed types that are not reachable from
9038 /// public interfaces and that have been filtered out by suppression
9039 /// specifications.
9040 size_t
num_removed_unreachable_types_filtered_out() const9041 corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out() const
9042 {return priv_->num_removed_unreachable_types_filtered_out;}
9043
9044 /// Setter of the number of removed types that are not reachable from
9045 /// public interfaces and that have been filtered out by suppression
9046 /// specifications.
9047 ///
9048 /// @param n the new number of removed types that are not reachable
9049 /// from public interfaces and that have been filtered out by
9050 /// suppression specifications.
9051 void
num_removed_unreachable_types_filtered_out(size_t n)9052 corpus_diff::diff_stats::num_removed_unreachable_types_filtered_out(size_t n)
9053 {priv_->num_removed_unreachable_types_filtered_out = n;}
9054
9055 /// Getter of the number of removed types that are not reachable from
9056 /// public interfaces and that have *NOT* been filtered out by
9057 /// suppression specifications.
9058 ///
9059 /// @return the number of removed types that are not reachable from
9060 /// public interfaces and that have *NOT* been filtered out by
9061 /// suppression specifications.
9062 size_t
net_num_removed_unreachable_types() const9063 corpus_diff::diff_stats::net_num_removed_unreachable_types() const
9064 {
9065 ABG_ASSERT(num_removed_unreachable_types()
9066 >=
9067 num_removed_unreachable_types_filtered_out());
9068
9069 return (num_removed_unreachable_types()
9070 -
9071 num_removed_unreachable_types_filtered_out());
9072 }
9073
9074 /// Getter of the number of changed types that are unreachable from
9075 /// the public interface of the ABI corpus.
9076 ///
9077 /// Public interface means the set of defined and publicly exported
9078 /// functions and variables of the ABI corpus.
9079 ///
9080 /// @return the number of changed types that are unreachable from the
9081 /// public interface of the ABI corpus.
9082 size_t
num_changed_unreachable_types() const9083 corpus_diff::diff_stats::num_changed_unreachable_types() const
9084 {return priv_->num_changed_unreachable_types;}
9085
9086 /// Setter of the number of changed types that are unreachable from
9087 /// the public interface of the ABI corpus.
9088 ///
9089 /// Public interface means the set of defined and publicly exported
9090 /// functions and variables of the ABI corpus.
9091 ///
9092 ///@param n the new number of changed types that are unreachable from
9093 /// the public interface of the ABI corpus.
9094 void
num_changed_unreachable_types(size_t n)9095 corpus_diff::diff_stats::num_changed_unreachable_types(size_t n)
9096 {priv_->num_changed_unreachable_types = n;}
9097
9098 /// Getter of the number of changed types that are unreachable from
9099 /// public interfaces and that have been filtered out by suppression
9100 /// specifications.
9101 ///
9102 /// @return the number of changed types that are unreachable from
9103 /// public interfaces and that have been filtered out by suppression
9104 /// specifications.
9105 size_t
num_changed_unreachable_types_filtered_out() const9106 corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out() const
9107 {return priv_->num_changed_unreachable_types_filtered_out;}
9108
9109 /// Setter of the number of changed types that are unreachable from
9110 /// public interfaces and that have been filtered out by suppression
9111 /// specifications.
9112 ///
9113 /// @param n the new number of changed types that are unreachable from
9114 /// public interfaces and that have been filtered out by suppression
9115 /// specifications.
9116 void
num_changed_unreachable_types_filtered_out(size_t n)9117 corpus_diff::diff_stats::num_changed_unreachable_types_filtered_out(size_t n)
9118 {priv_->num_changed_unreachable_types_filtered_out = n;}
9119
9120 /// Getter of the number of changed types that are unreachable from
9121 /// public interfaces and that have *NOT* been filtered out by
9122 /// suppression specifications.
9123 ///
9124 /// @return the number of changed types that are unreachable from
9125 /// public interfaces and that have *NOT* been filtered out by
9126 /// suppression specifications.
9127 size_t
net_num_changed_unreachable_types() const9128 corpus_diff::diff_stats::net_num_changed_unreachable_types() const
9129 {
9130 ABG_ASSERT(num_changed_unreachable_types()
9131 >=
9132 num_changed_unreachable_types_filtered_out());
9133
9134 return (num_changed_unreachable_types()
9135 -
9136 num_changed_unreachable_types_filtered_out());
9137 }
9138
9139 /// Getter for the number of leaf variable changes diff nodes that
9140 /// have been filtered out.
9141 ///
9142 /// @return the number of leaf variable changes diff nodes that have
9143 /// been filtered out.
9144 size_t
num_leaf_var_changes_filtered_out() const9145 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out() const
9146 {return priv_->num_leaf_var_changes_filtered_out;}
9147
9148 /// Setter for the number of leaf variable changes diff nodes that
9149 /// have been filtered out.
9150 ///
9151 /// @param n the number of leaf variable changes diff nodes that have
9152 /// been filtered out.
9153 void
num_leaf_var_changes_filtered_out(size_t n)9154 corpus_diff::diff_stats::num_leaf_var_changes_filtered_out(size_t n)
9155 {priv_->num_leaf_var_changes_filtered_out = n;}
9156
9157 /// Getter for the net number of leaf variable change diff nodes.
9158 ///
9159 /// This the difference between the number of leaf variable change
9160 /// diff nodes and the number of filtered out leaf variable change
9161 /// diff nodes.
9162 ///
9163 /// @return the net number of leaf variable change diff nodes.
9164 size_t
net_num_leaf_var_changes() const9165 corpus_diff::diff_stats::net_num_leaf_var_changes() const
9166 {return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9167
9168
9169 // <corpus_diff stuff>
9170
9171 /// Getter of the context associated with this corpus.
9172 ///
9173 /// @return a smart pointer to the context associate with the corpus.
9174 diff_context_sptr
get_context()9175 corpus_diff::priv::get_context()
9176 {return ctxt_.lock();}
9177
9178 /// Tests if the lookup tables are empty.
9179 ///
9180 /// @return true if the lookup tables are empty, false otherwise.
9181 bool
lookup_tables_empty() const9182 corpus_diff::priv::lookup_tables_empty() const
9183 {
9184 return (deleted_fns_.empty()
9185 && added_fns_.empty()
9186 && changed_fns_map_.empty()
9187 && deleted_vars_.empty()
9188 && added_vars_.empty()
9189 && changed_vars_map_.empty());
9190 }
9191
9192 /// Clear the lookup tables useful for reporting an enum_diff.
9193 void
clear_lookup_tables()9194 corpus_diff::priv::clear_lookup_tables()
9195 {
9196 deleted_fns_.clear();
9197 added_fns_.clear();
9198 changed_fns_map_.clear();
9199 deleted_vars_.clear();
9200 added_vars_.clear();
9201 changed_vars_map_.clear();
9202 }
9203
9204 /// If the lookup tables are not yet built, walk the differences and
9205 /// fill the lookup tables.
9206 void
ensure_lookup_tables_populated()9207 corpus_diff::priv::ensure_lookup_tables_populated()
9208 {
9209 if (!lookup_tables_empty())
9210 return;
9211
9212 diff_context_sptr ctxt = get_context();
9213
9214 {
9215 edit_script& e = fns_edit_script_;
9216
9217 for (vector<deletion>::const_iterator it = e.deletions().begin();
9218 it != e.deletions().end();
9219 ++it)
9220 {
9221 unsigned i = it->index();
9222 ABG_ASSERT(i < first_->get_functions().size());
9223
9224 function_decl* deleted_fn = first_->get_functions()[i];
9225 string n = get_function_id_or_pretty_representation(deleted_fn);
9226 ABG_ASSERT(!n.empty());
9227 // The below is commented out because there can be several
9228 // functions with the same ID in the corpus. So several
9229 // functions with the same ID can be deleted.
9230 // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9231 deleted_fns_[n] = deleted_fn;
9232 }
9233
9234 for (vector<insertion>::const_iterator it = e.insertions().begin();
9235 it != e.insertions().end();
9236 ++it)
9237 {
9238 for (vector<unsigned>::const_iterator iit =
9239 it->inserted_indexes().begin();
9240 iit != it->inserted_indexes().end();
9241 ++iit)
9242 {
9243 unsigned i = *iit;
9244 function_decl* added_fn = second_->get_functions()[i];
9245 string n = get_function_id_or_pretty_representation(added_fn);
9246 ABG_ASSERT(!n.empty());
9247 // The below is commented out because there can be several
9248 // functions with the same ID in the corpus. So several
9249 // functions with the same ID can be added.
9250 // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9251 string_function_ptr_map::const_iterator j =
9252 deleted_fns_.find(n);
9253 if (j != deleted_fns_.end())
9254 {
9255 function_decl_sptr f(j->second, noop_deleter());
9256 function_decl_sptr s(added_fn, noop_deleter());
9257 function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9258 if (*j->second != *added_fn)
9259 changed_fns_map_[j->first] = d;
9260 deleted_fns_.erase(j);
9261 }
9262 else
9263 added_fns_[n] = added_fn;
9264 }
9265 }
9266 sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9267
9268 // Now walk the allegedly deleted functions; check if their
9269 // underlying symbols are deleted as well; otherwise, consider
9270 // that the function in question hasn't been deleted.
9271
9272 vector<string> to_delete;
9273 for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9274 i != deleted_fns_.end();
9275 ++i)
9276 if (second_->lookup_function_symbol(*i->second->get_symbol()))
9277 to_delete.push_back(i->first);
9278
9279 for (vector<string>::const_iterator i = to_delete.begin();
9280 i != to_delete.end();
9281 ++i)
9282 deleted_fns_.erase(*i);
9283
9284 // Do something similar for added functions.
9285
9286 to_delete.clear();
9287 for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9288 i != added_fns_.end();
9289 ++i)
9290 {
9291 if (first_->lookup_function_symbol(*i->second->get_symbol()))
9292 to_delete.push_back(i->first);
9293 else if (! i->second->get_symbol()->get_version().is_empty()
9294 && i->second->get_symbol()->get_version().is_default())
9295 // We are looking for a symbol that has a default version,
9296 // and which seems to be newly added. Let's see if the same
9297 // symbol with *no* version was already present in the
9298 // former corpus. If yes, then the symbol shouldn't be
9299 // considered as 'added'.
9300 {
9301 elf_symbol::version empty_version;
9302 if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
9303 empty_version))
9304 to_delete.push_back(i->first);
9305 }
9306 }
9307
9308 for (vector<string>::const_iterator i = to_delete.begin();
9309 i != to_delete.end();
9310 ++i)
9311 added_fns_.erase(*i);
9312 }
9313
9314 {
9315 edit_script& e = vars_edit_script_;
9316
9317 for (vector<deletion>::const_iterator it = e.deletions().begin();
9318 it != e.deletions().end();
9319 ++it)
9320 {
9321 unsigned i = it->index();
9322 ABG_ASSERT(i < first_->get_variables().size());
9323
9324 var_decl* deleted_var = first_->get_variables()[i];
9325 string n = deleted_var->get_id();
9326 ABG_ASSERT(!n.empty());
9327 ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
9328 deleted_vars_[n] = deleted_var;
9329 }
9330
9331 for (vector<insertion>::const_iterator it = e.insertions().begin();
9332 it != e.insertions().end();
9333 ++it)
9334 {
9335 for (vector<unsigned>::const_iterator iit =
9336 it->inserted_indexes().begin();
9337 iit != it->inserted_indexes().end();
9338 ++iit)
9339 {
9340 unsigned i = *iit;
9341 var_decl* added_var = second_->get_variables()[i];
9342 string n = added_var->get_id();
9343 ABG_ASSERT(!n.empty());
9344 {
9345 string_var_ptr_map::const_iterator k = added_vars_.find(n);
9346 if ( k != added_vars_.end())
9347 {
9348 ABG_ASSERT(is_member_decl(k->second)
9349 && get_member_is_static(k->second));
9350 continue;
9351 }
9352 }
9353 string_var_ptr_map::const_iterator j =
9354 deleted_vars_.find(n);
9355 if (j != deleted_vars_.end())
9356 {
9357 if (*j->second != *added_var)
9358 {
9359 var_decl_sptr f(j->second, noop_deleter());
9360 var_decl_sptr s(added_var, noop_deleter());
9361 changed_vars_map_[n] = compute_diff(f, s, ctxt);
9362 }
9363 deleted_vars_.erase(j);
9364 }
9365 else
9366 added_vars_[n] = added_var;
9367 }
9368 }
9369 sort_string_var_diff_sptr_map(changed_vars_map_,
9370 sorted_changed_vars_);
9371
9372 // Now walk the allegedly deleted variables; check if their
9373 // underlying symbols are deleted as well; otherwise consider
9374 // that the variable in question hasn't been deleted.
9375
9376 vector<string> to_delete;
9377 for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
9378 i != deleted_vars_.end();
9379 ++i)
9380 if (second_->lookup_variable_symbol(*i->second->get_symbol()))
9381 to_delete.push_back(i->first);
9382
9383 for (vector<string>::const_iterator i = to_delete.begin();
9384 i != to_delete.end();
9385 ++i)
9386 deleted_vars_.erase(*i);
9387
9388 // Do something similar for added variables.
9389
9390 to_delete.clear();
9391 for (string_var_ptr_map::const_iterator i = added_vars_.begin();
9392 i != added_vars_.end();
9393 ++i)
9394 if (first_->lookup_variable_symbol(*i->second->get_symbol()))
9395 to_delete.push_back(i->first);
9396 else if (! i->second->get_symbol()->get_version().is_empty()
9397 && i->second->get_symbol()->get_version().is_default())
9398 // We are looking for a symbol that has a default version,
9399 // and which seems to be newly added. Let's see if the same
9400 // symbol with *no* version was already present in the
9401 // former corpus. If yes, then the symbol shouldn't be
9402 // considered as 'added'.
9403 {
9404 elf_symbol::version empty_version;
9405 if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
9406 empty_version))
9407 to_delete.push_back(i->first);
9408 }
9409
9410 for (vector<string>::const_iterator i = to_delete.begin();
9411 i != to_delete.end();
9412 ++i)
9413 added_vars_.erase(*i);
9414 }
9415
9416 // Massage the edit script for added/removed function symbols that
9417 // were not referenced by any debug info and turn them into maps of
9418 // {symbol_name, symbol}.
9419 {
9420 edit_script& e = unrefed_fn_syms_edit_script_;
9421 for (vector<deletion>::const_iterator it = e.deletions().begin();
9422 it != e.deletions().end();
9423 ++it)
9424 {
9425 unsigned i = it->index();
9426 ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
9427 elf_symbol_sptr deleted_sym =
9428 first_->get_unreferenced_function_symbols()[i];
9429 if (!second_->lookup_function_symbol(*deleted_sym))
9430 deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
9431 }
9432
9433 for (vector<insertion>::const_iterator it = e.insertions().begin();
9434 it != e.insertions().end();
9435 ++it)
9436 {
9437 for (vector<unsigned>::const_iterator iit =
9438 it->inserted_indexes().begin();
9439 iit != it->inserted_indexes().end();
9440 ++iit)
9441 {
9442 unsigned i = *iit;
9443 ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
9444 elf_symbol_sptr added_sym =
9445 second_->get_unreferenced_function_symbols()[i];
9446 if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
9447 == deleted_unrefed_fn_syms_.end()))
9448 {
9449 if (!first_->lookup_function_symbol(*added_sym))
9450 {
9451 bool do_add = true;
9452 if (! added_sym->get_version().is_empty()
9453 && added_sym->get_version().is_default())
9454 {
9455 // So added_seem has a default version. If
9456 // the former corpus had a symbol with the
9457 // same name as added_sym but with *no*
9458 // version, then added_sym shouldn't be
9459 // considered as a newly added symbol.
9460 elf_symbol::version empty_version;
9461 if (first_->lookup_function_symbol(added_sym->get_name(),
9462 empty_version))
9463 do_add = false;
9464 }
9465
9466 if (do_add)
9467 added_unrefed_fn_syms_[added_sym->get_id_string()] =
9468 added_sym;
9469 }
9470 }
9471 else
9472 deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
9473 }
9474 }
9475 }
9476
9477 // Massage the edit script for added/removed variable symbols that
9478 // were not referenced by any debug info and turn them into maps of
9479 // {symbol_name, symbol}.
9480 {
9481 edit_script& e = unrefed_var_syms_edit_script_;
9482 for (vector<deletion>::const_iterator it = e.deletions().begin();
9483 it != e.deletions().end();
9484 ++it)
9485 {
9486 unsigned i = it->index();
9487 ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9488 elf_symbol_sptr deleted_sym =
9489 first_->get_unreferenced_variable_symbols()[i];
9490 if (!second_->lookup_variable_symbol(*deleted_sym))
9491 deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9492 }
9493
9494 for (vector<insertion>::const_iterator it = e.insertions().begin();
9495 it != e.insertions().end();
9496 ++it)
9497 {
9498 for (vector<unsigned>::const_iterator iit =
9499 it->inserted_indexes().begin();
9500 iit != it->inserted_indexes().end();
9501 ++iit)
9502 {
9503 unsigned i = *iit;
9504 ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9505 elf_symbol_sptr added_sym =
9506 second_->get_unreferenced_variable_symbols()[i];
9507 if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9508 == deleted_unrefed_var_syms_.end())
9509 {
9510 if (!first_->lookup_variable_symbol(*added_sym))
9511 {
9512 bool do_add = true;
9513 if (! added_sym->get_version().is_empty()
9514 && added_sym->get_version().is_default())
9515 {
9516 // So added_seem has a default version. If
9517 // the former corpus had a symbol with the
9518 // same name as added_sym but with *no*
9519 // version, then added_sym shouldn't be
9520 // considered as a newly added symbol.
9521 elf_symbol::version empty_version;
9522 if (first_->lookup_variable_symbol(added_sym->get_name(),
9523 empty_version))
9524 do_add = false;
9525 }
9526
9527 if (do_add)
9528 added_unrefed_var_syms_[added_sym->get_id_string()] =
9529 added_sym;
9530 }
9531 }
9532 else
9533 deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9534 }
9535 }
9536 }
9537
9538 // Handle the unreachable_types_edit_script_
9539 {
9540 edit_script& e = unreachable_types_edit_script_;
9541
9542 // Populate the map of deleted unreachable types from the
9543 // deletions of the edit script.
9544 for (vector<deletion>::const_iterator it = e.deletions().begin();
9545 it != e.deletions().end();
9546 ++it)
9547 {
9548 unsigned i = it->index();
9549 type_base_sptr t
9550 (first_->get_types_not_reachable_from_public_interfaces()[i]);
9551
9552 if (!is_user_defined_type(t))
9553 continue;
9554
9555 string repr =
9556 abigail::ir::get_pretty_representation(t, /*internal=*/false);
9557 deleted_unreachable_types_[repr] = t;
9558 }
9559
9560 // Populate the map of added and change unreachable types from the
9561 // insertions of the edit script.
9562 for (vector<insertion>::const_iterator it = e.insertions().begin();
9563 it != e.insertions().end();
9564 ++it)
9565 {
9566 for (vector<unsigned>::const_iterator iit =
9567 it->inserted_indexes().begin();
9568 iit != it->inserted_indexes().end();
9569 ++iit)
9570 {
9571 unsigned i = *iit;
9572 type_base_sptr t
9573 (second_->get_types_not_reachable_from_public_interfaces()[i]);
9574
9575 if (!is_user_defined_type(t))
9576 continue;
9577
9578 string repr =
9579 abigail::ir::get_pretty_representation(t, /*internal=*/false);
9580
9581 // Let's see if the inserted type we are looking at was
9582 // reported as deleted as well.
9583 //
9584 // If it's been deleted and a different version of it has
9585 // now been added, it means it's been *changed*. In that
9586 // case we'll compute the diff of that change and store it
9587 // in the map of changed unreachable types.
9588 //
9589 // Otherwise, it means the type's been added so we'll add
9590 // it to the set of added unreachable types.
9591
9592 string_type_base_sptr_map::const_iterator j =
9593 deleted_unreachable_types_.find(repr);
9594 if (j != deleted_unreachable_types_.end())
9595 {
9596 // So there was another type of the same pretty
9597 // representation which was reported as deleted.
9598 // Let's see if they are different or not ...
9599 decl_base_sptr old_type = is_decl(j->second);
9600 decl_base_sptr new_type = is_decl(t);
9601 if (old_type != new_type)
9602 {
9603 // The previously added type is different from this
9604 // one that is added. That means the initial type
9605 // was changed. Let's compute its diff and store it
9606 // as a changed type.
9607 diff_sptr d = compute_diff(old_type, new_type, ctxt);
9608 ABG_ASSERT(d->has_changes());
9609 changed_unreachable_types_[repr]= d;
9610 }
9611
9612 // In any case, the type was both deleted and added,
9613 // so we cannot have it marked as being deleted. So
9614 // let's remove it from the deleted types.
9615 deleted_unreachable_types_.erase(j);
9616 }
9617 else
9618 // The type wasn't previously reported as deleted, so
9619 // it's really added.
9620 added_unreachable_types_[repr] = t;
9621 }
9622 }
9623
9624 // Handle anonymous enums that got changed. An anonymous enum is
9625 // designated by its flat textual representation. So a change to
9626 // any of its enumerators results in a different enum. That is
9627 // represented by a deletion of the previous anonymous enum, and
9628 // the addition of a new one. For the user however, it's the same
9629 // enum that changed. Let's massage this "added/removed" pattern
9630 // to show what the user expects, namely, a changed anonymous
9631 // enum.
9632 {
9633 std::set<type_base_sptr> deleted_anon_types;
9634 std::set<type_base_sptr> added_anon_types;
9635
9636 for (auto entry : deleted_unreachable_types_)
9637 {
9638 if ((is_enum_type(entry.second)
9639 && is_enum_type(entry.second)->get_is_anonymous())
9640 || (is_class_or_union_type(entry.second)
9641 && is_class_or_union_type(entry.second)->get_is_anonymous()))
9642 deleted_anon_types.insert(entry.second);
9643 }
9644
9645
9646 for (auto entry : added_unreachable_types_)
9647 if ((is_enum_type(entry.second)
9648 && is_enum_type(entry.second)->get_is_anonymous())
9649 || (is_class_or_union_type(entry.second)
9650 && is_class_or_union_type(entry.second)->get_is_anonymous()))
9651 added_anon_types.insert(entry.second);
9652
9653 string_type_base_sptr_map added_anon_types_to_erase;
9654 string_type_base_sptr_map removed_anon_types_to_erase;
9655 enum_type_decl_sptr deleted_enum;
9656 class_or_union_sptr deleted_class;
9657
9658 // Look for deleted anonymous types (enums, unions, structs &
9659 // classes) which have enumerators or data members present in an
9660 // added anonymous type ...
9661 for (auto deleted: deleted_anon_types)
9662 {
9663 deleted_enum = is_enum_type(deleted);
9664 deleted_class = is_class_or_union_type(deleted);
9665
9666 // For enums, look for any enumerator of 'deleted_enum' that
9667 // is also present in an added anonymous enum.
9668 if (deleted_enum)
9669 {
9670 for (auto enr : deleted_enum->get_enumerators())
9671 {
9672 bool this_enum_got_changed = false;
9673 for (auto t : added_anon_types)
9674 {
9675 if (enum_type_decl_sptr added_enum = is_enum_type(t))
9676 if (is_enumerator_present_in_enum(enr, *added_enum))
9677 {
9678 // So the enumerator 'enr' from the
9679 // 'deleted_enum' enum is also present in the
9680 // 'added_enum' enum so we assume that
9681 // 'deleted_enum' and 'added_enum' are the same
9682 // enum that got changed. Let's represent it
9683 // using a diff node.
9684 diff_sptr d = compute_diff(deleted_enum,
9685 added_enum, ctxt);
9686 ABG_ASSERT(d->has_changes());
9687 string repr =
9688 abigail::ir::get_pretty_representation(is_type(deleted_enum),
9689 /*internal=*/false);
9690 changed_unreachable_types_[repr]= d;
9691 this_enum_got_changed = true;
9692 string r1 =
9693 abigail::ir::get_pretty_representation(is_type(deleted_enum),
9694 /*internal=*/false);
9695 string r2 =
9696 abigail::ir::get_pretty_representation(is_type(added_enum),
9697 /*internal=*/false);
9698 removed_anon_types_to_erase[r1] = deleted_enum;
9699 added_anon_types_to_erase[r2] = added_enum;
9700 break;
9701 }
9702 }
9703 if (this_enum_got_changed)
9704 break;
9705 }
9706 }
9707 else if (deleted_class)
9708 {
9709 // For unions, structs & classes, look for any data
9710 // member of 'deleted_class' that is also present in an
9711 // added anonymous class.
9712 for (auto dm : deleted_class->get_data_members())
9713 {
9714 bool this_class_got_changed = false;
9715 for (auto klass : added_anon_types)
9716 {
9717 if (class_or_union_sptr added_class =
9718 is_class_or_union_type(klass))
9719 if (class_or_union_types_of_same_kind(deleted_class,
9720 added_class)
9721 && lookup_data_member(added_class, dm))
9722 {
9723 // So the data member 'dm' from the
9724 // 'deleted_class' class is also present in
9725 // the 'added_class' class so we assume that
9726 // 'deleted_class' and 'added_class' are the
9727 // same anonymous class that got changed.
9728 // Let's represent it using a diff node.
9729 diff_sptr d = compute_diff(is_type(deleted_class),
9730 is_type(added_class),
9731 ctxt);
9732 ABG_ASSERT(d->has_changes());
9733 string repr =
9734 abigail::ir::get_pretty_representation(is_type(deleted_class),
9735 /*internal=*/false);
9736 changed_unreachable_types_[repr]= d;
9737 this_class_got_changed = true;
9738 string r1 =
9739 abigail::ir::get_pretty_representation(is_type(deleted_class),
9740 /*internal=*/false);
9741 string r2 =
9742 abigail::ir::get_pretty_representation(is_type(added_class),
9743 /*internal=*/false);
9744 removed_anon_types_to_erase[r1] = deleted_class;
9745 added_anon_types_to_erase[r2] = added_class;
9746 break;
9747 }
9748 }
9749 if (this_class_got_changed)
9750 break;
9751 }
9752 }
9753 }
9754
9755 // Now remove the added/removed anonymous types from their maps,
9756 // as they are now represented as a changed type, not an added
9757 // and removed anonymous type.
9758 for (auto entry : added_anon_types_to_erase)
9759 added_unreachable_types_.erase(entry.first);
9760
9761 for (auto entry : removed_anon_types_to_erase)
9762 deleted_unreachable_types_.erase(entry.first);
9763 }
9764 }
9765 }
9766
9767 /// Test if a change reports about a given @ref function_decl that is
9768 /// changed in a certain way is suppressed by a given suppression
9769 /// specifiation
9770 ///
9771 /// @param fn the @ref function_decl to consider.
9772 ///
9773 /// @param suppr the suppression specification to consider.
9774 ///
9775 /// @param k the kind of change that happened to @p fn.
9776 ///
9777 /// @param ctxt the context of the current diff.
9778 ///
9779 /// @return true iff the suppression specification @p suppr suppresses
9780 /// change reports about function @p fn, if that function changes in
9781 /// the way expressed by @p k.
9782 static bool
function_is_suppressed(const function_decl * fn,const suppression_sptr suppr,function_suppression::change_kind k,const diff_context_sptr ctxt)9783 function_is_suppressed(const function_decl* fn,
9784 const suppression_sptr suppr,
9785 function_suppression::change_kind k,
9786 const diff_context_sptr ctxt)
9787 {
9788 function_suppression_sptr fn_suppr = is_function_suppression(suppr);
9789 if (!fn_suppr)
9790 return false;
9791 return fn_suppr->suppresses_function(fn, k, ctxt);
9792 }
9793
9794 /// Test if a change reports about a given @ref var_decl that is
9795 /// changed in a certain way is suppressed by a given suppression
9796 /// specifiation
9797 ///
9798 /// @param fn the @ref var_decl to consider.
9799 ///
9800 /// @param suppr the suppression specification to consider.
9801 ///
9802 /// @param k the kind of change that happened to @p fn.
9803 ///
9804 /// @param ctxt the context of the current diff.
9805 ///
9806 /// @return true iff the suppression specification @p suppr suppresses
9807 /// change reports about variable @p fn, if that variable changes in
9808 /// the way expressed by @p k.
9809 static bool
variable_is_suppressed(const var_decl * var,const suppression_sptr suppr,variable_suppression::change_kind k,const diff_context_sptr ctxt)9810 variable_is_suppressed(const var_decl* var,
9811 const suppression_sptr suppr,
9812 variable_suppression::change_kind k,
9813 const diff_context_sptr ctxt)
9814 {
9815 variable_suppression_sptr var_suppr = is_variable_suppression(suppr);
9816 if (!var_suppr)
9817 return false;
9818 return var_suppr->suppresses_variable(var, k, ctxt);
9819 }
9820
9821 /// Apply suppression specifications for this corpus diff to the set
9822 /// of added/removed functions/variables, as well as to types not
9823 /// reachable from global functions/variables.
9824 void
apply_supprs_to_added_removed_fns_vars_unreachable_types()9825 corpus_diff::priv::apply_supprs_to_added_removed_fns_vars_unreachable_types()
9826 {
9827 diff_context_sptr ctxt = get_context();
9828
9829 const suppressions_type& suppressions = ctxt->suppressions();
9830 for (suppressions_type::const_iterator i = suppressions.begin();
9831 i != suppressions.end();
9832 ++i)
9833 {
9834 // Added/Deleted functions.
9835 if (function_suppression_sptr fn_suppr = is_function_suppression(*i))
9836 {
9837 // Added functions
9838 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9839 e != added_fns_.end();
9840 ++e)
9841 if (function_is_suppressed(e->second, fn_suppr,
9842 function_suppression::ADDED_FUNCTION_CHANGE_KIND,
9843 ctxt))
9844 suppressed_added_fns_[e->first] = e->second;
9845
9846 // Deleted functions.
9847 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9848 e != deleted_fns_.end();
9849 ++e)
9850 if (function_is_suppressed(e->second, fn_suppr,
9851 function_suppression::DELETED_FUNCTION_CHANGE_KIND,
9852 ctxt))
9853 suppressed_deleted_fns_[e->first] = e->second;
9854
9855 // Added function symbols not referenced by any debug info
9856 for (string_elf_symbol_map::const_iterator e =
9857 added_unrefed_fn_syms_.begin();
9858 e != added_unrefed_fn_syms_.end();
9859 ++e)
9860 if (fn_suppr->suppresses_function_symbol(e->second,
9861 function_suppression::ADDED_FUNCTION_CHANGE_KIND,
9862 ctxt))
9863 suppressed_added_unrefed_fn_syms_[e->first] = e->second;
9864
9865 // Removed function symbols not referenced by any debug info
9866 for (string_elf_symbol_map::const_iterator e =
9867 deleted_unrefed_fn_syms_.begin();
9868 e != deleted_unrefed_fn_syms_.end();
9869 ++e)
9870 if (fn_suppr->suppresses_function_symbol(e->second,
9871 function_suppression::DELETED_FUNCTION_CHANGE_KIND,
9872 ctxt))
9873 suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
9874 }
9875 // Added/Delete virtual member functions changes that might be
9876 // suppressed by a type_suppression that matches the enclosing
9877 // class of the virtual member function.
9878 else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
9879 {
9880 // Added virtual functions
9881 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9882 e != added_fns_.end();
9883 ++e)
9884 if (is_member_function(e->second)
9885 && get_member_function_is_virtual(e->second))
9886 {
9887 function_decl *f = e->second;
9888 class_decl_sptr c =
9889 is_class_type(is_method_type(f->get_type())->get_class_type());
9890 ABG_ASSERT(c);
9891 if (type_suppr->suppresses_type(c, ctxt))
9892 suppressed_added_fns_[e->first] = e->second;
9893 }
9894 // Deleted virtual functions
9895 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9896 e != deleted_fns_.end();
9897 ++e)
9898 if (is_member_function(e->second)
9899 && get_member_function_is_virtual(e->second))
9900 {
9901 function_decl *f = e->second;
9902 class_decl_sptr c =
9903 is_class_type(is_method_type(f->get_type())->get_class_type());
9904 ABG_ASSERT(c);
9905 if (type_suppr->suppresses_type(c, ctxt))
9906 suppressed_deleted_fns_[e->first] = e->second;
9907 }
9908
9909 // Apply this type suppression to deleted types
9910 // non-reachable from a public interface.
9911 for (string_type_base_sptr_map::const_iterator e =
9912 deleted_unreachable_types_.begin();
9913 e != deleted_unreachable_types_.end();
9914 ++e)
9915 if (type_suppr->suppresses_type(e->second, ctxt))
9916 suppressed_deleted_unreachable_types_[e->first] = e->second;
9917
9918 // Apply this type suppression to added types
9919 // non-reachable from a public interface.
9920 for (string_type_base_sptr_map::const_iterator e =
9921 added_unreachable_types_.begin();
9922 e != added_unreachable_types_.end();
9923 ++e)
9924 if (type_suppr->suppresses_type(e->second, ctxt))
9925 suppressed_added_unreachable_types_[e->first] = e->second;
9926 }
9927 // Added/Deleted variables
9928 else if (variable_suppression_sptr var_suppr =
9929 is_variable_suppression(*i))
9930 {
9931 // Added variables
9932 for (string_var_ptr_map::const_iterator e = added_vars_.begin();
9933 e != added_vars_.end();
9934 ++e)
9935 if (variable_is_suppressed(e->second, var_suppr,
9936 variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
9937 ctxt))
9938 suppressed_added_vars_[e->first] = e->second;
9939
9940 //Deleted variables
9941 for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
9942 e != deleted_vars_.end();
9943 ++e)
9944 if (variable_is_suppressed(e->second, var_suppr,
9945 variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
9946 ctxt))
9947 suppressed_deleted_vars_[e->first] = e->second;
9948
9949 // Added variable symbols not referenced by any debug info
9950 for (string_elf_symbol_map::const_iterator e =
9951 added_unrefed_var_syms_.begin();
9952 e != added_unrefed_var_syms_.end();
9953 ++e)
9954 if (var_suppr->suppresses_variable_symbol(e->second,
9955 variable_suppression::ADDED_VARIABLE_CHANGE_KIND,
9956 ctxt))
9957 suppressed_added_unrefed_var_syms_[e->first] = e->second;
9958
9959 // Removed variable symbols not referenced by any debug info
9960 for (string_elf_symbol_map::const_iterator e =
9961 deleted_unrefed_var_syms_.begin();
9962 e != deleted_unrefed_var_syms_.end();
9963 ++e)
9964 if (var_suppr->suppresses_variable_symbol(e->second,
9965 variable_suppression::DELETED_VARIABLE_CHANGE_KIND,
9966 ctxt))
9967 suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
9968 }
9969 }
9970 }
9971
9972 /// Test if the change reports for a given deleted function have
9973 /// been deleted.
9974 ///
9975 /// @param fn the function to consider.
9976 ///
9977 /// @return true iff the change reports for a give given deleted
9978 /// function have been deleted.
9979 bool
deleted_function_is_suppressed(const function_decl * fn) const9980 corpus_diff::priv::deleted_function_is_suppressed(const function_decl* fn) const
9981 {
9982 if (!fn)
9983 return false;
9984
9985 string_function_ptr_map::const_iterator i =
9986 suppressed_deleted_fns_.find(fn->get_id());
9987
9988 return (i != suppressed_deleted_fns_.end());
9989 }
9990
9991 /// Test if an added type that is unreachable from public interface
9992 /// has been suppressed by a suppression specification.
9993 ///
9994 /// @param t the added unreachable type to be considered.
9995 ///
9996 /// @return true iff @p t has been suppressed by a suppression
9997 /// specification.
9998 bool
added_unreachable_type_is_suppressed(const type_base * t) const9999 corpus_diff::priv::added_unreachable_type_is_suppressed(const type_base *t)const
10000 {
10001 if (!t)
10002 return false;
10003
10004 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10005 string_type_base_sptr_map::const_iterator i =
10006 suppressed_added_unreachable_types_.find(repr);
10007 if (i == suppressed_added_unreachable_types_.end())
10008 return false;
10009
10010 return true;
10011 }
10012
10013 /// Test if a deleted type that is unreachable from public interface
10014 /// has been suppressed by a suppression specification.
10015 ///
10016 /// @param t the deleted unreachable type to be considered.
10017 ///
10018 /// @return true iff @p t has been suppressed by a suppression
10019 /// specification.
10020 bool
deleted_unreachable_type_is_suppressed(const type_base * t) const10021 corpus_diff::priv::deleted_unreachable_type_is_suppressed(const type_base *t) const
10022 {
10023 if (!t)
10024 return false;
10025
10026 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10027 string_type_base_sptr_map::const_iterator i =
10028 suppressed_deleted_unreachable_types_.find(repr);
10029 if (i == suppressed_deleted_unreachable_types_.end())
10030 return false;
10031
10032 return true;
10033 }
10034
10035 /// Test if the change reports for a give given added function has
10036 /// been deleted.
10037 ///
10038 /// @param fn the function to consider.
10039 ///
10040 /// @return true iff the change reports for a give given added
10041 /// function has been deleted.
10042 bool
added_function_is_suppressed(const function_decl * fn) const10043 corpus_diff::priv::added_function_is_suppressed(const function_decl* fn) const
10044 {
10045 if (!fn)
10046 return false;
10047
10048 string_function_ptr_map::const_iterator i =
10049 suppressed_added_fns_.find(fn->get_id());
10050
10051 return (i != suppressed_added_fns_.end());
10052 }
10053
10054 /// Test if the change reports for a give given deleted variable has
10055 /// been deleted.
10056 ///
10057 /// @param var the variable to consider.
10058 ///
10059 /// @return true iff the change reports for a give given deleted
10060 /// variable has been deleted.
10061 bool
deleted_variable_is_suppressed(const var_decl * var) const10062 corpus_diff::priv::deleted_variable_is_suppressed(const var_decl* var) const
10063 {
10064 if (!var)
10065 return false;
10066
10067 string_var_ptr_map::const_iterator i =
10068 suppressed_deleted_vars_.find(var->get_id());
10069
10070 return (i != suppressed_deleted_vars_.end());
10071 }
10072
10073 /// Test if the change reports for a given added variable have been
10074 /// suppressed.
10075 ///
10076 /// @param var the variable to consider.
10077 ///
10078 /// @return true iff the change reports for a given deleted
10079 /// variable has been deleted.
10080 bool
added_variable_is_suppressed(const var_decl * var) const10081 corpus_diff::priv::added_variable_is_suppressed(const var_decl* var) const
10082 {
10083 if (!var)
10084 return false;
10085
10086 string_var_ptr_map::const_iterator i =
10087 suppressed_added_vars_.find(var->get_id());
10088
10089 return (i != suppressed_added_vars_.end());
10090 }
10091
10092 /// Test if the change reports for a given deleted function symbol
10093 /// (that is not referenced by any debug info) has been suppressed.
10094 ///
10095 /// @param var the function to consider.
10096 ///
10097 /// @return true iff the change reports for a given deleted function
10098 /// symbol has been suppressed.
10099 bool
deleted_unrefed_fn_sym_is_suppressed(const elf_symbol * s) const10100 corpus_diff::priv::deleted_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
10101 {
10102 if (!s)
10103 return false;
10104
10105 string_elf_symbol_map::const_iterator i =
10106 suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10107
10108 return (i != suppressed_deleted_unrefed_fn_syms_.end());
10109 }
10110
10111 /// Test if the change reports for a given added function symbol
10112 /// (that is not referenced by any debug info) has been suppressed.
10113 ///
10114 /// @param var the function to consider.
10115 ///
10116 /// @return true iff the change reports for a given added function
10117 /// symbol has been suppressed.
10118 bool
added_unrefed_fn_sym_is_suppressed(const elf_symbol * s) const10119 corpus_diff::priv::added_unrefed_fn_sym_is_suppressed(const elf_symbol* s) const
10120 {
10121 if (!s)
10122 return false;
10123
10124 string_elf_symbol_map::const_iterator i =
10125 suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10126
10127 return (i != suppressed_added_unrefed_fn_syms_.end());
10128 }
10129
10130 /// Test if the change reports for a given deleted variable symbol
10131 /// (that is not referenced by any debug info) has been suppressed.
10132 ///
10133 /// @param var the variable to consider.
10134 ///
10135 /// @return true iff the change reports for a given deleted variable
10136 /// symbol has been suppressed.
10137 bool
deleted_unrefed_var_sym_is_suppressed(const elf_symbol * s) const10138 corpus_diff::priv::deleted_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
10139 {
10140 if (!s)
10141 return false;
10142
10143 string_elf_symbol_map::const_iterator i =
10144 suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10145
10146 return (i != suppressed_deleted_unrefed_var_syms_.end());
10147 }
10148
10149 /// Test if the change reports for a given added variable symbol
10150 /// (that is not referenced by any debug info) has been suppressed.
10151 ///
10152 /// @param var the variable to consider.
10153 ///
10154 /// @return true iff the change reports for a given added variable
10155 /// symbol has been suppressed.
10156 bool
added_unrefed_var_sym_is_suppressed(const elf_symbol * s) const10157 corpus_diff::priv::added_unrefed_var_sym_is_suppressed(const elf_symbol* s) const
10158 {
10159 if (!s)
10160 return false;
10161
10162 string_elf_symbol_map::const_iterator i =
10163 suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10164
10165 return (i != suppressed_added_unrefed_var_syms_.end());
10166 }
10167
10168 #ifdef do_count_diff_map_changes
10169 #undef do_count_diff_map_changes
10170 #endif
10171 #define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10172 { \
10173 string_diff_ptr_map::const_iterator i; \
10174 for (i = diff_map.begin(); \
10175 i != diff_map.end(); \
10176 ++i) \
10177 { \
10178 if (const var_diff* d = is_var_diff(i->second)) \
10179 if (is_data_member(d->first_var())) \
10180 continue; \
10181 \
10182 if (i->second->has_local_changes()) \
10183 ++n_changes; \
10184 if (!i->second->get_canonical_diff()->to_be_reported()) \
10185 ++n_filtered; \
10186 } \
10187 }
10188
10189 /// Count the number of leaf changes as well as the number of the
10190 /// changes that have been filtered out.
10191 ///
10192 /// @param num_changes out parameter. This is set to the total number
10193 /// of leaf changes.
10194 ///
10195 /// @param num_filtered out parameter. This is set to the number of
10196 /// leaf changes that have been filtered out.
10197 void
count_leaf_changes(size_t & num_changes,size_t & num_filtered)10198 corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10199 {
10200 count_leaf_type_changes(num_changes, num_filtered);
10201
10202 // Now count the non-type changes.
10203 do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10204 num_changes, num_filtered);
10205 do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10206 num_changes, num_filtered);
10207 }
10208
10209 /// Count the number of leaf *type* changes as well as the number of
10210 /// the leaf type changes that have been filtered out.
10211 ///
10212 /// @param num_changes out parameter. This is set to the total number
10213 /// of leaf type changes.
10214 ///
10215 /// @param num_filtered out parameter. This is set to the number of
10216 /// leaf type changes that have been filtered out.
10217 void
count_leaf_type_changes(size_t & num_changes,size_t & num_filtered)10218 corpus_diff::priv::count_leaf_type_changes(size_t &num_changes,
10219 size_t &num_filtered)
10220 {
10221 do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10222 num_changes, num_filtered);
10223 do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10224 num_changes, num_filtered);
10225 do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10226 num_changes, num_filtered);
10227 do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10228 num_changes, num_filtered);
10229 do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10230 num_changes, num_filtered);
10231 do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10232 num_changes, num_filtered);
10233 do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10234 num_changes, num_filtered);
10235 do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10236 num_changes, num_filtered);
10237 do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10238 num_changes, num_filtered);
10239 }
10240
10241 /// Count the number of types not reachable from the interface (i.e,
10242 /// not reachable from global functions or variables).
10243 ///
10244 /// @param num_added this is set to the number of added types not
10245 /// reachable from the interface.
10246 ///
10247 /// @param num_deleted this is set to the number of deleted types not
10248 /// reachable from the interface.
10249 ///
10250 /// @param num_changed this is set to the number of changed types not
10251 /// reachable from the interface.
10252 ///
10253 /// @param num_filtered_added this is set to the number of added types
10254 /// not reachable from the interface and that have been filtered out
10255 /// by suppression specifications.
10256 ///
10257 /// @param num_filtered_deleted this is set to the number of deleted
10258 /// types not reachable from the interface and that have been filtered
10259 /// out by suppression specifications.
10260 ///
10261 /// @param num_filtered_changed this is set to the number of changed
10262 /// types not reachable from the interface and that have been filtered
10263 /// out by suppression specifications.
10264 void
count_unreachable_types(size_t & num_added,size_t & num_deleted,size_t & num_changed,size_t & num_filtered_added,size_t & num_filtered_deleted,size_t & num_filtered_changed)10265 corpus_diff::priv::count_unreachable_types(size_t &num_added,
10266 size_t &num_deleted,
10267 size_t &num_changed,
10268 size_t &num_filtered_added,
10269 size_t &num_filtered_deleted,
10270 size_t &num_filtered_changed)
10271 {
10272 num_added = added_unreachable_types_.size();
10273 num_deleted = deleted_unreachable_types_.size();
10274 num_changed = changed_unreachable_types_.size();
10275 num_filtered_added = suppressed_added_unreachable_types_.size();
10276 num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10277
10278 for (vector<diff_sptr>::const_iterator i =
10279 changed_unreachable_types_sorted().begin();
10280 i != changed_unreachable_types_sorted().end();
10281 ++i)
10282 if (!(*i)->to_be_reported())
10283 ++num_filtered_changed;
10284 }
10285
10286 /// Get the map of diff nodes representing changed unreachable types.
10287 ///
10288 /// @return the map of diff nodes representing changed unreachable
10289 /// types.
10290 const string_diff_sptr_map&
changed_unreachable_types() const10291 corpus_diff::priv::changed_unreachable_types() const
10292 {return changed_unreachable_types_;}
10293
10294 /// Get the sorted vector of diff nodes representing changed
10295 /// unreachable types.
10296 ///
10297 /// Upon the first invocation of this method, if the vector is empty,
10298 /// this function gets the diff nodes representing changed
10299 /// unreachable, sort them, and return the sorted vector.
10300 ///
10301 /// @return the sorted vector of diff nodes representing changed
10302 /// unreachable types.
10303 const vector<diff_sptr>&
changed_unreachable_types_sorted() const10304 corpus_diff::priv::changed_unreachable_types_sorted() const
10305 {
10306 if (changed_unreachable_types_sorted_.empty())
10307 if (!changed_unreachable_types_.empty())
10308 sort_string_diff_sptr_map(changed_unreachable_types_,
10309 changed_unreachable_types_sorted_);
10310
10311 return changed_unreachable_types_sorted_;
10312 }
10313
10314 /// Compute the diff stats.
10315 ///
10316 /// To know the number of functions that got filtered out, this
10317 /// function applies the categorizing filters to the diff sub-trees of
10318 /// each function changes diff, prior to calculating the stats.
10319 ///
10320 /// @param num_removed the number of removed functions.
10321 ///
10322 /// @param num_added the number of added functions.
10323 ///
10324 /// @param num_changed the number of changed functions.
10325 ///
10326 /// @param num_filtered_out the number of changed functions that are
10327 /// got filtered out from the report
10328 void
apply_filters_and_compute_diff_stats(diff_stats & stat)10329 corpus_diff::priv::apply_filters_and_compute_diff_stats(diff_stats& stat)
10330 {
10331 stat.num_func_removed(deleted_fns_.size());
10332 stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
10333 stat.num_func_added(added_fns_.size());
10334 stat.num_added_func_filtered_out(suppressed_added_fns_.size());
10335 stat.num_func_changed(changed_fns_map_.size());
10336
10337 stat.num_vars_removed(deleted_vars_.size());
10338 stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
10339 stat.num_vars_added(added_vars_.size());
10340 stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
10341 stat.num_vars_changed(changed_vars_map_.size());
10342
10343 diff_context_sptr ctxt = get_context();
10344
10345 tools_utils::timer t;
10346 if (ctxt->perform_change_categorization())
10347 {
10348 if (get_context()->do_log())
10349 {
10350 std::cerr << "in apply_filters_and_compute_diff_stats:"
10351 << "applying filters to "
10352 << changed_fns_.size()
10353 << " changed fns ...\n";
10354 t.start();
10355 }
10356 // Walk the changed function diff nodes to apply the categorization
10357 // filters.
10358 diff_sptr diff;
10359 for (function_decl_diff_sptrs_type::const_iterator i =
10360 changed_fns_.begin();
10361 i != changed_fns_.end();
10362 ++i)
10363 {
10364 diff_sptr diff = *i;
10365 ctxt->maybe_apply_filters(diff);
10366 }
10367
10368 if (get_context()->do_log())
10369 {
10370 t.stop();
10371 std::cerr << "in apply_filters_and_compute_diff_stats:"
10372 << "filters to changed fn applied!:" << t << "\n";
10373
10374 std::cerr << "in apply_filters_and_compute_diff_stats:"
10375 << "applying filters to "
10376 << sorted_changed_vars_.size()
10377 << " changed vars ...\n";
10378 t.start();
10379 }
10380
10381 // Walk the changed variable diff nodes to apply the categorization
10382 // filters.
10383 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10384 i != sorted_changed_vars_.end();
10385 ++i)
10386 {
10387 diff_sptr diff = *i;
10388 ctxt->maybe_apply_filters(diff);
10389 }
10390
10391 if (get_context()->do_log())
10392 {
10393 t.stop();
10394 std::cerr << "in apply_filters_and_compute_diff_stats:"
10395 << "filters to changed vars applied!:" << t << "\n";
10396
10397 std::cerr << "in apply_filters_and_compute_diff_stats:"
10398 << "applying filters to unreachable types ...\n";
10399 t.start();
10400 }
10401
10402 // walk the changed unreachable types to apply categorization
10403 // filters
10404 for (auto& diff : changed_unreachable_types_sorted())
10405 ctxt->maybe_apply_filters(diff);
10406
10407 for (auto& entry : changed_unreachable_types())
10408 ctxt->maybe_apply_filters(entry.second);
10409
10410 if (get_context()->do_log())
10411 {
10412 t.stop();
10413 std::cerr << "in apply_filters_and_compute_diff_stats:"
10414 << "filters to unreachable types applied!:" << t << "\n";
10415
10416 std::cerr << "in apply_filters_and_compute_diff_stats:"
10417 << "categorizing redundant changed sub nodes ...\n";
10418 t.start();
10419 }
10420
10421 categorize_redundant_changed_sub_nodes();
10422
10423 if (get_context()->do_log())
10424 {
10425 t.stop();
10426 std::cerr << "in apply_filters_and_compute_diff_stats:"
10427 << "redundant changed sub nodes categorized!:" << t << "\n";
10428
10429 std::cerr << "in apply_filters_and_compute_diff_stats:"
10430 << "count changed fns ...\n";
10431 t.start();
10432 }
10433 }
10434
10435 // Walk the changed function diff nodes to count the number of
10436 // filtered-out functions and the number of functions with virtual
10437 // offset changes.
10438 for (function_decl_diff_sptrs_type::const_iterator i =
10439 changed_fns_.begin();
10440 i != changed_fns_.end();
10441 ++i)
10442 {
10443 if ((*i)->is_filtered_out())
10444 {
10445 stat.num_changed_func_filtered_out
10446 (stat.num_changed_func_filtered_out() + 1);
10447
10448 if ((*i)->has_local_changes())
10449 stat.num_leaf_func_changes_filtered_out
10450 (stat.num_leaf_func_changes_filtered_out() + 1);
10451 }
10452 else
10453 {
10454 if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
10455 stat.num_func_with_virtual_offset_changes
10456 (stat.num_func_with_virtual_offset_changes() + 1);
10457 }
10458
10459 if ((*i)->has_local_changes())
10460 stat.num_leaf_func_changes
10461 (stat.num_leaf_func_changes() + 1);
10462 }
10463
10464 if (get_context()->do_log())
10465 {
10466 t.stop();
10467 std::cerr << "in apply_filters_and_compute_diff_stats:"
10468 << "changed fn counted!:" << t << "\n";
10469
10470 std::cerr << "in apply_filters_and_compute_diff_stats:"
10471 << "count changed vars ...\n";
10472 t.start();
10473 }
10474
10475 // Walk the changed variables diff nodes to count the number of
10476 // filtered-out variables.
10477 for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
10478 i != sorted_changed_vars_.end();
10479 ++i)
10480 {
10481 if ((*i)->is_filtered_out())
10482 {
10483 stat.num_changed_vars_filtered_out
10484 (stat.num_changed_vars_filtered_out() + 1);
10485
10486 if ((*i)->has_local_changes())
10487 stat.num_leaf_var_changes_filtered_out
10488 (stat.num_leaf_var_changes_filtered_out() + 1);
10489 }
10490 if ((*i)->has_local_changes())
10491 stat.num_leaf_var_changes
10492 (stat.num_leaf_var_changes() + 1);
10493 }
10494
10495 if (get_context()->do_log())
10496 {
10497 t.stop();
10498 std::cerr << "in apply_filters_and_compute_diff_stats:"
10499 << "changed vars counted!:" << t << "\n";
10500
10501 std::cerr << "in apply_filters_and_compute_diff_stats:"
10502 << "count leaf changed types ...\n";
10503 t.start();
10504 }
10505
10506 stat.num_func_syms_added(added_unrefed_fn_syms_.size());
10507 stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
10508 stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
10509 stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
10510 stat.num_var_syms_added(added_unrefed_var_syms_.size());
10511 stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
10512 stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
10513 stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
10514
10515 // Walk the general leaf type diff nodes to count them
10516 {
10517 size_t num_type_changes = 0, num_type_filtered = 0;
10518 count_leaf_type_changes(num_type_changes, num_type_filtered);
10519
10520 stat.num_leaf_type_changes(num_type_changes);
10521 stat.num_leaf_type_changes_filtered_out(num_type_filtered);
10522 }
10523
10524 if (get_context()->do_log())
10525 {
10526 t.stop();
10527 std::cerr << "in apply_filters_and_compute_diff_stats:"
10528 << "changed leaf types counted!:" << t << "\n";
10529
10530 std::cerr << "in apply_filters_and_compute_diff_stats:"
10531 << "count leaf changed artefacts ...\n";
10532 t.start();
10533 }
10534
10535 // Walk the general leaf artefacts diff nodes to count them
10536 {
10537 size_t num_changes = 0, num_filtered = 0;
10538 count_leaf_changes(num_changes, num_filtered);
10539
10540 stat.num_leaf_changes(num_changes);
10541 stat.num_leaf_changes_filtered_out(num_filtered);
10542 }
10543
10544 if (get_context()->do_log())
10545 {
10546 t.stop();
10547 std::cerr << "in apply_filters_and_compute_diff_stats:"
10548 << "changed leaf artefacts counted!:" << t << "\n";
10549
10550 std::cerr << "in apply_filters_and_compute_diff_stats:"
10551 << "count unreachable types ...\n";
10552 t.start();
10553 }
10554
10555 // Walk the unreachable types to count them
10556 {
10557 size_t num_added_unreachable_types = 0,
10558 num_changed_unreachable_types = 0,
10559 num_deleted_unreachable_types = 0,
10560 num_added_unreachable_types_filtered = 0,
10561 num_changed_unreachable_types_filtered = 0,
10562 num_deleted_unreachable_types_filtered = 0;
10563
10564 count_unreachable_types(num_added_unreachable_types,
10565 num_deleted_unreachable_types,
10566 num_changed_unreachable_types,
10567 num_added_unreachable_types_filtered,
10568 num_deleted_unreachable_types_filtered,
10569 num_changed_unreachable_types_filtered);
10570
10571 if (get_context()->do_log())
10572 {
10573 t.stop();
10574 std::cerr << "in apply_filters_and_compute_diff_stats:"
10575 << "unreachable types counted!:" << t << "\n";
10576 }
10577
10578 stat.num_added_unreachable_types(num_added_unreachable_types);
10579 stat.num_removed_unreachable_types(num_deleted_unreachable_types);
10580 stat.num_changed_unreachable_types(num_changed_unreachable_types);
10581 stat.num_added_unreachable_types_filtered_out
10582 (num_added_unreachable_types_filtered);
10583 stat.num_removed_unreachable_types_filtered_out
10584 (num_deleted_unreachable_types_filtered);
10585 stat.num_changed_unreachable_types_filtered_out
10586 (num_changed_unreachable_types_filtered);
10587 }
10588 }
10589
10590 /// Emit the summary of the functions & variables that got
10591 /// removed/changed/added.
10592 ///
10593 /// TODO: This should be handled by the reporters, just like what is
10594 /// done for reporter_base::diff_to_be_reported.
10595 ///
10596 /// @param out the output stream to emit the stats to.
10597 ///
10598 /// @param indent the indentation string to use in the summary.
10599 void
emit_diff_stats(const diff_stats & s,ostream & out,const string & indent)10600 corpus_diff::priv::emit_diff_stats(const diff_stats& s,
10601 ostream& out,
10602 const string& indent)
10603 {
10604 /// Report added/removed/changed functions.
10605 size_t net_num_leaf_changes =
10606 s.net_num_func_removed() +
10607 s.net_num_func_added() +
10608 s.net_num_leaf_func_changes() +
10609 s.net_num_vars_removed() +
10610 s.net_num_vars_added() +
10611 s.net_num_leaf_var_changes() +
10612 s.net_num_leaf_type_changes() +
10613 s.net_num_removed_func_syms() +
10614 s.net_num_added_func_syms() +
10615 s.net_num_removed_var_syms() +
10616 s.net_num_added_var_syms();
10617
10618 if (!sonames_equal_)
10619 out << indent << "ELF SONAME changed\n";
10620
10621 if (!architectures_equal_)
10622 out << indent << "ELF architecture changed\n";
10623
10624 diff_context_sptr ctxt = get_context();
10625
10626 if (ctxt->show_leaf_changes_only())
10627 {
10628 out << "Leaf changes summary: ";
10629 out << net_num_leaf_changes << " artifact";
10630 if (net_num_leaf_changes > 1)
10631 out << "s";
10632 out << " changed";
10633
10634 if (size_t num_filtered = s.num_leaf_changes_filtered_out())
10635 out << " (" << num_filtered << " filtered out)";
10636 out << "\n";
10637
10638 out << indent << "Changed leaf types summary: "
10639 << s.net_num_leaf_type_changes();
10640 if (s.num_leaf_type_changes_filtered_out())
10641 out << " (" << s.num_leaf_type_changes_filtered_out()
10642 << " filtered out)";
10643 out << " leaf type";
10644 if (s.num_leaf_type_changes() > 1)
10645 out << "s";
10646 out << " changed\n";
10647
10648 // function changes summary
10649 out << indent << "Removed/Changed/Added functions summary: ";
10650 out << s.net_num_func_removed() << " Removed";
10651 if (s.num_removed_func_filtered_out())
10652 out << " ("
10653 << s.num_removed_func_filtered_out()
10654 << " filtered out)";
10655 out << ", ";
10656
10657 out << s.net_num_leaf_func_changes() << " Changed";
10658 if (s.num_leaf_func_changes_filtered_out())
10659 out << " ("
10660 << s.num_leaf_func_changes_filtered_out()
10661 << " filtered out)";
10662 out << ", ";
10663
10664 out << s.net_num_func_added()<< " Added ";
10665 if (s.net_num_func_added() <= 1)
10666 out << "function";
10667 else
10668 out << "functions";
10669 if (s.num_added_func_filtered_out())
10670 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10671 out << "\n";
10672
10673 // variables changes summary
10674 out << indent << "Removed/Changed/Added variables summary: ";
10675 out << s.net_num_vars_removed() << " Removed";
10676 if (s.num_removed_vars_filtered_out())
10677 out << " (" << s.num_removed_vars_filtered_out()
10678 << " filtered out)";
10679 out << ", ";
10680
10681 out << s.net_num_leaf_var_changes() << " Changed";
10682 if (s.num_leaf_var_changes_filtered_out())
10683 out << " ("
10684 << s.num_leaf_var_changes_filtered_out()
10685 << " filtered out)";
10686 out << ", ";
10687
10688 out << s.net_num_vars_added() << " Added ";
10689 if (s.net_num_vars_added() <= 1)
10690 out << "variable";
10691 else
10692 out << "variables";
10693 if (s.num_added_vars_filtered_out())
10694 out << " (" << s.num_added_vars_filtered_out()
10695 << " filtered out)";
10696 out << "\n";
10697 }
10698 else // if (ctxt->show_leaf_changes_only())
10699 {
10700 size_t total_nb_function_changes = s.num_func_removed()
10701 + s.num_func_changed() + s.num_func_added();
10702
10703 // function changes summary
10704 out << indent << "Functions changes summary: ";
10705 out << s.net_num_func_removed() << " Removed";
10706 if (s.num_removed_func_filtered_out())
10707 out << " ("
10708 << s.num_removed_func_filtered_out()
10709 << " filtered out)";
10710 out << ", ";
10711
10712 out << s.net_num_func_changed() << " Changed";
10713 if (s.num_changed_func_filtered_out())
10714 out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
10715 out << ", ";
10716
10717 out << s.net_num_func_added() << " Added";
10718 if (s.num_added_func_filtered_out())
10719 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10720 if (total_nb_function_changes <= 1)
10721 out << " function";
10722 else
10723 out << " functions";
10724 out << "\n";
10725
10726 // variables changes summary
10727 size_t total_nb_variable_changes = s.num_vars_removed()
10728 + s.num_vars_changed() + s.num_vars_added();
10729
10730 out << indent << "Variables changes summary: ";
10731 out << s.net_num_vars_removed() << " Removed";
10732 if (s.num_removed_vars_filtered_out())
10733 out << " (" << s.num_removed_vars_filtered_out()
10734 << " filtered out)";
10735 out << ", ";
10736
10737 out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
10738 if (s.num_changed_vars_filtered_out())
10739 out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
10740 out << ", ";
10741
10742 out << s.net_num_vars_added() << " Added";
10743 if (s.num_added_vars_filtered_out())
10744 out << " (" << s.num_added_vars_filtered_out()
10745 << " filtered out)";
10746 if (total_nb_variable_changes <= 1)
10747 out << " variable";
10748 else
10749 out << " variables";
10750 out << "\n";
10751 }
10752
10753 // Show statistics about types not reachable from global
10754 // functions/variables.
10755 if (ctxt->show_unreachable_types())
10756 {
10757 size_t total_nb_unreachable_type_changes =
10758 s.num_removed_unreachable_types()
10759 + s.num_changed_unreachable_types()
10760 + s.num_added_unreachable_types();
10761
10762 // Show summary of unreachable types
10763 out << indent << "Unreachable types summary: "
10764 << s.net_num_removed_unreachable_types()
10765 << " removed";
10766 if (s.num_removed_unreachable_types_filtered_out())
10767 out << " (" << s.num_removed_unreachable_types_filtered_out()
10768 << " filtered out)";
10769 out << ", ";
10770
10771 out << s.net_num_changed_unreachable_types()
10772 << " changed";
10773 if (s.num_changed_unreachable_types_filtered_out())
10774 out << " (" << s.num_changed_unreachable_types_filtered_out()
10775 << " filtered out)";
10776 out << ", ";
10777
10778 out << s.net_num_added_unreachable_types()
10779 << " added";
10780 if (s.num_added_unreachable_types_filtered_out())
10781 out << " (" << s.num_added_unreachable_types_filtered_out()
10782 << " filtered out)";
10783 if (total_nb_unreachable_type_changes <= 1)
10784 out << " type";
10785 else
10786 out << " types";
10787 out << "\n";
10788 }
10789
10790 if (ctxt->show_symbols_unreferenced_by_debug_info()
10791 && (s.num_func_syms_removed()
10792 || s.num_func_syms_added()
10793 || s.num_var_syms_removed()
10794 || s.num_var_syms_added()))
10795 {
10796 // function symbols changes summary.
10797
10798 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10799 && s.num_func_syms_removed() == 0
10800 && s.num_func_syms_added() != 0)
10801 // If the only unreferenced function symbol change is function
10802 // syms that got added, but we were forbidden to show function
10803 // syms being added, do nothing.
10804 ;
10805 else
10806 {
10807 out << indent
10808 << "Function symbols changes summary: "
10809 << s.net_num_removed_func_syms() << " Removed";
10810 if (s.num_removed_func_syms_filtered_out())
10811 out << " (" << s.num_removed_func_syms_filtered_out()
10812 << " filtered out)";
10813 out << ", ";
10814 out << s.net_num_added_func_syms() << " Added";
10815 if (s.num_added_func_syms_filtered_out())
10816 out << " (" << s.num_added_func_syms_filtered_out()
10817 << " filtered out)";
10818 out << " function symbol";
10819 if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
10820 out << "s";
10821 out << " not referenced by debug info\n";
10822 }
10823
10824 // variable symbol changes summary.
10825
10826 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10827 && s.num_var_syms_removed() == 0
10828 && s.num_var_syms_added() != 0)
10829 // If the only unreferenced variable symbol change is variable
10830 // syms that got added, but we were forbidden to show variable
10831 // syms being added, do nothing.
10832 ;
10833 else
10834 {
10835 out << indent
10836 << "Variable symbols changes summary: "
10837 << s.net_num_removed_var_syms() << " Removed";
10838 if (s.num_removed_var_syms_filtered_out())
10839 out << " (" << s.num_removed_var_syms_filtered_out()
10840 << " filtered out)";
10841 out << ", ";
10842 out << s.net_num_added_var_syms() << " Added";
10843 if (s.num_added_var_syms_filtered_out())
10844 out << " (" << s.num_added_var_syms_filtered_out()
10845 << " filtered out)";
10846 out << " variable symbol";
10847 if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
10848 out << "s";
10849 out << " not referenced by debug info\n";
10850 }
10851 }
10852 }
10853
10854 /// Walk the changed functions and variables diff nodes to categorize
10855 /// redundant nodes.
10856 void
categorize_redundant_changed_sub_nodes()10857 corpus_diff::priv::categorize_redundant_changed_sub_nodes()
10858 {
10859 diff_sptr diff;
10860
10861 diff_context_sptr ctxt = get_context();
10862
10863 ctxt->forget_visited_diffs();
10864 for (function_decl_diff_sptrs_type::const_iterator i =
10865 changed_fns_.begin();
10866 i!= changed_fns_.end();
10867 ++i)
10868 {
10869 diff = *i;
10870 categorize_redundancy(diff);
10871 }
10872
10873 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10874 i!= sorted_changed_vars_.end();
10875 ++i)
10876 {
10877 diff_sptr diff = *i;
10878 categorize_redundancy(diff);
10879 }
10880
10881 for (diff_sptrs_type::const_iterator i =
10882 changed_unreachable_types_sorted().begin();
10883 i!= changed_unreachable_types_sorted().end();
10884 ++i)
10885 {
10886 diff_sptr diff = *i;
10887 categorize_redundancy(diff);
10888 }
10889 }
10890
10891 /// Walk the changed functions and variables diff nodes and clear the
10892 /// redundancy categorization they might carry.
10893 void
clear_redundancy_categorization()10894 corpus_diff::priv::clear_redundancy_categorization()
10895 {
10896 diff_sptr diff;
10897 for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
10898 i!= changed_fns_.end();
10899 ++i)
10900 {
10901 diff = *i;
10902 abigail::comparison::clear_redundancy_categorization(diff);
10903 }
10904
10905 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10906 i!= sorted_changed_vars_.end();
10907 ++i)
10908 {
10909 diff = *i;
10910 abigail::comparison::clear_redundancy_categorization(diff);
10911 }
10912 }
10913
10914 /// If the user asked to dump the diff tree node (for changed
10915 /// variables and functions) on the error output stream, then just do
10916 /// that.
10917 ///
10918 /// This function is used for debugging purposes.
10919 void
maybe_dump_diff_tree()10920 corpus_diff::priv::maybe_dump_diff_tree()
10921 {
10922 diff_context_sptr ctxt = get_context();
10923
10924 if (!ctxt->dump_diff_tree()
10925 || ctxt->error_output_stream() == 0)
10926 return;
10927
10928 if (!changed_fns_.empty())
10929 {
10930 *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
10931 for (function_decl_diff_sptrs_type::const_iterator i =
10932 changed_fns_.begin();
10933 i != changed_fns_.end();
10934 ++i)
10935 {
10936 diff_sptr d = *i;
10937 print_diff_tree(d, *ctxt->error_output_stream());
10938 }
10939 }
10940
10941 if (!sorted_changed_vars_.empty())
10942 {
10943 *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
10944 for (var_diff_sptrs_type::const_iterator i =
10945 sorted_changed_vars_.begin();
10946 i != sorted_changed_vars_.end();
10947 ++i)
10948 {
10949 diff_sptr d = *i;
10950 print_diff_tree(d, *ctxt->error_output_stream());
10951 }
10952 }
10953
10954 if (!changed_unreachable_types_sorted().empty())
10955 {
10956 *ctxt->error_output_stream() << "\nchanged unreachable "
10957 "types diff tree: \n\n";
10958 for (vector<diff_sptr>::const_iterator i =
10959 changed_unreachable_types_sorted().begin();
10960 i != changed_unreachable_types_sorted().end();
10961 ++i)
10962 {
10963 diff_sptr d = *i;
10964 print_diff_tree(d, *ctxt->error_output_stream());
10965 }
10966 }
10967 }
10968
10969 /// Populate the vector of children node of the @ref corpus_diff type.
10970 ///
10971 /// The children node can then later be retrieved using
10972 /// corpus_diff::children_node().
10973 void
chain_into_hierarchy()10974 corpus_diff::chain_into_hierarchy()
10975 {
10976 for (function_decl_diff_sptrs_type::const_iterator i =
10977 changed_functions_sorted().begin();
10978 i != changed_functions_sorted().end();
10979 ++i)
10980 if (diff_sptr d = *i)
10981 append_child_node(d);
10982 }
10983
10984 /// Constructor for @ref corpus_diff.
10985 ///
10986 /// @param first the first corpus of the diff.
10987 ///
10988 /// @param second the second corpus of the diff.
10989 ///
10990 /// @param ctxt the diff context to use. Note that this context
10991 /// object must stay alive at least during the life time of the
10992 /// current instance of @ref corpus_diff. Otherwise memory corruption
10993 /// issues occur.
corpus_diff(corpus_sptr first,corpus_sptr second,diff_context_sptr ctxt)10994 corpus_diff::corpus_diff(corpus_sptr first,
10995 corpus_sptr second,
10996 diff_context_sptr ctxt)
10997 : priv_(new priv(first, second, ctxt))
10998 {}
10999
11000 corpus_diff::~corpus_diff() = default;
11001
11002 /// Finish building the current instance of @ref corpus_diff.
11003 void
finish_diff_type()11004 corpus_diff::finish_diff_type()
11005 {
11006 if (priv_->finished_)
11007 return;
11008 chain_into_hierarchy();
11009 priv_->finished_ = true;
11010 }
11011
11012 /// Test if logging was requested.
11013 ///
11014 /// @return true iff logging was requested.
11015 bool
do_log() const11016 corpus_diff::do_log() const
11017 {return context()->do_log();}
11018
11019 /// Request logging, or not.
11020 ///
11021 /// @param f true iff logging is requested.
11022 void
do_log(bool f)11023 corpus_diff::do_log(bool f)
11024 {context()->do_log(f);}
11025
11026 /// @return the first corpus of the diff.
11027 corpus_sptr
first_corpus() const11028 corpus_diff::first_corpus() const
11029 {return priv_->first_;}
11030
11031 /// @return the second corpus of the diff.
11032 corpus_sptr
second_corpus() const11033 corpus_diff::second_corpus() const
11034 {return priv_->second_;}
11035
11036 /// @return the children nodes of the current instance of corpus_diff.
11037 const vector<diff*>&
children_nodes() const11038 corpus_diff::children_nodes() const
11039 {return priv_->children_;}
11040
11041 /// Append a new child node to the vector of children nodes for the
11042 /// current instance of @ref corpus_diff node.
11043 ///
11044 /// Note that the vector of children nodes for the current instance of
11045 /// @ref corpus_diff node must remain sorted, using
11046 /// diff_less_than_functor.
11047 ///
11048 /// @param d the new child node. Note that the life time of the
11049 /// object held by @p d will thus equal the life time of the current
11050 /// instance of @ref corpus_diff.
11051 void
append_child_node(diff_sptr d)11052 corpus_diff::append_child_node(diff_sptr d)
11053 {
11054 ABG_ASSERT(d);
11055
11056 diff_less_than_functor is_less_than;
11057 bool inserted = false;
11058 for (vector<diff*>::iterator i = priv_->children_.begin();
11059 i != priv_->children_.end();
11060 ++i)
11061 // Look for the point where to insert the diff child node.
11062 if (!is_less_than(d.get(), *i))
11063 {
11064 context()->keep_diff_alive(d);
11065 priv_->children_.insert(i, d.get());
11066 // As we have just inserted 'd' into the vector, the iterator
11067 // 'i' is invalidated. We must *NOT* use it anymore.
11068 inserted = true;
11069 break;
11070 }
11071
11072 if (!inserted)
11073 {
11074 context()->keep_diff_alive(d);
11075 // We didn't insert anything to the vector, presumably b/c it was
11076 // empty or had one element that was "less than" 'd'. We can thus
11077 // just append 'd' to the end of the vector.
11078 priv_->children_.push_back(d.get());
11079 }
11080 }
11081
11082 /// @return the bare edit script of the functions changed as recorded
11083 /// by the diff.
11084 edit_script&
function_changes() const11085 corpus_diff::function_changes() const
11086 {return priv_->fns_edit_script_;}
11087
11088 /// @return the bare edit script of the variables changed as recorded
11089 /// by the diff.
11090 edit_script&
variable_changes() const11091 corpus_diff::variable_changes() const
11092 {return priv_->vars_edit_script_;}
11093
11094 /// Test if the soname of the underlying corpus has changed.
11095 ///
11096 /// @return true iff the soname has changed.
11097 bool
soname_changed() const11098 corpus_diff::soname_changed() const
11099 {return !priv_->sonames_equal_;}
11100
11101 /// Test if the architecture of the underlying corpus has changed.
11102 ///
11103 /// @return true iff the architecture has changed.
11104 bool
architecture_changed() const11105 corpus_diff::architecture_changed() const
11106 {return !priv_->architectures_equal_;}
11107
11108 /// Getter for the deleted functions of the diff.
11109 ///
11110 /// @return the the deleted functions of the diff.
11111 const string_function_ptr_map&
deleted_functions() const11112 corpus_diff::deleted_functions() const
11113 {return priv_->deleted_fns_;}
11114
11115 /// Getter for the added functions of the diff.
11116 ///
11117 /// @return the added functions of the diff.
11118 const string_function_ptr_map&
added_functions()11119 corpus_diff::added_functions()
11120 {return priv_->added_fns_;}
11121
11122 /// Getter for the functions which signature didn't change, but which
11123 /// do have some indirect changes in their parms.
11124 ///
11125 /// @return a non-sorted map of functions which signature didn't
11126 /// change, but which do have some indirect changes in their parms.
11127 /// The key of the map is a unique identifier for the function; it's
11128 /// usually made of the name and version of the underlying ELF symbol
11129 /// of the function for corpora that were built from ELF files.
11130 const string_function_decl_diff_sptr_map&
changed_functions()11131 corpus_diff::changed_functions()
11132 {return priv_->changed_fns_map_;}
11133
11134 /// Getter for a sorted vector of functions which signature didn't
11135 /// change, but which do have some indirect changes in their parms.
11136 ///
11137 /// @return a sorted vector of functions which signature didn't
11138 /// change, but which do have some indirect changes in their parms.
11139 const function_decl_diff_sptrs_type&
changed_functions_sorted()11140 corpus_diff::changed_functions_sorted()
11141 {return priv_->changed_fns_;}
11142
11143 /// Getter for the variables that got deleted from the first subject
11144 /// of the diff.
11145 ///
11146 /// @return the map of deleted variable.
11147 const string_var_ptr_map&
deleted_variables() const11148 corpus_diff::deleted_variables() const
11149 {return priv_->deleted_vars_;}
11150
11151 /// Getter for the added variables of the diff.
11152 ///
11153 /// @return the map of added variable.
11154 const string_var_ptr_map&
added_variables() const11155 corpus_diff::added_variables() const
11156 {return priv_->added_vars_;}
11157
11158 /// Getter for the non-sorted map of variables which signature didn't
11159 /// change but which do have some indirect changes in some sub-types.
11160 ///
11161 /// @return the non-sorted map of changed variables.
11162 const string_var_diff_sptr_map&
changed_variables()11163 corpus_diff::changed_variables()
11164 {return priv_->changed_vars_map_;}
11165
11166 /// Getter for the sorted vector of variables which signature didn't
11167 /// change but which do have some indirect changes in some sub-types.
11168 ///
11169 /// @return a sorted vector of changed variables.
11170 const var_diff_sptrs_type&
changed_variables_sorted()11171 corpus_diff::changed_variables_sorted()
11172 {return priv_->sorted_changed_vars_;}
11173
11174 /// Getter for function symbols not referenced by any debug info and
11175 /// that got deleted.
11176 ///
11177 /// @return a map of elf function symbols not referenced by any debug
11178 /// info and that got deleted.
11179 const string_elf_symbol_map&
deleted_unrefed_function_symbols() const11180 corpus_diff::deleted_unrefed_function_symbols() const
11181 {return priv_->deleted_unrefed_fn_syms_;}
11182
11183 /// Getter for function symbols not referenced by any debug info and
11184 /// that got added.
11185 ///
11186 /// @return a map of elf function symbols not referenced by any debug
11187 /// info and that got added.
11188 const string_elf_symbol_map&
added_unrefed_function_symbols() const11189 corpus_diff::added_unrefed_function_symbols() const
11190 {return priv_->added_unrefed_fn_syms_;}
11191
11192 /// Getter for variable symbols not referenced by any debug info and
11193 /// that got deleted.
11194 ///
11195 /// @return a map of elf variable symbols not referenced by any debug
11196 /// info and that got deleted.
11197 const string_elf_symbol_map&
deleted_unrefed_variable_symbols() const11198 corpus_diff::deleted_unrefed_variable_symbols() const
11199 {return priv_->deleted_unrefed_var_syms_;}
11200
11201 /// Getter for variable symbols not referenced by any debug info and
11202 /// that got added.
11203 ///
11204 /// @return a map of elf variable symbols not referenced by any debug
11205 /// info and that got added.
11206 const string_elf_symbol_map&
added_unrefed_variable_symbols() const11207 corpus_diff::added_unrefed_variable_symbols() const
11208 {return priv_->added_unrefed_var_syms_;}
11209
11210 /// Getter for a map of deleted types that are not reachable from
11211 /// global functions/variables.
11212 ///
11213 /// @return a map that associates pretty representation of deleted
11214 /// unreachable types and said types.
11215 const string_type_base_sptr_map&
deleted_unreachable_types() const11216 corpus_diff::deleted_unreachable_types() const
11217 {return priv_->deleted_unreachable_types_;}
11218
11219 /// Getter of a sorted vector of deleted types that are not reachable
11220 /// from global functions/variables.
11221 ///
11222 /// @return a sorted vector of deleted types that are not reachable
11223 /// from global functions/variables. The types are lexicographically
11224 /// sorted by considering their pretty representation.
11225 const vector<type_base_sptr>&
deleted_unreachable_types_sorted() const11226 corpus_diff::deleted_unreachable_types_sorted() const
11227 {
11228 if (priv_->deleted_unreachable_types_sorted_.empty())
11229 if (!priv_->deleted_unreachable_types_.empty())
11230 sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
11231 priv_->deleted_unreachable_types_sorted_);
11232
11233 return priv_->deleted_unreachable_types_sorted_;
11234 }
11235
11236 /// Getter for a map of added types that are not reachable from global
11237 /// functions/variables.
11238 ///
11239 /// @return a map that associates pretty representation of added
11240 /// unreachable types and said types.
11241 const string_type_base_sptr_map&
added_unreachable_types() const11242 corpus_diff::added_unreachable_types() const
11243 {return priv_->added_unreachable_types_;}
11244
11245 /// Getter of a sorted vector of added types that are not reachable
11246 /// from global functions/variables.
11247 ///
11248 /// @return a sorted vector of added types that are not reachable from
11249 /// global functions/variables. The types are lexicographically
11250 /// sorted by considering their pretty representation.
11251 const vector<type_base_sptr>&
added_unreachable_types_sorted() const11252 corpus_diff::added_unreachable_types_sorted() const
11253 {
11254 if (priv_->added_unreachable_types_sorted_.empty())
11255 if (!priv_->added_unreachable_types_.empty())
11256 sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
11257 priv_->added_unreachable_types_sorted_);
11258
11259 return priv_->added_unreachable_types_sorted_;
11260 }
11261
11262 /// Getter for a map of changed types that are not reachable from
11263 /// global functions/variables.
11264 ///
11265 /// @return a map that associates pretty representation of changed
11266 /// unreachable types and said types.
11267 const string_diff_sptr_map&
changed_unreachable_types() const11268 corpus_diff::changed_unreachable_types() const
11269 {return priv_->changed_unreachable_types_;}
11270
11271 /// Getter of a sorted vector of changed types that are not reachable
11272 /// from global functions/variables.
11273 ///
11274 /// @return a sorted vector of changed types that are not reachable
11275 /// from global functions/variables. The diffs are lexicographically
11276 /// sorted by considering their pretty representation.
11277 const vector<diff_sptr>&
changed_unreachable_types_sorted() const11278 corpus_diff::changed_unreachable_types_sorted() const
11279 {return priv_->changed_unreachable_types_sorted();}
11280
11281 /// Getter of the diff context of this diff
11282 ///
11283 /// @return the diff context for this diff.
11284 const diff_context_sptr
context() const11285 corpus_diff::context() const
11286 {return priv_->get_context();}
11287
11288 /// @return the pretty representation for the current instance of @ref
11289 /// corpus_diff
11290 const string&
get_pretty_representation() const11291 corpus_diff::get_pretty_representation() const
11292 {
11293 if (priv_->pretty_representation_.empty())
11294 {
11295 std::ostringstream o;
11296 o << "corpus_diff["
11297 << first_corpus()->get_path()
11298 << ", "
11299 << second_corpus()->get_path()
11300 << "]";
11301 priv_->pretty_representation_ = o.str();
11302 }
11303 return priv_->pretty_representation_;
11304 }
11305 /// Return true iff the current @ref corpus_diff node carries a
11306 /// change.
11307 ///
11308 /// @return true iff the current diff node carries a change.
11309 bool
has_changes() const11310 corpus_diff::has_changes() const
11311 {
11312 return (soname_changed()
11313 || architecture_changed()
11314 || !(priv_->deleted_fns_.empty()
11315 && priv_->added_fns_.empty()
11316 && priv_->changed_fns_map_.empty()
11317 && priv_->deleted_vars_.empty()
11318 && priv_->added_vars_.empty()
11319 && priv_->changed_vars_map_.empty()
11320 && priv_->added_unrefed_fn_syms_.empty()
11321 && priv_->deleted_unrefed_fn_syms_.empty()
11322 && priv_->added_unrefed_var_syms_.empty()
11323 && priv_->deleted_unrefed_var_syms_.empty()
11324 && priv_->deleted_unreachable_types_.empty()
11325 && priv_->added_unreachable_types_.empty()
11326 && priv_->changed_unreachable_types_.empty()));
11327 }
11328
11329 /// Test if the current instance of @ref corpus_diff carries changes
11330 /// that we are sure are incompatible. By incompatible change we mean
11331 /// a change that "breaks" the ABI of the corpus we are looking at.
11332 ///
11333 /// In concrete terms, this function considers the following changes
11334 /// as being ABI incompatible for sure:
11335 ///
11336 /// - a soname change
11337 /// - if exported functions or variables got removed
11338 ///
11339 /// Note that subtype changes *can* represent changes that break ABI
11340 /// too. But they also can be changes that are OK, ABI-wise.
11341 ///
11342 /// It's up to the user to provide suppression specifications to say
11343 /// explicitely which subtype change is OK. The remaining sub-type
11344 /// changes are then considered to be ABI incompatible. But to test
11345 /// if such ABI incompatible subtype changes are present you need to
11346 /// use the function @ref corpus_diff::has_net_subtype_changes()
11347 ///
11348 /// @return true iff the current instance of @ref corpus_diff carries
11349 /// changes that we are sure are ABI incompatible.
11350 bool
has_incompatible_changes() const11351 corpus_diff::has_incompatible_changes() const
11352 {
11353 const diff_stats& stats = const_cast<corpus_diff*>(this)->
11354 apply_filters_and_suppressions_before_reporting();
11355
11356 bool has_incompatible_changes =
11357 (soname_changed() || architecture_changed()
11358 || stats.net_num_func_removed() != 0
11359 || (stats.num_func_with_virtual_offset_changes() != 0
11360 // If all reports about functions with sub-type changes
11361 // have been suppressed, then even those about functions
11362 // that are virtual don't matter anymore because the
11363 // user willingly requested to shut them down
11364 && stats.net_num_func_changed() != 0)
11365 || stats.net_num_vars_removed() != 0
11366 || stats.net_num_removed_func_syms() != 0
11367 || stats.net_num_removed_var_syms() != 0
11368 || stats.net_num_removed_unreachable_types() != 0);
11369
11370 // If stats.net_num_changed_unreachable_types() != 0 then walk the
11371 // corpus_diff::priv::changed_unreachable_types_, and see if there
11372 // is one that is harmful by bitwise and-ing their category with
11373 // abigail::comparison::get_default_harmful_categories_bitmap().
11374 if (!has_incompatible_changes
11375 && stats.net_num_changed_unreachable_types())
11376 {
11377 // The changed unreachable types can carry harmful changes.
11378 // Let's figure if they actually do.
11379
11380 diff_context_sptr ctxt = context();
11381 for (auto &entry : priv_->changed_unreachable_types())
11382 {
11383 diff_sptr dif = entry.second;
11384
11385 // Let's see if any of the categories of this diff node
11386 // belong to the "harmful" ones.
11387 if (dif->get_category() & get_default_harmful_categories_bitmap())
11388 {
11389 has_incompatible_changes |= true;
11390 break;
11391 }
11392 }
11393 }
11394
11395 return has_incompatible_changes;
11396 }
11397
11398 /// Test if the current instance of @ref corpus_diff carries subtype
11399 /// changes whose reports are not suppressed by any suppression
11400 /// specification. In effect, these are deemed incompatible ABI
11401 /// changes.
11402 ///
11403 /// @return true iff the the current instance of @ref corpus_diff
11404 /// carries subtype changes that are deemed incompatible ABI changes.
11405 bool
has_net_subtype_changes() const11406 corpus_diff::has_net_subtype_changes() const
11407 {
11408 const diff_stats& stats = const_cast<corpus_diff*>(this)->
11409 apply_filters_and_suppressions_before_reporting();
11410
11411 return (stats.net_num_func_changed() != 0
11412 || stats.net_num_vars_changed() != 0
11413 || stats.net_num_removed_unreachable_types() != 0
11414 || stats.net_num_changed_unreachable_types() != 0);
11415 }
11416
11417 /// Test if the current instance of @ref corpus_diff carries changes
11418 /// whose reports are not suppressed by any suppression specification.
11419 /// In effect, these are deemed incompatible ABI changes.
11420 ///
11421 /// @return true iff the the current instance of @ref corpus_diff
11422 /// carries subtype changes that are deemed incompatible ABI changes.
11423 bool
has_net_changes() const11424 corpus_diff::has_net_changes() const
11425 {return context()->get_reporter()->diff_has_net_changes(this);}
11426
11427 /// Apply the different filters that are registered to be applied to
11428 /// the diff tree; that includes the categorization filters. Also,
11429 /// apply the suppression interpretation filters.
11430 ///
11431 /// After the filters are applied, this function calculates some
11432 /// statistics about the changes carried by the current instance of
11433 /// @ref corpus_diff. These statistics are represented by an instance
11434 /// of @ref corpus_diff::diff_stats.
11435 ///
11436 /// This member function is called by the reporting function
11437 /// corpus_diff::report().
11438 ///
11439 /// Note that for a given instance of corpus_diff, this function
11440 /// applies the filters and suppressions only the first time it is
11441 /// invoked. Subsequent invocations just return the instance of
11442 /// corpus_diff::diff_stats that was cached after the first
11443 /// invocation.
11444 ///
11445 /// @return a reference to the statistics about the changes carried by
11446 /// the current instance of @ref corpus_diff.
11447 const corpus_diff::diff_stats&
apply_filters_and_suppressions_before_reporting()11448 corpus_diff::apply_filters_and_suppressions_before_reporting()
11449 {
11450 if (priv_->diff_stats_)
11451 return *priv_->diff_stats_;
11452
11453 tools_utils::timer t;
11454 if (do_log())
11455 {
11456 std::cerr << "Applying suppressions ...\n";
11457 t.start();
11458 }
11459
11460 apply_suppressions(this);
11461
11462 if (do_log())
11463 {
11464 t.stop();
11465 std::cerr << "suppressions applied!:" << t << "\n";
11466 }
11467
11468 priv_->diff_stats_.reset(new diff_stats(context()));
11469
11470 if (do_log())
11471 {
11472 std::cerr << "Marking leaf nodes ...\n";
11473 t.start();
11474 }
11475
11476 mark_leaf_diff_nodes();
11477
11478 if (do_log())
11479 {
11480 t.stop();
11481 std::cerr << "leaf nodes marked!:" << t << "\n";
11482 std::cerr << "Applying filters and computing diff stats ...\n";
11483 t.start();
11484 }
11485
11486 priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
11487
11488 if (do_log())
11489 {
11490 t.stop();
11491 std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
11492 }
11493
11494 return *priv_->diff_stats_;
11495 }
11496
11497 /// A visitor that marks leaf diff nodes by storing them in the
11498 /// instance of @ref diff_maps returned by
11499 /// corpus_diff::get_leaf_diffs() invoked on the current instance of
11500 /// corpus_diff.
11501 struct leaf_diff_node_marker_visitor : public diff_node_visitor
11502 {
11503 /// This is called when the visitor visits a diff node.
11504 ///
11505 /// It basically tests if the diff node being visited is a leaf diff
11506 /// node - that is, it contains local changes. If it does, then the
11507 /// node is added to the set of maps that hold leaf diffs in the
11508 /// current corpus_diff.
11509 ///
11510 /// Note that only leaf nodes that are reachable from public
11511 /// interfaces (global functions or variables) are collected by this
11512 /// visitor.
11513 ///
11514 /// @param d the diff node being visited.
11515 virtual void
visit_beginabigail::comparison::leaf_diff_node_marker_visitor11516 visit_begin(diff *d)
11517 {
11518 if (d->has_local_changes()
11519 // A leaf basic (or class/union) type name change makes no
11520 // sense when showing just leaf changes. It only makes sense
11521 // when it can explain the details about a non-leaf change.
11522 // In other words, it doesn't make sense to say that an "int"
11523 // became "unsigned int". But it does make sense to say that
11524 // a typedef changed because its underlying type was 'int' and
11525 // is now an "unsigned int".
11526 && !filtering::has_basic_or_class_type_name_change(d)
11527 // Similarly, a *local* change describing a type that changed
11528 // its nature doesn't make sense.
11529 && !is_distinct_diff(d)
11530 // Similarly, a pointer (or reference or array), a typedef or
11531 // qualified type change in itself doesn't make sense. It
11532 // would rather make sense to show that pointer change as part
11533 // of the variable change whose pointer type changed, for
11534 // instance.
11535 && !is_pointer_diff(d)
11536 && !is_reference_diff(d)
11537 && !is_qualified_type_diff(d)
11538 && !is_typedef_diff(d)
11539 && !is_array_diff(d)
11540 // Similarly a parameter change in itself doesn't make sense.
11541 // It should have already been reported as part of the change
11542 // of the function it belongs to.
11543 && !is_fn_parm_diff(d)
11544 // An anonymous class or union diff doesn't make sense on its
11545 // own. It must have been described already by the diff of
11546 // the enclosing struct or union if 'd' is from an anonymous
11547 // data member, or from a typedef change if 'd' is from a
11548 // typedef change which underlying type is an anonymous
11549 // struct/union.
11550 && !is_anonymous_class_or_union_diff(d)
11551 // Don't show decl-only-ness changes either.
11552 && !filtering::has_decl_only_def_change(d)
11553 // Sometime, we can encounter artifacts of bogus DWARF that
11554 // yield a diff node for a decl-only class (and empty class
11555 // with the is_declaration flag set) that carries a non-zero
11556 // size! And of course at some point that non-zero size
11557 // changes. We need to be able to detect that.
11558 && !filtering::is_decl_only_class_with_size_change(d))
11559 {
11560 diff_context_sptr ctxt = d->context();
11561 const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
11562 ABG_ASSERT(corpus_diff_node);
11563
11564 if (diff *iface_diff = get_current_topmost_iface_diff())
11565 {
11566 type_or_decl_base_sptr iface = iface_diff->first_subject();
11567 // So, this diff node that is reachable from a global
11568 // function or variable carries a leaf change. Let's add
11569 // it to the set of of leaf diffs of corpus_diff_node.
11570 const_cast<corpus_diff*>(corpus_diff_node)->
11571 get_leaf_diffs().insert_diff_node(d, iface);
11572 }
11573 }
11574 }
11575 }; // end struct leaf_diff_node_marker_visitor
11576
11577 /// Walks the diff nodes associated to the current corpus diff and
11578 /// mark those that carry local changes. They are said to be leaf
11579 /// diff nodes.
11580 ///
11581 /// The marked nodes are available from the
11582 /// corpus_diff::get_leaf_diffs() function.
11583 void
mark_leaf_diff_nodes()11584 corpus_diff::mark_leaf_diff_nodes()
11585 {
11586 if (!has_changes())
11587 return;
11588
11589 if (!context()->show_leaf_changes_only())
11590 return;
11591
11592 leaf_diff_node_marker_visitor v;
11593 context()->forget_visited_diffs();
11594 bool s = context()->visiting_a_node_twice_is_forbidden();
11595 context()->forbid_visiting_a_node_twice(true);
11596 if (context()->show_impacted_interfaces())
11597 context()->forbid_visiting_a_node_twice_per_interface(true);
11598 traverse(v);
11599 context()->forbid_visiting_a_node_twice(s);
11600 context()->forbid_visiting_a_node_twice_per_interface(false);
11601 }
11602
11603 /// Get the set of maps that contain leaf nodes. A leaf node being a
11604 /// node with a local change.
11605 ///
11606 /// @return the set of maps that contain leaf nodes. A leaf node
11607 /// being a node with a local change.
11608 diff_maps&
get_leaf_diffs()11609 corpus_diff::get_leaf_diffs()
11610 {return priv_->leaf_diffs_;}
11611
11612 /// Get the set of maps that contain leaf nodes. A leaf node being a
11613 /// node with a local change.
11614 ///
11615 /// @return the set of maps that contain leaf nodes. A leaf node
11616 /// being a node with a local change.
11617 const diff_maps&
get_leaf_diffs() const11618 corpus_diff::get_leaf_diffs() const
11619 {return priv_->leaf_diffs_;}
11620
11621 /// Report the diff in a serialized form.
11622 ///
11623 /// @param out the stream to serialize the diff to.
11624 ///
11625 /// @param indent the prefix to use for the indentation of this
11626 /// serialization.
11627 void
report(ostream & out,const string & indent) const11628 corpus_diff::report(ostream& out, const string& indent) const
11629 {
11630 context()->get_reporter()->report(*this, out, indent);
11631 }
11632
11633 /// Traverse the diff sub-tree under the current instance corpus_diff.
11634 ///
11635 /// @param v the visitor to invoke on each diff node of the sub-tree.
11636 ///
11637 /// @return true if the traversing has to keep going on, false otherwise.
11638 bool
traverse(diff_node_visitor & v)11639 corpus_diff::traverse(diff_node_visitor& v)
11640 {
11641 finish_diff_type();
11642
11643 v.visit_begin(this);
11644
11645 if (!v.visit(this, true))
11646 {
11647 v.visit_end(this);
11648 return false;
11649 }
11650
11651 for (function_decl_diff_sptrs_type::const_iterator i =
11652 changed_functions_sorted().begin();
11653 i != changed_functions_sorted().end();
11654 ++i)
11655 {
11656 if (diff_sptr d = *i)
11657 {
11658 const diff_context_sptr &ctxt = context();
11659 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11660 ctxt->forget_visited_diffs();
11661
11662 v.set_current_topmost_iface_diff(d.get());
11663
11664 if (!d->traverse(v))
11665 {
11666 v.visit_end(this);
11667 v.set_current_topmost_iface_diff(0);
11668 return false;
11669 }
11670 }
11671 }
11672
11673 for (var_diff_sptrs_type::const_iterator i =
11674 changed_variables_sorted().begin();
11675 i != changed_variables_sorted().end();
11676 ++i)
11677 {
11678 if (diff_sptr d = *i)
11679 {
11680 const diff_context_sptr &ctxt = context();
11681 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11682 ctxt->forget_visited_diffs();
11683
11684 v.set_current_topmost_iface_diff(d.get());
11685
11686 if (!d->traverse(v))
11687 {
11688 v.visit_end(this);
11689 v.set_current_topmost_iface_diff(0);
11690 return false;
11691 }
11692 }
11693 }
11694
11695 v.set_current_topmost_iface_diff(0);
11696
11697 // Traverse the changed unreachable type diffs. These diffs are on
11698 // types that are not reachable from global functions or variables.
11699 for (vector<diff_sptr>::const_iterator i =
11700 changed_unreachable_types_sorted().begin();
11701 i != changed_unreachable_types_sorted().end();
11702 ++i)
11703 {
11704 if (diff_sptr d = *i)
11705 {
11706 const diff_context_sptr &ctxt = context();
11707 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11708 ctxt->forget_visited_diffs();
11709
11710 if (!d->traverse(v))
11711 {
11712 v.visit_end(this);
11713 return false;
11714 }
11715 }
11716 }
11717
11718 v.visit_end(this);
11719 return true;
11720 }
11721
11722 /// Compute the diff between two instances of @ref corpus.
11723 ///
11724 /// Note that the two corpora must have been created in the same @ref
11725 /// environment, otherwise, this function aborts.
11726 ///
11727 /// @param f the first @ref corpus to consider for the diff.
11728 ///
11729 /// @param s the second @ref corpus to consider for the diff.
11730 ///
11731 /// @param ctxt the diff context to use.
11732 ///
11733 /// @return the resulting diff between the two @ref corpus.
11734 corpus_diff_sptr
compute_diff(const corpus_sptr f,const corpus_sptr s,diff_context_sptr ctxt)11735 compute_diff(const corpus_sptr f,
11736 const corpus_sptr s,
11737 diff_context_sptr ctxt)
11738 {
11739 typedef corpus::functions::const_iterator fns_it_type;
11740 typedef corpus::variables::const_iterator vars_it_type;
11741 typedef elf_symbols::const_iterator symbols_it_type;
11742 typedef diff_utils::deep_ptr_eq_functor eq_type;
11743 typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
11744
11745 ABG_ASSERT(f && s);
11746
11747 if (!ctxt)
11748 ctxt.reset(new diff_context);
11749
11750 corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
11751
11752 ctxt->set_corpus_diff(r);
11753
11754 if(ctxt->show_soname_change())
11755 r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
11756 else
11757 r->priv_->sonames_equal_ = true;
11758
11759 r->priv_->architectures_equal_ =
11760 f->get_architecture_name() == s->get_architecture_name();
11761
11762 // Compute the diff of publicly defined and exported functions
11763 diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
11764 f->get_functions().end(),
11765 s->get_functions().begin(),
11766 s->get_functions().end(),
11767 r->priv_->fns_edit_script_);
11768
11769 // Compute the diff of publicly defined and exported variables.
11770 diff_utils::compute_diff<vars_it_type, eq_type>
11771 (f->get_variables().begin(), f->get_variables().end(),
11772 s->get_variables().begin(), s->get_variables().end(),
11773 r->priv_->vars_edit_script_);
11774
11775 // Compute the diff of function elf symbols not referenced by debug
11776 // info.
11777 diff_utils::compute_diff<symbols_it_type, eq_type>
11778 (f->get_unreferenced_function_symbols().begin(),
11779 f->get_unreferenced_function_symbols().end(),
11780 s->get_unreferenced_function_symbols().begin(),
11781 s->get_unreferenced_function_symbols().end(),
11782 r->priv_->unrefed_fn_syms_edit_script_);
11783
11784 // Compute the diff of variable elf symbols not referenced by debug
11785 // info.
11786 diff_utils::compute_diff<symbols_it_type, eq_type>
11787 (f->get_unreferenced_variable_symbols().begin(),
11788 f->get_unreferenced_variable_symbols().end(),
11789 s->get_unreferenced_variable_symbols().begin(),
11790 s->get_unreferenced_variable_symbols().end(),
11791 r->priv_->unrefed_var_syms_edit_script_);
11792
11793 if (ctxt->show_unreachable_types())
11794 // Compute the diff of types not reachable from public functions
11795 // or global variables that are exported.
11796 diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
11797 (f->get_types_not_reachable_from_public_interfaces().begin(),
11798 f->get_types_not_reachable_from_public_interfaces().end(),
11799 s->get_types_not_reachable_from_public_interfaces().begin(),
11800 s->get_types_not_reachable_from_public_interfaces().end(),
11801 r->priv_->unreachable_types_edit_script_);
11802
11803 r->priv_->ensure_lookup_tables_populated();
11804
11805 return r;
11806 }
11807
11808 // </corpus stuff>
11809
11810 /// Compute the diff between two instances of @ref corpus_group.
11811 ///
11812 /// Note that the two corpus_diff must have been created in the same
11813 /// @ref environment, otherwise, this function aborts.
11814 ///
11815 /// @param f the first @ref corpus_group to consider for the diff.
11816 ///
11817 /// @param s the second @ref corpus_group to consider for the diff.
11818 ///
11819 /// @param ctxt the diff context to use.
11820 ///
11821 /// @return the resulting diff between the two @ref corpus_group.
11822 corpus_diff_sptr
compute_diff(const corpus_group_sptr & f,const corpus_group_sptr & s,diff_context_sptr ctxt)11823 compute_diff(const corpus_group_sptr& f,
11824 const corpus_group_sptr& s,
11825 diff_context_sptr ctxt)
11826 {
11827
11828 corpus_sptr c1 = f;
11829 corpus_sptr c2 = s;
11830
11831 return compute_diff(c1, c2, ctxt);
11832 }
11833
11834 // <corpus_group stuff>
11835
11836 // </corpus_group stuff>
11837 // <diff_node_visitor stuff>
11838
11839 /// The private data of the @diff_node_visitor type.
11840 struct diff_node_visitor::priv
11841 {
11842 diff* topmost_interface_diff;
11843 visiting_kind kind;
11844
privabigail::comparison::diff_node_visitor::priv11845 priv()
11846 : topmost_interface_diff(),
11847 kind()
11848 {}
11849
privabigail::comparison::diff_node_visitor::priv11850 priv(visiting_kind k)
11851 : topmost_interface_diff(),
11852 kind(k)
11853 {}
11854 }; // end struct diff_node_visitor
11855
11856 /// Default constructor of the @ref diff_node_visitor type.
diff_node_visitor()11857 diff_node_visitor::diff_node_visitor()
11858 : priv_(new priv)
11859 {}
11860
11861 diff_node_visitor::~diff_node_visitor() = default;
11862
11863 /// Constructor of the @ref diff_node_visitor type.
11864 ///
11865 /// @param k how the visiting has to be performed.
diff_node_visitor(visiting_kind k)11866 diff_node_visitor::diff_node_visitor(visiting_kind k)
11867 : priv_(new priv(k))
11868 {}
11869
11870 /// Getter for the visiting policy of the traversing code while
11871 /// invoking this visitor.
11872 ///
11873 /// @return the visiting policy used by the traversing code when
11874 /// invoking this visitor.
11875 visiting_kind
get_visiting_kind() const11876 diff_node_visitor::get_visiting_kind() const
11877 {return priv_->kind;}
11878
11879 /// Setter for the visiting policy of the traversing code while
11880 /// invoking this visitor.
11881 ///
11882 /// @param v a bit map representing the new visiting policy used by
11883 /// the traversing code when invoking this visitor.
11884 void
set_visiting_kind(visiting_kind v)11885 diff_node_visitor::set_visiting_kind(visiting_kind v)
11886 {priv_->kind = v;}
11887
11888 /// Setter for the visiting policy of the traversing code while
11889 /// invoking this visitor. This one makes a logical or between the
11890 /// current policy and the bitmap given in argument and assigns the
11891 /// current policy to the result.
11892 ///
11893 /// @param v a bitmap representing the visiting policy to or with
11894 /// the current policy.
11895 void
or_visiting_kind(visiting_kind v)11896 diff_node_visitor::or_visiting_kind(visiting_kind v)
11897 {priv_->kind = priv_->kind | v;}
11898
11899 /// Setter of the diff current topmost interface which is impacted by
11900 /// the current diff node being visited.
11901 ///
11902 /// @param d the current topmost interface diff impacted.
11903 void
set_current_topmost_iface_diff(diff * d)11904 diff_node_visitor::set_current_topmost_iface_diff(diff* d)
11905 {priv_->topmost_interface_diff = d;}
11906
11907 /// Getter of the diff current topmost interface which is impacted by
11908 /// the current diff node being visited.
11909 ///
11910 /// @return the current topmost interface diff impacted.
11911 diff*
get_current_topmost_iface_diff() const11912 diff_node_visitor::get_current_topmost_iface_diff() const
11913 {return priv_->topmost_interface_diff;}
11914
11915 /// This is called by the traversing code on a @ref diff node just
11916 /// before visiting it. That is, before visiting it and its children
11917 /// node.
11918 ///
11919 /// @param d the diff node to visit.
11920 void
visit_begin(diff *)11921 diff_node_visitor::visit_begin(diff* /*p*/)
11922 {}
11923
11924 /// This is called by the traversing code on a @ref diff node just
11925 /// after visiting it. That is after visiting it and its children
11926 /// nodes.
11927 ///
11928 /// @param d the diff node that got visited.
11929 void
visit_end(diff *)11930 diff_node_visitor::visit_end(diff* /*p*/)
11931 {}
11932
11933 /// This is called by the traversing code on a @ref corpus_diff node
11934 /// just before visiting it. That is, before visiting it and its
11935 /// children node.
11936 ///
11937 /// @param p the corpus_diff node to visit.
11938 ///
11939 void
visit_begin(corpus_diff *)11940 diff_node_visitor::visit_begin(corpus_diff* /*p*/)
11941 {}
11942
11943 /// This is called by the traversing code on a @ref corpus_diff node
11944 /// just after visiting it. That is after visiting it and its children
11945 /// nodes.
11946 ///
11947 /// @param d the diff node that got visited.
11948 void
visit_end(corpus_diff *)11949 diff_node_visitor::visit_end(corpus_diff* /*d*/)
11950 {}
11951
11952 /// Default visitor implementation
11953 ///
11954 /// @return true
11955 bool
visit(diff *,bool)11956 diff_node_visitor::visit(diff*, bool)
11957 {return true;}
11958
11959 /// Default visitor implementation.
11960 ///
11961 /// @return true
11962 bool
visit(distinct_diff * dif,bool pre)11963 diff_node_visitor::visit(distinct_diff* dif, bool pre)
11964 {
11965 diff* d = dif;
11966 visit(d, pre);
11967
11968 return true;
11969 }
11970
11971 /// Default visitor implementation.
11972 ///
11973 /// @return true
11974 bool
visit(var_diff * dif,bool pre)11975 diff_node_visitor::visit(var_diff* dif, bool pre)
11976 {
11977 diff* d = dif;
11978 visit(d, pre);
11979
11980 return true;
11981 }
11982
11983 /// Default visitor implementation.
11984 ///
11985 /// @return true
11986 bool
visit(pointer_diff * dif,bool pre)11987 diff_node_visitor::visit(pointer_diff* dif, bool pre)
11988 {
11989 diff* d = dif;
11990 visit(d, pre);
11991
11992 return true;
11993 }
11994
11995 /// Default visitor implementation.
11996 ///
11997 /// @return true
11998 bool
visit(reference_diff * dif,bool pre)11999 diff_node_visitor::visit(reference_diff* dif, bool pre)
12000 {
12001 diff* d = dif;
12002 visit(d, pre);
12003
12004 return true;
12005 }
12006
12007 /// Default visitor implementation.
12008 ///
12009 /// @return true
12010 bool
visit(qualified_type_diff * dif,bool pre)12011 diff_node_visitor::visit(qualified_type_diff* dif, bool pre)
12012 {
12013 diff* d = dif;
12014 visit(d, pre);
12015
12016 return true;
12017 }
12018
12019 /// Default visitor implementation.
12020 ///
12021 /// @return true
12022 bool
visit(enum_diff * dif,bool pre)12023 diff_node_visitor::visit(enum_diff* dif, bool pre)
12024 {
12025 diff* d = dif;
12026 visit(d, pre);
12027
12028 return true;
12029 }
12030
12031 /// Default visitor implementation.
12032 ///
12033 /// @return true
12034 bool
visit(class_diff * dif,bool pre)12035 diff_node_visitor::visit(class_diff* dif, bool pre)
12036 {
12037 diff* d = dif;
12038 visit(d, pre);
12039
12040 return true;
12041 }
12042
12043 /// Default visitor implementation.
12044 ///
12045 /// @return true
12046 bool
visit(base_diff * dif,bool pre)12047 diff_node_visitor::visit(base_diff* dif, bool pre)
12048 {
12049 diff* d = dif;
12050 visit(d, pre);
12051
12052 return true;
12053 }
12054
12055 /// Default visitor implementation.
12056 ///
12057 /// @return true
12058 bool
visit(scope_diff * dif,bool pre)12059 diff_node_visitor::visit(scope_diff* dif, bool pre)
12060 {
12061 diff* d = dif;
12062 visit(d, pre);
12063
12064 return true;
12065 }
12066
12067 /// Default visitor implementation.
12068 ///
12069 /// @return true
12070 bool
visit(function_decl_diff * dif,bool pre)12071 diff_node_visitor::visit(function_decl_diff* dif, bool pre)
12072 {
12073 diff* d = dif;
12074 visit(d, pre);
12075
12076 return true;
12077 }
12078
12079 /// Default visitor implementation.
12080 ///
12081 /// @return true
12082 bool
visit(type_decl_diff * dif,bool pre)12083 diff_node_visitor::visit(type_decl_diff* dif, bool pre)
12084 {
12085 diff* d = dif;
12086 visit(d, pre);
12087
12088 return true;
12089 }
12090
12091 /// Default visitor implementation.
12092 ///
12093 /// @return true
12094 bool
visit(typedef_diff * dif,bool pre)12095 diff_node_visitor::visit(typedef_diff* dif, bool pre)
12096 {
12097 diff* d = dif;
12098 visit(d, pre);
12099
12100 return true;
12101 }
12102
12103 /// Default visitor implementation.
12104 ///
12105 /// @return true
12106 bool
visit(translation_unit_diff * dif,bool pre)12107 diff_node_visitor::visit(translation_unit_diff* dif, bool pre)
12108 {
12109 diff* d = dif;
12110 visit(d, pre);
12111
12112 return true;
12113 }
12114
12115 /// Default visitor implementation.
12116 ///
12117 /// @return true
12118 bool
visit(corpus_diff *,bool)12119 diff_node_visitor::visit(corpus_diff*, bool)
12120 {return true;}
12121
12122 // </diff_node_visitor stuff>
12123
12124 // <redundant diff node marking>
12125
12126 // </redundant diff node marking>
12127
12128 // <diff tree category propagation>
12129
12130 /// A visitor to propagate the category of a node up to its parent
12131 /// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
12132 /// SUPPRESSED_CATEGORY because those are propagated using other
12133 /// specific visitors.
12134 struct category_propagation_visitor : public diff_node_visitor
12135 {
12136 virtual void
visit_endabigail::comparison::category_propagation_visitor12137 visit_end(diff* d)
12138 {
12139 // Has this diff node 'd' been already visited ?
12140 bool already_visited = d->context()->diff_has_been_visited(d);
12141
12142 // The canonical diff node of the class of equivalence of the diff
12143 // node 'd'.
12144 diff* canonical = d->get_canonical_diff();
12145
12146 // If this class of equivalence of diff node is being visited for
12147 // the first time, then update its canonical node's category too.
12148 bool update_canonical = !already_visited && canonical;
12149
12150 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12151 i != d->children_nodes().end();
12152 ++i)
12153 {
12154 // If we are visiting the class of equivalence of 'd' for the
12155 // first time, then let's look at the children of 'd' and
12156 // propagate their categories to 'd'.
12157 //
12158 // If the class of equivalence of 'd' has already been
12159 // visited, then let's look at the canonical diff nodes of the
12160 // children of 'd' and propagate their categories to 'd'.
12161 diff* diff = already_visited
12162 ? (*i)->get_canonical_diff()
12163 : *i;
12164
12165 ABG_ASSERT(diff);
12166
12167 diff_category c = diff->get_category();
12168 // Do not propagate redundant and suppressed categories. Those
12169 // are propagated in a specific pass elsewhere.
12170 c &= ~(REDUNDANT_CATEGORY
12171 | SUPPRESSED_CATEGORY
12172 | PRIVATE_TYPE_CATEGORY
12173 | HAS_ALLOWED_CHANGE_CATEGORY
12174 | HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
12175 | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
12176 // Also, if a (class) type has got a harmful name change, do not
12177 // propagate harmless name changes coming from its sub-types
12178 // (i.e, data members) to the class itself.
12179 if (filtering::has_harmful_name_change(d))
12180 c &= ~HARMLESS_DECL_NAME_CHANGE_CATEGORY;
12181
12182 d->add_to_category(c);
12183 if (!already_visited && canonical)
12184 if (update_canonical)
12185 canonical->add_to_category(c);
12186 }
12187 }
12188 };// end struct category_propagation_visitor
12189
12190 /// Visit all the nodes of a given sub-tree. For each node that has a
12191 /// particular category set, propagate that category set up to its
12192 /// parent nodes.
12193 ///
12194 /// @param diff_tree the diff sub-tree to walk for categorization
12195 /// purpose;
12196 void
propagate_categories(diff * diff_tree)12197 propagate_categories(diff* diff_tree)
12198 {
12199 category_propagation_visitor v;
12200 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12201 diff_tree->context()->forbid_visiting_a_node_twice(true);
12202 diff_tree->context()->forget_visited_diffs();
12203 diff_tree->traverse(v);
12204 diff_tree->context()->forbid_visiting_a_node_twice(s);
12205 }
12206
12207 /// Visit all the nodes of a given sub-tree. For each node that has a
12208 /// particular category set, propagate that category set up to its
12209 /// parent nodes.
12210 ///
12211 /// @param diff_tree the diff sub-tree to walk for categorization
12212 /// purpose;
12213 void
propagate_categories(diff_sptr diff_tree)12214 propagate_categories(diff_sptr diff_tree)
12215 {propagate_categories(diff_tree.get());}
12216
12217 /// Visit all the nodes of a given corpus tree. For each node that
12218 /// has a particular category set, propagate that category set up to
12219 /// its parent nodes.
12220 ///
12221 /// @param diff_tree the corpus_diff tree to walk for categorization
12222 /// purpose;
12223 void
propagate_categories(corpus_diff * diff_tree)12224 propagate_categories(corpus_diff* diff_tree)
12225 {
12226 category_propagation_visitor v;
12227 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12228 diff_tree->context()->forbid_visiting_a_node_twice(false);
12229 diff_tree->traverse(v);
12230 diff_tree->context()->forbid_visiting_a_node_twice(s);
12231 }
12232
12233 /// Visit all the nodes of a given corpus tree. For each node that
12234 /// has a particular category set, propagate that category set up to
12235 /// its parent nodes.
12236 ///
12237 /// @param diff_tree the corpus_diff tree to walk for categorization
12238 /// purpose;
12239 void
propagate_categories(corpus_diff_sptr diff_tree)12240 propagate_categories(corpus_diff_sptr diff_tree)
12241 {propagate_categories(diff_tree.get());}
12242
12243 /// A tree node visitor that knows how to categorizes a given diff
12244 /// node in the SUPPRESSED_CATEGORY category and how to propagate that
12245 /// categorization.
12246 struct suppression_categorization_visitor : public diff_node_visitor
12247 {
12248
12249 /// Before visiting the children of the diff node, check if the node
12250 /// is suppressed by a suppression specification. If it is, mark
12251 /// the node as belonging to the SUPPRESSED_CATEGORY category.
12252 ///
12253 /// @param p the diff node to visit.
12254 virtual void
visit_beginabigail::comparison::suppression_categorization_visitor12255 visit_begin(diff* d)
12256 {
12257 bool is_private_type = false;
12258 if (d->is_suppressed(is_private_type))
12259 {
12260 diff_category c = is_private_type
12261 ? PRIVATE_TYPE_CATEGORY
12262 : SUPPRESSED_CATEGORY;
12263 d->add_to_local_and_inherited_categories(c);
12264
12265 // If a node was suppressed, all the other nodes of its class
12266 // of equivalence are suppressed too.
12267 diff *canonical_diff = d->get_canonical_diff();
12268 if (canonical_diff != d)
12269 canonical_diff->add_to_category(c);
12270 }
12271 else if (d->is_allowed_by_specific_negated_suppression())
12272 {
12273 // This diff node is specifically allowed by a
12274 // negated_suppression, then mark it as being in the
12275 // HAS_ALLOWED_CHANGE_CATEGORY.
12276 diff_category c = HAS_ALLOWED_CHANGE_CATEGORY;
12277 d->add_to_local_category(c);
12278 diff *canonical_diff = d->get_canonical_diff();
12279 canonical_diff->add_to_category(c);
12280
12281 // Note that some complementary code later down below does
12282 // categorize the descendants and parents nodes of this node
12283 // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
12284 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
12285 }
12286
12287 // If a parent node has been allowed by a negated suppression
12288 // specification, then categorize the current node as
12289 // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
12290 if (d->parent_node())
12291 {
12292 diff_category c = d->parent_node()->get_local_category();
12293 if (c & (HAS_ALLOWED_CHANGE_CATEGORY
12294 | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY))
12295 d->add_to_category(HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
12296 else
12297 {
12298 c = d->parent_node()->get_category();
12299 if (c & (HAS_ALLOWED_CHANGE_CATEGORY
12300 | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY))
12301 d->add_to_category(HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
12302 }
12303 }
12304
12305 }
12306
12307 /// After visiting the children nodes of a given diff node,
12308 /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
12309 /// diff node, if need be.
12310 ///
12311 /// That is, if all children nodes carry a suppressed change the
12312 /// current node should be marked as suppressed as well.
12313 ///
12314 /// In practice, this might be too strong of a condition. If the
12315 /// current node carries a local change (i.e, a change not carried
12316 /// by any of its children node) and if that change is not
12317 /// suppressed, then the current node should *NOT* be suppressed.
12318 ///
12319 /// But right now, the IR doesn't let us know about local vs
12320 /// children-carried changes. So we cannot be that precise yet.
12321 virtual void
visit_endabigail::comparison::suppression_categorization_visitor12322 visit_end(diff* d)
12323 {
12324 bool has_non_suppressed_child = false;
12325 bool has_non_empty_child = false;
12326 bool has_suppressed_child = false;
12327 bool has_non_private_child = false;
12328 bool has_private_child = false;
12329 bool has_descendant_with_allowed_change = false;
12330
12331 if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
12332 // (or the PRIVATE_TYPE_CATEGORY for the same matter)
12333 // category from its children is a node which:
12334 //
12335 // 1/ hasn't been suppressed already
12336 //
12337 // 2/ and has no local change (unless it's a pointer,
12338 // reference or qualified diff node).
12339 //
12340 // Note that qualified type and typedef diff nodes are a bit
12341 // special. The local changes of the underlying type are
12342 // considered local for the qualified/typedef type, just like
12343 // for pointer/reference types. But then the qualified or
12344 // typedef type itself can have local changes of its own, and
12345 // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
12346 // So a qualified type which have local changes that are
12347 // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
12348 // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
12349 // or SUPPRESSED_CATEGORY can see these categories be
12350 // propagated.
12351 //
12352 // Note that all pointer/reference diff node changes are
12353 // potentially considered local, i.e, local changes of the
12354 // pointed-to-type are considered local to the pointer itself.
12355 //
12356 // Similarly, changes local to the type of function parameters,
12357 // variables (and data members) and classes (that are not of
12358 // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
12359 // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
12360 // those kinds of diff node.
12361 !(d->get_category() & SUPPRESSED_CATEGORY)
12362 && (!d->has_local_changes()
12363 || is_pointer_diff(d)
12364 || is_reference_diff(d)
12365 || (is_qualified_type_diff(d)
12366 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12367 || (is_typedef_diff(d)
12368 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12369 || (is_function_decl_diff(d)
12370 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12371 || (is_fn_parm_diff(d)
12372 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12373 || (is_function_type_diff(d)
12374 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12375 || (is_var_diff(d)
12376 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12377 || (is_class_diff(d)
12378 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
12379 {
12380 // Note that we handle private diff nodes differently from
12381 // generally suppressed diff nodes. E.g, it's not because a
12382 // type is private (and suppressed because of that; i.e, in
12383 // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
12384 // type should also be private and so suppressed. Private
12385 // diff nodes thus have different propagation rules than
12386 // generally suppressed rules.
12387 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12388 i != d->children_nodes().end();
12389 ++i)
12390 {
12391 diff* child = *i;
12392 if (child->has_changes())
12393 {
12394 has_non_empty_child = true;
12395 if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
12396 has_suppressed_child = true;
12397 else if (child->get_class_of_equiv_category()
12398 & PRIVATE_TYPE_CATEGORY)
12399 // Propagation of the PRIVATE_TYPE_CATEGORY is going
12400 // to be handled later below.
12401 ;
12402 else
12403 has_non_suppressed_child = true;
12404
12405 if (child->get_class_of_equiv_category()
12406 & PRIVATE_TYPE_CATEGORY)
12407 has_private_child = true;
12408 else if (child->get_class_of_equiv_category()
12409 & SUPPRESSED_CATEGORY)
12410 // Propagation of the SUPPRESSED_CATEGORY has been
12411 // handled above already.
12412 ;
12413 else
12414 has_non_private_child = true;
12415 }
12416 }
12417
12418 if (has_non_empty_child
12419 && has_suppressed_child
12420 && !has_non_suppressed_child)
12421 {
12422 d->add_to_category(SUPPRESSED_CATEGORY);
12423 // If a node was suppressed, all the other nodes of its class
12424 // of equivalence are suppressed too.
12425 diff *canonical_diff = d->get_canonical_diff();
12426 if (canonical_diff != d)
12427 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12428 }
12429
12430 // Note that the private-ness of a an underlying type won't be
12431 // propagated to its parent typedef, by virtue of the big "if"
12432 // clause at the beginning of this function. So we don't have
12433 // to handle that case here. So the idiom of defining
12434 // typedefs of private (opaque) types will be respected;
12435 // meaning that changes to opaque underlying type will be
12436 // flagged as private and the typedef will be flagged private
12437 // as well, unless the typedef itself has local non-type
12438 // changes. In the later case, changes to the typedef will be
12439 // emitted because the typedef won't inherit the privateness
12440 // of its underlying type. So in practise, the typedef
12441 // remains public for the purpose of change reporting.
12442 if (has_non_empty_child
12443 && has_private_child
12444 && !has_non_private_child)
12445 {
12446 d->add_to_category(PRIVATE_TYPE_CATEGORY);
12447 // If a node was suppressed, all the other nodes of its class
12448 // of equivalence are suppressed too.
12449 diff *canonical_diff = d->get_canonical_diff();
12450 if (canonical_diff != d)
12451 canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
12452 }
12453
12454 // If the underlying type of a typedef is private and carries
12455 // changes (that are implicitely suppressed because it's
12456 // private) then the typedef must be suppressed too, so that
12457 // those changes to the underlying type are not seen.
12458 if (is_typedef_diff(d)
12459 && !d->has_local_changes()
12460 && has_private_child
12461 && has_non_empty_child)
12462 {
12463 d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
12464 // If a node was suppressed, all the other nodes of its class
12465 // of equivalence are suppressed too.
12466 diff *canonical_diff = d->get_canonical_diff();
12467 if (canonical_diff != d)
12468 canonical_diff->add_to_category
12469 (SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
12470 }
12471
12472 if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
12473 if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
12474 {
12475 // d is a function diff that carries a local *type*
12476 // change (that means it's a change to the function
12477 // type). Let's see if the child function type diff
12478 // node is suppressed. That would mean that we are
12479 // instructed to show details of a diff that is deemed
12480 // suppressed; this means the suppression conflicts with
12481 // a local type change. In that case, let's follow what
12482 // the user asked and suppress the function altogether,
12483 if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
12484 if (fn_type_diff->is_suppressed())
12485 {
12486 d->add_to_category(SUPPRESSED_CATEGORY);
12487 // If a node was suppressed, all the other nodes
12488 // of its class of equivalence are suppressed too.
12489 diff *canonical_diff = d->get_canonical_diff();
12490 if (canonical_diff != d)
12491 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12492 }
12493 }
12494 }
12495
12496 // If any descendant node was selected by a negated suppression
12497 // specification then categorize the current one as
12498 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
12499 for (auto child_node : d->children_nodes())
12500 {
12501 diff *canonical_diff = child_node->get_canonical_diff();
12502 diff_category c = canonical_diff->get_category();
12503 if (c & (HAS_ALLOWED_CHANGE_CATEGORY
12504 | HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY))
12505 has_descendant_with_allowed_change = true;
12506 }
12507 if (has_descendant_with_allowed_change)
12508 {
12509 diff_category c = HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY;
12510 d->add_to_category(c);
12511 d->get_canonical_diff()->add_to_category(c);
12512 }
12513 }
12514 }; //end struct suppression_categorization_visitor
12515
12516 /// Walk a given diff-sub tree and appply the suppressions carried by
12517 /// the context. If the suppression applies to a given node than
12518 /// categorize the node into the SUPPRESSED_CATEGORY category and
12519 /// propagate that categorization.
12520 ///
12521 /// @param diff_tree the diff-sub tree to apply the suppressions to.
12522 void
apply_suppressions(diff * diff_tree)12523 apply_suppressions(diff* diff_tree)
12524 {
12525 if (diff_tree && !diff_tree->context()->suppressions().empty())
12526 {
12527 // Apply suppressions to functions and variables that have
12528 // changed sub-types.
12529 suppression_categorization_visitor v;
12530 diff_tree->context()->forget_visited_diffs();
12531 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12532 diff_tree->context()->forbid_visiting_a_node_twice(true);
12533 diff_tree->traverse(v);
12534 diff_tree->context()->forbid_visiting_a_node_twice(s);
12535 }
12536 }
12537
12538 /// Walk a given diff-sub tree and appply the suppressions carried by
12539 /// the context. If the suppression applies to a given node than
12540 /// categorize the node into the SUPPRESSED_CATEGORY category and
12541 /// propagate that categorization.
12542 ///
12543 /// @param diff_tree the diff-sub tree to apply the suppressions to.
12544 void
apply_suppressions(diff_sptr diff_tree)12545 apply_suppressions(diff_sptr diff_tree)
12546 {apply_suppressions(diff_tree.get());}
12547
12548 /// Walk a @ref corpus_diff tree and appply the suppressions carried
12549 /// by the context. If the suppression applies to a given node then
12550 /// categorize the node into the SUPPRESSED_CATEGORY category and
12551 /// propagate that categorization.
12552 ///
12553 /// @param diff_tree the diff tree to apply the suppressions to.
12554 void
apply_suppressions(const corpus_diff * diff_tree)12555 apply_suppressions(const corpus_diff* diff_tree)
12556 {
12557 if (diff_tree && !diff_tree->context()->suppressions().empty())
12558 {
12559 // First, visit the children trees of changed constructs:
12560 // changed functions, variables, as well as sub-types of these,
12561 // and apply suppression specifications to these ...
12562 suppression_categorization_visitor v;
12563 diff_tree->context()->forget_visited_diffs();
12564 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12565 diff_tree->context()->forbid_visiting_a_node_twice(true);
12566 const_cast<corpus_diff*>(diff_tree)->traverse(v);
12567 diff_tree->context()->forbid_visiting_a_node_twice(s);
12568
12569 // ... then also visit the set of added and removed functions,
12570 // variables, symbols, and types not reachable from global
12571 // functions and variables.
12572 diff_tree->priv_->
12573 apply_supprs_to_added_removed_fns_vars_unreachable_types();
12574 }
12575 }
12576
12577 /// Walk a diff tree and appply the suppressions carried by the
12578 /// context. If the suppression applies to a given node than
12579 /// categorize the node into the SUPPRESSED_CATEGORY category and
12580 /// propagate that categorization.
12581 ///
12582 /// @param diff_tree the diff tree to apply the suppressions to.
12583 void
apply_suppressions(corpus_diff_sptr diff_tree)12584 apply_suppressions(corpus_diff_sptr diff_tree)
12585 {apply_suppressions(diff_tree.get());}
12586
12587 // </diff tree category propagation>
12588
12589 // <diff tree printing stuff>
12590
12591 /// A visitor to print (to an output stream) a pretty representation
12592 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
12593 struct diff_node_printer : public diff_node_visitor
12594 {
12595 ostream& out_;
12596 unsigned level_;
12597
12598 /// Emit a certain number of spaces to the output stream associated
12599 /// to this diff_node_printer.
12600 ///
12601 /// @param level half of the numver of spaces to emit.
12602 void
do_indentabigail::comparison::diff_node_printer12603 do_indent(unsigned level)
12604 {
12605 for (unsigned i = 0; i < level; ++i)
12606 out_ << " ";
12607 }
12608
diff_node_printerabigail::comparison::diff_node_printer12609 diff_node_printer(ostream& out)
12610 : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
12611 out_(out),
12612 level_(0)
12613 {}
12614
12615 virtual void
visit_beginabigail::comparison::diff_node_printer12616 visit_begin(diff*)
12617 {
12618 ++level_;
12619 }
12620
12621 virtual void
visit_endabigail::comparison::diff_node_printer12622 visit_end(diff*)
12623 {
12624 --level_;
12625 }
12626
12627 virtual void
visit_beginabigail::comparison::diff_node_printer12628 visit_begin(corpus_diff*)
12629 {
12630 ++level_;
12631 }
12632
12633 virtual void
visit_endabigail::comparison::diff_node_printer12634 visit_end(corpus_diff*)
12635 {
12636 --level_;
12637 }
12638
12639 virtual bool
visitabigail::comparison::diff_node_printer12640 visit(diff* d, bool pre)
12641 {
12642 if (!pre)
12643 // We are post-visiting the diff node D. Which means, we have
12644 // printed a pretty representation for it already. So do
12645 // nothing now.
12646 return true;
12647
12648 do_indent(level_);
12649 out_ << d->get_pretty_representation();
12650 out_ << "\n";
12651 do_indent(level_);
12652 out_ << "{\n";
12653 do_indent(level_ + 1);
12654 out_ << "category: "<< d->get_category() << "\n";
12655 do_indent(level_ + 1);
12656 out_ << "@: " << std::hex << d << std::dec << "\n";
12657 do_indent(level_ + 1);
12658 out_ << "@-canonical: " << std::hex
12659 << d->get_canonical_diff()
12660 << std::dec << "\n";
12661 do_indent(level_);
12662 out_ << "}\n";
12663
12664 return true;
12665 }
12666
12667 virtual bool
visitabigail::comparison::diff_node_printer12668 visit(corpus_diff* d, bool pre)
12669 {
12670 if (!pre)
12671 // We are post-visiting the diff node D. Which means, we have
12672 // printed a pretty representation for it already. So do
12673 // nothing now.
12674 return true;
12675
12676 // indent
12677 for (unsigned i = 0; i < level_; ++i)
12678 out_ << ' ';
12679 out_ << d->get_pretty_representation();
12680 out_ << '\n';
12681 return true;
12682 }
12683 }; // end struct diff_printer_visitor
12684
12685 // </ diff tree printing stuff>
12686
12687 /// Emit a textual representation of a @ref diff sub-tree to an
12688 /// output stream.
12689 ///
12690 /// @param diff_tree the sub-tree to emit the textual representation
12691 /// for.
12692 ///
12693 /// @param out the output stream to emit the textual representation
12694 /// for @p diff_tree to.
12695 void
print_diff_tree(diff * diff_tree,ostream & out)12696 print_diff_tree(diff* diff_tree, ostream& out)
12697 {
12698 diff_node_printer p(out);
12699 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12700 diff_tree->context()->forbid_visiting_a_node_twice(false);
12701 diff_tree->traverse(p);
12702 diff_tree->context()->forbid_visiting_a_node_twice(s);
12703 }
12704
12705 /// Emit a textual representation of a @ref corpus_diff tree to an
12706 /// output stream.
12707 ///
12708 /// @param diff_tree the @ref corpus_diff tree to emit the textual
12709 /// representation for.
12710 ///
12711 /// @param out the output stream to emit the textual representation
12712 /// for @p diff_tree to.
12713 void
print_diff_tree(corpus_diff * diff_tree,std::ostream & out)12714 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
12715 {
12716 diff_node_printer p(out);
12717 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12718 diff_tree->context()->forbid_visiting_a_node_twice(false);
12719 diff_tree->traverse(p);
12720 diff_tree->context()->forbid_visiting_a_node_twice(s);
12721 }
12722
12723 /// Emit a textual representation of a @ref diff sub-tree to an
12724 /// output stream.
12725 ///
12726 /// @param diff_tree the sub-tree to emit the textual representation
12727 /// for.
12728 ///
12729 /// @param out the output stream to emit the textual representation
12730 /// for @p diff_tree to.
12731 void
print_diff_tree(diff_sptr diff_tree,std::ostream & o)12732 print_diff_tree(diff_sptr diff_tree,
12733 std::ostream& o)
12734 {print_diff_tree(diff_tree.get(), o);}
12735
12736 /// Emit a textual representation of a @ref corpus_diff tree to an
12737 /// output stream.
12738 ///
12739 /// @param diff_tree the @ref corpus_diff tree to emit the textual
12740 /// representation for.
12741 ///
12742 /// @param out the output stream to emit the textual representation
12743 /// for @p diff_tree to.
12744 void
print_diff_tree(corpus_diff_sptr diff_tree,std::ostream & o)12745 print_diff_tree(corpus_diff_sptr diff_tree,
12746 std::ostream& o)
12747 {print_diff_tree(diff_tree.get(), o);}
12748
12749 // <redundancy_marking_visitor>
12750
12751 /// A tree visitor to categorize nodes with respect to the
12752 /// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
12753 /// present on several spots of the tree) and mark such nodes
12754 /// appropriatly. This visitor also takes care of propagating the
12755 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
12756 /// appropriate.
12757 struct redundancy_marking_visitor : public diff_node_visitor
12758 {
12759 bool skip_children_nodes_;
12760
redundancy_marking_visitorabigail::comparison::redundancy_marking_visitor12761 redundancy_marking_visitor()
12762 : skip_children_nodes_()
12763 {}
12764
12765 virtual void
visit_beginabigail::comparison::redundancy_marking_visitor12766 visit_begin(diff* d)
12767 {
12768 if (d->to_be_reported())
12769 {
12770 // A diff node that carries a change and that has been already
12771 // traversed elsewhere is considered redundant. So let's mark
12772 // it as such and let's not traverse it; that is, let's not
12773 // visit its children.
12774 if ((d->context()->diff_has_been_visited(d)
12775 || d->get_canonical_diff()->is_traversing())
12776 && d->has_changes())
12777 {
12778 // But if two diff nodes are redundant sibbling that carry
12779 // changes of base types, do not mark them as being
12780 // redundant. This is to avoid marking nodes as redundant
12781 // in this case:
12782 //
12783 // int foo(int a, int b);
12784 // compared with:
12785 // float foo(float a, float b); (in C).
12786 //
12787 // In this case, we want to report all the occurences of
12788 // the int->float change because logically, they are at
12789 // the same level in the diff tree.
12790
12791 bool redundant_with_sibling_node = false;
12792 const diff* p = d->parent_node();
12793
12794 // If this is a child node of a fn_parm_diff, look through
12795 // the fn_parm_diff node to get the function diff node.
12796 if (p && dynamic_cast<const fn_parm_diff*>(p))
12797 p = p->parent_node();
12798
12799 if (p)
12800 for (vector<diff*>::const_iterator s =
12801 p->children_nodes().begin();
12802 s != p->children_nodes().end();
12803 ++s)
12804 {
12805 if (*s == d)
12806 continue;
12807 diff* sib = *s;
12808 // If this is a fn_parm_diff, look through the
12809 // fn_parm_diff node to get at the real type node.
12810 if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
12811 sib = f->type_diff().get();
12812 if (sib == d)
12813 continue;
12814 if (sib->get_canonical_diff() == d->get_canonical_diff()
12815 // Sibbling diff nodes that carry base type
12816 // changes ar to be marked as redundant.
12817 && (is_base_diff(sib) || is_distinct_diff(sib)))
12818 {
12819 redundant_with_sibling_node = true;
12820 break;
12821 }
12822 }
12823 if (!redundant_with_sibling_node
12824 // Changes to basic types should never be considered
12825 // redundant. For instance, if a member of integer
12826 // type is changed into a char type in both a struct A
12827 // and a struct B, we want to see both changes.
12828 && !has_basic_type_change_only(d)
12829 // The same goes for distinct type changes
12830 && !filtering::is_mostly_distinct_diff(d)
12831 // Functions with similar *local* changes are never marked
12832 // redundant because otherwise one could miss important
12833 // similar local changes that are applied to different
12834 // functions.
12835 && !is_function_type_diff_with_local_changes(d)
12836 // Changes involving variadic parameters of functions
12837 // should never be marked redundant because we want to see
12838 // them all.
12839 && !is_diff_of_variadic_parameter(d)
12840 && !is_diff_of_variadic_parameter_type(d)
12841 // If the canonical diff itself has been filtered out,
12842 // then this one is not marked redundant, unless the
12843 // canonical diff was already redundant.
12844 && (!d->get_canonical_diff()->is_filtered_out()
12845 || (d->get_canonical_diff()->get_category()
12846 & REDUNDANT_CATEGORY))
12847 // If the *same* diff node (not one that is merely
12848 // equivalent to this one) has already been visited
12849 // the do not mark it as beind redundant. It's only
12850 // the other nodes that are equivalent to this one
12851 // that must be marked redundant.
12852 && d->context()->diff_has_been_visited(d) != d
12853 // If the diff node is a function parameter and is not
12854 // a reference/pointer (to a non basic or a non
12855 // distinct type diff) then do not mark it as
12856 // redundant.
12857 //
12858 // Children nodes of base class diff nodes are never
12859 // redundant either, we want to see them all.
12860 && (is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(d)
12861 || (!is_child_node_of_function_parm_diff(d)
12862 && !is_child_node_of_base_diff(d))))
12863 {
12864 d->add_to_category(REDUNDANT_CATEGORY);
12865 // As we said in preamble, as this node is marked as
12866 // being redundant, let's not visit its children.
12867 // This is not an optimization; it's needed for
12868 // correctness. In the case of a diff node involving
12869 // a class type that refers to himself, visiting the
12870 // children nodes might cause them to be wrongly
12871 // marked as redundant.
12872 set_visiting_kind(get_visiting_kind()
12873 | SKIP_CHILDREN_VISITING_KIND);
12874 skip_children_nodes_ = true;
12875 }
12876 }
12877 }
12878 else
12879 {
12880 // If the node is not to be reported, do not look at it children.
12881 set_visiting_kind(get_visiting_kind() | SKIP_CHILDREN_VISITING_KIND);
12882 skip_children_nodes_ = true;
12883 }
12884 }
12885
12886 virtual void
visit_beginabigail::comparison::redundancy_marking_visitor12887 visit_begin(corpus_diff*)
12888 {
12889 }
12890
12891 virtual void
visit_endabigail::comparison::redundancy_marking_visitor12892 visit_end(diff* d)
12893 {
12894 if (skip_children_nodes_)
12895 // When visiting this node, we decided to skip its children
12896 // node. Now that we are done visiting the node, lets stop
12897 // avoiding the children nodes visiting for the other tree
12898 // nodes.
12899 {
12900 set_visiting_kind(get_visiting_kind() & (~SKIP_CHILDREN_VISITING_KIND));
12901 skip_children_nodes_ = false;
12902 }
12903 else
12904 {
12905 // Propagate the redundancy categorization of the children nodes
12906 // to this node. But if this node has local changes, then it
12907 // doesn't inherit redundancy from its children nodes.
12908 if (!(d->get_category() & REDUNDANT_CATEGORY)
12909 && (!d->has_local_changes_to_be_reported()
12910 // By default, pointer, reference and qualified types
12911 // consider that a local changes to their underlying
12912 // type is always a local change for themselves.
12913 //
12914 // This is as if those types don't have local changes
12915 // in the same sense as other types. So we always
12916 // propagate redundancy to them, regardless of if they
12917 // have local changes or not.
12918 //
12919 // We also propagate redundancy to typedef types if
12920 // these /only/ carry changes to their underlying
12921 // type.
12922 //
12923 // Note that changes to the underlying type of a
12924 // typedef is considered local of
12925 // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
12926 // typedef itself are considered local of
12927 // LOCAL_NON_TYPE_CHANGE_KIND kind.
12928 || is_pointer_diff(d)
12929 || is_qualified_type_diff(d)
12930 // A typedef with local non-type changes should not
12931 // see redundancy propagation from its underlying
12932 // type, otherwise, the non-type change might be
12933 // "suppressed" away.
12934 || (is_typedef_diff(d)
12935 && (!(d->has_local_changes()
12936 & LOCAL_NON_TYPE_CHANGE_KIND)))
12937 // A (member) variable with non-type local changes
12938 // should not see redundacy propagation from its type.
12939 // If redundant local-type changes are carried by its
12940 // type however, then that redundancy is propagated to
12941 // the variable. This is key to keep the redundancy
12942 // consistency in the system; otherwise, a type change
12943 // would be rightfully considered redundant at some
12944 // places but not at others.
12945 || (is_var_diff(d)
12946 && (!(d->has_local_changes()
12947 & LOCAL_NON_TYPE_CHANGE_KIND)))
12948 // A function parameter with non-type local changes
12949 // should not see redundancy propagation either. But
12950 // a function parameter with local type changes can
12951 // definitely be redundant.
12952 || (is_fn_parm_diff(d)
12953 && (!(d->has_local_changes()
12954 & LOCAL_NON_TYPE_CHANGE_KIND)))
12955 ))
12956 {
12957 bool has_non_redundant_child = false;
12958 bool has_non_empty_child = false;
12959 for (vector<diff*>::const_iterator i =
12960 d->children_nodes().begin();
12961 i != d->children_nodes().end();
12962 ++i)
12963 {
12964 if ((*i)->has_changes())
12965 {
12966 has_non_empty_child = true;
12967 // Let's see if the current child node '*i' is
12968 // "non-redundant".
12969 //
12970 // A non-redundant node would be a node that
12971 // carries a change to be reported and has not
12972 // been marked as being redundant.
12973 if ((*i)->to_be_reported()
12974 && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
12975 has_non_redundant_child = true;
12976 }
12977 if (has_non_redundant_child)
12978 break;
12979 }
12980
12981 // A diff node for which at least a child node carries a
12982 // change, and for which all the children are redundant is
12983 // deemed redundant too, unless it has local changes.
12984 if (has_non_empty_child
12985 && !has_non_redundant_child)
12986 d->add_to_category(REDUNDANT_CATEGORY);
12987 }
12988 }
12989 }
12990
12991 virtual void
visit_endabigail::comparison::redundancy_marking_visitor12992 visit_end(corpus_diff*)
12993 {
12994 }
12995
12996 virtual bool
visitabigail::comparison::redundancy_marking_visitor12997 visit(diff*, bool)
12998 {return true;}
12999
13000 virtual bool
visitabigail::comparison::redundancy_marking_visitor13001 visit(corpus_diff*, bool)
13002 {
13003 return true;
13004 }
13005 };// end struct redundancy_marking_visitor
13006
13007 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13008 /// category out of the nodes.
13009 struct redundancy_clearing_visitor : public diff_node_visitor
13010 {
13011 bool
visitabigail::comparison::redundancy_clearing_visitor13012 visit(corpus_diff*, bool)
13013 {return true;}
13014
13015 bool
visitabigail::comparison::redundancy_clearing_visitor13016 visit(diff* d, bool)
13017 {
13018 // clear the REDUNDANT_CATEGORY out of the current node.
13019 diff_category c = d->get_category();
13020 c &= ~REDUNDANT_CATEGORY;
13021 d->set_category(c);
13022 return true;
13023 }
13024 }; // end struct redundancy_clearing_visitor
13025
13026 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13027 /// with respect to the REDUNDANT_CATEGORY.
13028 ///
13029 /// @param diff_tree the @ref diff sub-tree to walk.
13030 void
categorize_redundancy(diff * diff_tree)13031 categorize_redundancy(diff* diff_tree)
13032 {
13033 if (diff_tree->context()->show_redundant_changes())
13034 return;
13035 redundancy_marking_visitor v;
13036 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13037 diff_tree->context()->forbid_visiting_a_node_twice(false);
13038 diff_tree->traverse(v);
13039 diff_tree->context()->forbid_visiting_a_node_twice(s);
13040 }
13041
13042 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13043 /// with respect to the REDUNDANT_CATEGORY.
13044 ///
13045 /// @param diff_tree the @ref diff sub-tree to walk.
13046 void
categorize_redundancy(diff_sptr diff_tree)13047 categorize_redundancy(diff_sptr diff_tree)
13048 {categorize_redundancy(diff_tree.get());}
13049
13050 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13051 /// with respect to the REDUNDANT_CATEGORY.
13052 ///
13053 /// @param diff_tree the @ref corpus_diff tree to walk.
13054 void
categorize_redundancy(corpus_diff * diff_tree)13055 categorize_redundancy(corpus_diff* diff_tree)
13056 {
13057 redundancy_marking_visitor v;
13058 diff_tree->context()->forget_visited_diffs();
13059 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13060 diff_tree->context()->forbid_visiting_a_node_twice(false);
13061 diff_tree->traverse(v);
13062 diff_tree->context()->forbid_visiting_a_node_twice(s);
13063 }
13064
13065 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13066 /// with respect to the REDUNDANT_CATEGORY.
13067 ///
13068 /// @param diff_tree the @ref corpus_diff tree to walk.
13069 void
categorize_redundancy(corpus_diff_sptr diff_tree)13070 categorize_redundancy(corpus_diff_sptr diff_tree)
13071 {categorize_redundancy(diff_tree.get());}
13072
13073 // </redundancy_marking_visitor>
13074
13075 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13076 /// out of the category of the nodes.
13077 ///
13078 /// @param diff_tree the @ref diff sub-tree to walk.
13079 void
clear_redundancy_categorization(diff * diff_tree)13080 clear_redundancy_categorization(diff* diff_tree)
13081 {
13082 redundancy_clearing_visitor v;
13083 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13084 diff_tree->context()->forbid_visiting_a_node_twice(false);
13085 diff_tree->traverse(v);
13086 diff_tree->context()->forbid_visiting_a_node_twice(s);
13087 diff_tree->context()->forget_visited_diffs();
13088 }
13089
13090 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13091 /// out of the category of the nodes.
13092 ///
13093 /// @param diff_tree the @ref diff sub-tree to walk.
13094 void
clear_redundancy_categorization(diff_sptr diff_tree)13095 clear_redundancy_categorization(diff_sptr diff_tree)
13096 {clear_redundancy_categorization(diff_tree.get());}
13097
13098 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13099 /// out of the category of the nodes.
13100 ///
13101 /// @param diff_tree the @ref corpus_diff tree to walk.
13102 void
clear_redundancy_categorization(corpus_diff * diff_tree)13103 clear_redundancy_categorization(corpus_diff* diff_tree)
13104 {
13105 redundancy_clearing_visitor v;
13106 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13107 diff_tree->context()->forbid_visiting_a_node_twice(false);
13108 diff_tree->traverse(v);
13109 diff_tree->context()->forbid_visiting_a_node_twice(s);
13110 diff_tree->context()->forget_visited_diffs();
13111 }
13112
13113 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13114 /// out of the category of the nodes.
13115 ///
13116 /// @param diff_tree the @ref corpus_diff tree to walk.
13117 void
clear_redundancy_categorization(corpus_diff_sptr diff_tree)13118 clear_redundancy_categorization(corpus_diff_sptr diff_tree)
13119 {clear_redundancy_categorization(diff_tree.get());}
13120
13121 /// Apply the @ref diff tree filters that have been associated to the
13122 /// context of the a given @ref corpus_diff tree. As a result, the
13123 /// nodes of the @diff tree are going to be categorized into one of
13124 /// several of the categories of @ref diff_category.
13125 ///
13126 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
13127 /// to be categorized.
13128 void
apply_filters(corpus_diff_sptr diff_tree)13129 apply_filters(corpus_diff_sptr diff_tree)
13130 {
13131 diff_tree->context()->maybe_apply_filters(diff_tree);
13132 propagate_categories(diff_tree);
13133 }
13134
13135 /// Test if a diff node represents the difference between a variadic
13136 /// parameter type and something else.
13137 ///
13138 /// @param d the diff node to consider.
13139 ///
13140 /// @return true iff @p d is a diff node that represents the
13141 /// difference between a variadic parameter type and something else.
13142 bool
is_diff_of_variadic_parameter_type(const diff * d)13143 is_diff_of_variadic_parameter_type(const diff* d)
13144 {
13145 if (!d)
13146 return false;
13147
13148 type_base_sptr t = is_type(d->first_subject());
13149 if (t && t->get_environment().is_variadic_parameter_type(t))
13150 return true;
13151
13152 t = is_type(d->second_subject());
13153 if (t && t->get_environment().is_variadic_parameter_type(t))
13154 return true;
13155
13156 return false;
13157 }
13158
13159 /// Test if a diff node represents the difference between a variadic
13160 /// parameter type and something else.
13161 ///
13162 /// @param d the diff node to consider.
13163 ///
13164 /// @return true iff @p d is a diff node that represents the
13165 /// difference between a variadic parameter type and something else.
13166 bool
is_diff_of_variadic_parameter_type(const diff_sptr & d)13167 is_diff_of_variadic_parameter_type(const diff_sptr& d)
13168 {return is_diff_of_variadic_parameter_type(d.get());}
13169
13170 /// Test if a diff node represents the difference between a variadic
13171 /// parameter and something else.
13172 ///
13173 /// @param d the diff node to consider.
13174 ///
13175 /// @return true iff @p d is a diff node that represents the
13176 /// difference between a variadic parameter and something else.
13177 bool
is_diff_of_variadic_parameter(const diff * d)13178 is_diff_of_variadic_parameter(const diff* d)
13179 {
13180 fn_parm_diff* diff =
13181 dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
13182 return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
13183 }
13184
13185 /// Test if a diff node represents the difference between a variadic
13186 /// parameter and something else.
13187 ///
13188 /// @param d the diff node to consider.
13189 ///
13190 /// @return true iff @p d is a diff node that represents the
13191 /// difference between a variadic parameter and something else.
13192 bool
is_diff_of_variadic_parameter(const diff_sptr & d)13193 is_diff_of_variadic_parameter(const diff_sptr& d)
13194 {return is_diff_of_variadic_parameter(d.get());}
13195
13196 /// Test if a diff node represents a diff between two basic types.
13197 ///
13198 /// @param d the diff node to consider.
13199 ///
13200 /// @return true iff @p d is a diff between two basic types.
13201 const type_decl_diff*
is_diff_of_basic_type(const diff * d)13202 is_diff_of_basic_type(const diff *d)
13203 {return dynamic_cast<const type_decl_diff*>(d);}
13204
13205 /// Test if a diff node represents a diff between two basic types, or
13206 /// between pointers, references or qualified type to basic types.
13207 ///
13208 /// @param diff the diff node to consider.
13209 ///
13210 /// @param allow_indirect_type if true, then this function looks into
13211 /// pointer, reference or qualified diff types to see if they "point
13212 /// to" basic types.
13213 ///
13214 /// @return true iff @p d is a diff between two basic types.
13215 const type_decl_diff*
is_diff_of_basic_type(const diff * diff,bool allow_indirect_type)13216 is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
13217 {
13218 if (allow_indirect_type)
13219 diff = peel_pointer_or_qualified_type_diff(diff);
13220 return is_diff_of_basic_type(diff);
13221 }
13222
13223 /// If a diff node is about changes between two typedef types, get the
13224 /// diff node about changes between the underlying types.
13225 ///
13226 /// Note that this function walks the tree of underlying diff nodes
13227 /// returns the first diff node about types that are not typedefs.
13228 ///
13229 /// @param dif the dif node to consider.
13230 ///
13231 /// @return the underlying diff node of @p dif, or just return @p dif
13232 /// if it's not a typedef diff node.
13233 const diff*
peel_typedef_diff(const diff * dif)13234 peel_typedef_diff(const diff* dif)
13235 {
13236 const typedef_diff *d = 0;
13237 while ((d = is_typedef_diff(dif)))
13238 dif = d->underlying_type_diff().get();
13239 return dif;
13240 }
13241
13242 /// If a diff node is about changes between two pointer types, get the
13243 /// diff node about changes between the underlying (pointed-to) types.
13244 ///
13245 /// Note that this function walks the tree of underlying diff nodes
13246 /// returns the first diff node about types that are not pointers.
13247 ///
13248 /// @param dif the dif node to consider.
13249 ///
13250 /// @return the underlying diff node of @p dif, or just return @p dif
13251 /// if it's not a pointer diff node.
13252 const diff*
peel_pointer_diff(const diff * dif)13253 peel_pointer_diff(const diff* dif)
13254 {
13255 const pointer_diff *d = 0;
13256 while ((d = is_pointer_diff(dif)))
13257 dif = d->underlying_type_diff().get();
13258 return dif;
13259 }
13260
13261 /// If a diff node is about changes between two reference types, get
13262 /// the diff node about changes between the underlying (pointed-to)
13263 /// types.
13264 ///
13265 /// Note that this function walks the tree of underlying diff nodes
13266 /// returns the first diff node about types that are not references.
13267 ///
13268 /// @param dif the dif node to consider.
13269 ///
13270 /// @return the underlying diff node of @p dif, or just return @p dif
13271 /// if it's not a reference diff node.
13272 const diff*
peel_reference_diff(const diff * dif)13273 peel_reference_diff(const diff* dif)
13274 {
13275 const reference_diff *d = 0;
13276 while ((d = is_reference_diff(dif)))
13277 dif = d->underlying_type_diff().get();
13278 return dif;
13279 }
13280
13281 /// If a diff node is about changes between two qualified types, get
13282 /// the diff node about changes between the underlying (non-qualified)
13283 /// types.
13284 ///
13285 /// Note that this function walks the tree of underlying diff nodes
13286 /// returns the first diff node about types that are not qualified.
13287 ///
13288 /// @param dif the dif node to consider.
13289 ///
13290 /// @return the underlying diff node of @p dif, or just return @p dif
13291 /// if it's not a qualified diff node.
13292 const diff*
peel_qualified_diff(const diff * dif)13293 peel_qualified_diff(const diff* dif)
13294 {
13295 const qualified_type_diff *d = 0;
13296 while ((d = is_qualified_type_diff(dif)))
13297 dif = d->underlying_type_diff().get();
13298 return dif;
13299 }
13300
13301 /// If a diff node is about changes between two function parameters
13302 /// get the diff node about changes between the types of the parameters.
13303 ///
13304 /// @param dif the dif node to consider.
13305 ///
13306 /// @return the diff of the types of the parameters.
13307 const diff*
peel_fn_parm_diff(const diff * dif)13308 peel_fn_parm_diff(const diff* dif)
13309 {
13310 const fn_parm_diff *d = 0;
13311 while ((d = is_fn_parm_diff(dif)))
13312 dif = d->type_diff().get();
13313 return dif;
13314 }
13315
13316 /// If a diff node is about changes between two pointer, reference or
13317 /// qualified types, get the diff node about changes between the
13318 /// underlying types.
13319 ///
13320 /// Note that this function walks the tree of underlying diff nodes
13321 /// returns the first diff node about types that are not pointer,
13322 /// reference or qualified.
13323 ///
13324 /// @param dif the dif node to consider.
13325 ///
13326 /// @return the underlying diff node of @p dif, or just return @p dif
13327 /// if it's not a pointer, reference or qualified diff node.
13328 const diff*
peel_pointer_or_qualified_type_diff(const diff * dif)13329 peel_pointer_or_qualified_type_diff(const diff*dif)
13330 {
13331 while (true)
13332 {
13333 if (const pointer_diff *d = is_pointer_diff(dif))
13334 dif = peel_pointer_diff(d);
13335 else if (const reference_diff *d = is_reference_diff(dif))
13336 dif = peel_reference_diff(d);
13337 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13338 dif = peel_qualified_diff(d);
13339 else
13340 break;
13341 }
13342 return dif;
13343 }
13344
13345 /// If a diff node is about changes between two typedefs or qualified
13346 /// types, get the diff node about changes between the underlying
13347 /// types.
13348 ///
13349 /// Note that this function walks the tree of underlying diff nodes
13350 /// returns the first diff node about types that are not typedef or
13351 /// qualified types.
13352 ///
13353 /// @param dif the dif node to consider.
13354 ///
13355 /// @return the underlying diff node of @p dif, or just return @p dif
13356 /// if it's not typedef or qualified diff node.
13357 const diff*
peel_typedef_or_qualified_type_diff(const diff * dif)13358 peel_typedef_or_qualified_type_diff(const diff *dif)
13359 {
13360 while (true)
13361 {
13362 if (const typedef_diff *d = is_typedef_diff(dif))
13363 dif = peel_typedef_diff(d);
13364 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13365 dif = peel_qualified_diff(d);
13366 else
13367 break;
13368 }
13369 return dif;
13370 }
13371
13372 /// If a diff node is about changes between two typedefs or qualified
13373 /// types, get the diff node about changes between the underlying
13374 /// types.
13375 ///
13376 /// Note that this function walks the tree of underlying diff nodes
13377 /// returns the first diff node about types that are neither typedef,
13378 /// qualified type nor parameters.
13379 ///
13380 /// @param dif the dif node to consider.
13381 ///
13382 /// @return the diff node about changes between the underlying types.
13383 const diff*
peel_typedef_qualified_type_or_parameter_diff(const diff * dif)13384 peel_typedef_qualified_type_or_parameter_diff(const diff *dif)
13385 {
13386 while (true)
13387 {
13388 if (const typedef_diff *d = is_typedef_diff(dif))
13389 dif = peel_typedef_diff(d);
13390 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13391 dif = peel_qualified_diff(d);
13392 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
13393 dif = peel_fn_parm_diff(d);
13394 else
13395 break;
13396 }
13397 return dif;
13398 }
13399
13400 /// Test if a diff node represents a diff between two class or union
13401 /// types.
13402 ///
13403 /// @param d the diff node to consider.
13404 ///
13405 /// @return iff @p is a diff between two class or union types then
13406 /// return the instance of @ref class_or_union_diff that @p derives
13407 /// from. Otherwise, return nil.
13408 const class_or_union_diff*
is_diff_of_class_or_union_type(const diff * d)13409 is_diff_of_class_or_union_type(const diff *d)
13410 {return dynamic_cast<const class_or_union_diff*>(d);}
13411
13412 /// Test if a given diff node carries *only* a local type change.
13413 ///
13414 /// @param d the diff node to consider.
13415 ///
13416 /// @return true iff @p has a change and that change is a local type
13417 /// change.
13418 static bool
has_local_type_change_only(const diff * d)13419 has_local_type_change_only(const diff *d)
13420 {
13421 if (enum change_kind k = d->has_local_changes())
13422 if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
13423 && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
13424 return true;
13425
13426 return false;
13427 }
13428
13429 /// Test if a diff node is a decl diff that only carries a basic type
13430 /// change on its type diff sub-node.
13431 ///
13432 ///Note that that pointers/references/qualified types diffs to basic
13433 /// type diffs are considered as having basic type change only.
13434 ///
13435 /// @param d the diff node to consider.
13436 ///
13437 /// @return true iff @p d is a decl diff that only carries a basic
13438 /// type change on its type diff sub-node.
13439 bool
has_basic_type_change_only(const diff * d)13440 has_basic_type_change_only(const diff *d)
13441 {
13442 d = peel_typedef_qualified_type_or_parameter_diff(d);
13443
13444 if (is_diff_of_basic_type(d, true) && d->has_changes())
13445 return true;
13446 else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
13447 return (has_local_type_change_only(v)
13448 && is_diff_of_basic_type(v->type_diff().get(), true));
13449 else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
13450 return (has_local_type_change_only(p)
13451 && is_diff_of_basic_type(p->type_diff().get(), true));
13452 else if (const function_decl_diff* f =
13453 dynamic_cast<const function_decl_diff*>(d))
13454 return (has_local_type_change_only(f)
13455 && f->type_diff()
13456 && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
13457 true));
13458 return false;
13459 }
13460 }// end namespace comparison
13461 } // end namespace abigail
13462