libabigail
abg-comparison.cc
Go to the documentation of this file.
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
18#include "abg-comparison-priv.h"
19#include "abg-reporter-priv.h"
20#include "abg-tools-utils.h"
21
22namespace abigail
23{
24
25namespace comparison
26{
27
28///
29///
30///@defgroup DiffNode Internal Representation of the comparison engine
31/// @{
32///
33/// @brief How changes are represented in libabigail's comparison engine.
34///
35///@par diff nodes
36///
37/// The internal representation of the comparison engine is basically
38/// a graph of @ref instances of @ref diff node. We refer to these
39/// just as <em>diff nodes</em>. A diff node represents a change
40/// between two ABI artifacts represented by instances of types of the
41/// abigail::ir namespace. These two artifacts that are being
42/// compared are called the <em>subjects of the diff</em>.
43///
44/// The types of that IR are in the abigail::comparison namespace.
45///
46///@par comparing diff nodes
47///
48/// Comparing two instances of @ref diff nodes amounts to comparing
49/// the subject of the diff. In other words, two @ref diff nodes are
50/// equal if and only if their subjects are equal. Thus, two @ref
51/// diff nodes can have different memory addresses and yet be equal.
52///
53///@par diff reporting and context
54///
55/// A diff node can be serialized to an output stream to express, in
56/// a human-readable textual form, the different changes that exist
57/// between its two subjects. This is done by invoking the
58/// diff::report() method. That reporting is controlled by several
59/// parameters that are conceptually part of the context of the diff.
60/// That context is materialized by an instance of the @ref
61/// diff_context type.
62///
63/// Please note that the role of the instance(s) of @ref diff_context
64/// is boreader than just controlling the reporting of @ref diff
65/// nodes. Basically, a @ref diff node itself is created following
66/// behaviours that are controlled by a particular instance of
67/// diff_context. A diff node is created in a particular diff
68/// context, so to speak.
69///
70/// @}
71///
72
73///
74///@defgroup CanonicalDiff Canonical diff tree nodes
75/// @{
76///
77/// @brief How equivalent diff nodes are quickly spotted.
78///
79/// @par Equivalence of diff nodes.
80///
81/// Each @ref diff node has a property named <em>Canonical Diff
82/// Node</em>. If \c D is a diff node, the canonical diff node of @c
83/// D, noted @c C(D) is a particular diff node that is equal to @c D.
84/// Thus, a fast way to compare two @ref diff node is to perform a
85/// pointer comparison of their canonical diff nodes.
86///
87/// A set of equivalent @ref diff nodes is a set of diff nodes that
88/// all have the same canonical node. All the nodes of that set are
89/// equal.
90///
91/// A canonical node is registereded for a given diff node by invoking
92/// the method diff_context::initialize_canonical_diff().
93///
94/// Please note that the diff_context holds all the canonical diffs
95/// that got registered through it. Thus, the life time of all of
96/// canonical diff objects is the same as the life time of the @ref
97/// diff_context they relate to.
98///
99/// @}
100///
101
102// -----------------------------------------
103// <private functions re-usable elsewhere>
104// -----------------------------------------
105/// Sort a map of enumerators by their value.
106///
107/// @param enumerators_map the map to sort.
108///
109/// @param sorted the resulting vector of sorted enumerators.
110void
113{
114 for (string_enumerator_map::const_iterator i = enumerators_map.begin();
115 i != enumerators_map.end();
116 ++i)
117 sorted.push_back(i->second);
119 std::sort(sorted.begin(), sorted.end(), comp);
120}
121
122/// Sort a map of changed enumerators.
123///
124/// @param enumerators_map the map to sort.
125///
126///@param output parameter. The resulting sorted enumerators.
127void
130{
131 for (string_changed_enumerator_map::const_iterator i =
132 enumerators_map.begin();
133 i != enumerators_map.end();
134 ++i)
135 sorted.push_back(i->second);
136
138 std::sort(sorted.begin(), sorted.end(), comp);
139}
140
141/// Sort a map of data members by the offset of their initial value.
142///
143/// @param data_members the map of changed data members to sort.
144///
145/// @param sorted the resulting vector of sorted changed data members.
146void
148 vector<decl_base_sptr>& sorted)
149{
150 sorted.reserve(data_members.size());
151 for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
152 i != data_members.end();
153 ++i)
154 sorted.push_back(i->second);
155
156 data_member_comp comp;
157 std::sort(sorted.begin(), sorted.end(), comp);
158}
159
160/// Sort (in place) a vector of changed data members.
161///
162/// @param to_sort the vector to sort.
163void
165{
166 data_member_comp comp;
167 std::sort(to_sort.begin(), to_sort.end(), comp);
168}
169
170/// Sort an instance of @ref string_function_ptr_map map and stuff a
171/// resulting sorted vector of pointers to function_decl.
172///
173/// @param map the map to sort.
174///
175/// @param sorted the resulting sorted vector.
176void
178 vector<function_decl*>& sorted)
179{
180 sorted.reserve(map.size());
181 for (string_function_ptr_map::const_iterator i = map.begin();
182 i != map.end();
183 ++i)
184 sorted.push_back(i->second);
185
186 function_comp comp;
187 std::sort(sorted.begin(), sorted.end(), comp);
188}
189
190/// Sort a map that's an instance of @ref
191/// string_member_function_sptr_map and fill a vector of member
192/// functions with the sorted result.
193///
194/// @param map the map to sort.
195///
196/// @param sorted the resulting sorted vector.
197void
200{
201 sorted.reserve(map.size());
202 for (string_member_function_sptr_map::const_iterator i = map.begin();
203 i != map.end();
204 ++i)
205 sorted.push_back(i->second);
206
207 function_comp comp;
208 std::sort(sorted.begin(), sorted.end(), comp);
209}
210
211/// Sort the values of a @ref string_function_decl_diff_sptr_map map
212/// and store the result in a vector of @ref function_decl_diff_sptr
213/// objects.
214///
215/// @param map the map whose values to store.
216///
217/// @param sorted the vector of function_decl_diff_sptr to store the
218/// result of the sort into.
219void
223{
224 sorted.reserve(map.size());
225 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
226 i != map.end();
227 ++i)
228 sorted.push_back(i->second);
230 std::sort(sorted.begin(), sorted.end(), comp);
231}
232
233/// Sort of an instance of @ref string_var_diff_sptr_map map.
234///
235/// @param map the input map to sort.
236///
237/// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
238/// It's populated with the sorted content.
239void
241 var_diff_sptrs_type& sorted)
242{
243 sorted.reserve(map.size());
244 for (string_var_diff_sptr_map::const_iterator i = map.begin();
245 i != map.end();
246 ++i)
247 sorted.push_back(i->second);
248
250 std::sort(sorted.begin(), sorted.end(), comp);
251}
252
253/// Sort a map of string -> pointer to @ref elf_symbol.
254///
255/// The result is a vector of @ref elf_symbol_sptr sorted by the
256/// name of the symbol.
257///
258/// @param map the map to sort.
259///
260/// @param sorted out parameter; the sorted vector of @ref
261/// elf_symbol_sptr.
262void
264 vector<elf_symbol_sptr>& sorted)
265{
266 for (string_elf_symbol_map::const_iterator i = map.begin();
267 i!= map.end();
268 ++i)
269 sorted.push_back(i->second);
270
271 elf_symbol_comp comp;
272 std::sort(sorted.begin(), sorted.end(), comp);
273}
274
275/// Sort a map of string -> pointer to @ref var_decl.
276///
277/// The result is a vector of var_decl* sorted by the qualified name
278/// of the variables.
279///
280/// @param map the map to sort.
281///
282/// @param sorted out parameter; the sorted vector of @ref var_decl.
283void
285 vector<var_decl*>& sorted)
286{
287 for (string_var_ptr_map::const_iterator i = map.begin();
288 i != map.end();
289 ++i)
290 sorted.push_back(i->second);
291
292 var_comp comp;
293 std::sort(sorted.begin(), sorted.end(), comp);
294}
295
296/// Sort the values of a string_var_diff_sptr_map and store the result
297/// in a vector of var_diff_sptr.
298///
299/// @param map the map of changed data members to sort.
300///
301/// @param sorted the resulting vector of var_diff_sptr.
302void
304 var_diff_sptrs_type& sorted)
305{
306 sorted.reserve(map.size());
307 for (string_var_diff_sptr_map::const_iterator i = map.begin();
308 i != map.end();
309 ++i)
310 sorted.push_back(i->second);
312 std::sort(sorted.begin(), sorted.end(), comp);
313}
314
315/// Sort the values of a unsigned_var_diff_sptr_map map and store the
316/// result into a vector of var_diff_sptr.
317///
318/// @param map the map of changed data members to sort.
319///
320/// @param sorted the resulting vector of sorted var_diff_sptr.
321void
323 var_diff_sptrs_type& sorted)
324{
325 sorted.reserve(map.size());
326 for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
327 i != map.end();
328 ++i)
329 sorted.push_back(i->second);
331 std::sort(sorted.begin(), sorted.end(), comp);
332}
333
334/// Sort an map of string -> virtual member function into a vector of
335/// virtual member functions. The virtual member functions are sorted
336/// by increasing order of their virtual index.
337///
338/// @param map the input map.
339///
340/// @param sorted the resulting sorted vector of virtual function
341/// member.
342void
346{
347 sorted.reserve(map.size());
348 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
349 i != map.end();
350 ++i)
351 sorted.push_back(i->second);
352
354 sort(sorted.begin(), sorted.end(), comp);
355}
356
357/// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
358/// diff_sptr. The diff_sptr are sorted lexicographically wrt
359/// qualified names of their first subjects.
360///
361/// @param map the map to sort.
362///
363/// @param sorted the resulting sorted vector.
364void
366 diff_sptrs_type& sorted)
367{
368 sorted.reserve(map.size());
369 for (string_diff_sptr_map::const_iterator i = map.begin();
370 i != map.end();
371 ++i)
372 sorted.push_back(i->second);
373
374 diff_comp comp;
375 sort(sorted.begin(), sorted.end(), comp);
376}
377
378/// Sort a map ofg string -> @ref diff* into a vector of @ref
379/// diff_ptr. The diff_ptr are sorted lexicographically wrt
380/// qualified names of their first subjects.
381///
382/// @param map the map to sort.
383///
384/// @param sorted the resulting sorted vector.
385void
387 diff_ptrs_type& sorted)
388{
389 sorted.reserve(map.size());
390 for (string_diff_ptr_map::const_iterator i = map.begin();
391 i != map.end();
392 ++i)
393 sorted.push_back(i->second);
394
395 diff_comp comp;
396 sort(sorted.begin(), sorted.end(), comp);
397}
398
399/// Sort a map of string -> base_diff_sptr into a sorted vector of
400/// base_diff_sptr. The base_diff_sptr are sorted by increasing value
401/// of their offset in their containing type.
402///
403/// @param map the input map to sort.
404///
405/// @param sorted the resulting sorted vector.
406void
408 base_diff_sptrs_type& sorted)
409{
410 for (string_base_diff_sptr_map::const_iterator i = map.begin();
411 i != map.end();
412 ++i)
413 sorted.push_back(i->second);
414 base_diff_comp comp;
415 sort(sorted.begin(), sorted.end(), comp);
416}
417
418/// Lexicographically sort base specifications found
419/// in instances of string_base_sptr_map.
420void
423{
424 for (string_base_sptr_map::const_iterator i = m.begin();
425 i != m.end();
426 ++i)
427 sorted.push_back(i->second);
428
429 base_spec_comp comp;
430 std::sort(sorted.begin(), sorted.end(), comp);
431}
432
433/// Sort a map of @ref fn_parm_diff by the indexes of the function
434/// parameters.
435///
436/// @param map the map to sort.
437///
438/// @param sorted the resulting sorted vector of changed function
439/// parms.
440void
442 vector<fn_parm_diff_sptr>& sorted)
443{
444 sorted.reserve(map.size());
445 for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
446 i != map.end();
447 ++i)
448 sorted.push_back(i->second);
449
451 std::sort(sorted.begin(), sorted.end(), comp);
452}
453
454/// Sort a map of changed function parameters by the indexes of the
455/// function parameters.
456///
457/// @param map the map to sort.
458///
459/// @param sorted the resulting sorted vector of instances of @ref
460/// fn_parm_diff_sptr
461void
463 vector<fn_parm_diff_sptr>& sorted)
464{
465 sorted.reserve(map.size());
466 for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
467 i != map.end();
468 ++i)
469 sorted.push_back(i->second);
470
472 std::sort(sorted.begin(), sorted.end(), comp);
473}
474
475/// Sort a map of string -> function parameters.
476///
477/// @param map the map to sort.
478///
479/// @param sorted the resulting sorted vector of
480/// @ref vector<function_decl::parameter_sptr>
481void
483 vector<function_decl::parameter_sptr>& sorted)
484{
485 for (string_parm_map::const_iterator i = map.begin();
486 i != map.end();
487 ++i)
488 sorted.push_back(i->second);
489
490 parm_comp comp;
491 std::sort(sorted.begin(), sorted.end(), comp);
492}
493
494/// Sort the set of ABI artifacts contained in a @ref
495/// artifact_sptr_set_type.
496///
497/// @param set the set of ABI artifacts to sort.
498///
499/// @param output parameter the vector containing the sorted ABI
500/// artifacts.
501void
503 vector<type_or_decl_base_sptr>& sorted)
504{
505
506 for (artifact_sptr_set_type::const_iterator it = set.begin();
507 it != set.end();
508 ++it)
509 sorted.push_back(*it);
510
512 std::sort(sorted.begin(), sorted.end(), comp);
513}
514
515/// Sort a map of string to type_base_sptr entities.
516///
517/// The entries are sorted based on the lexicographic order of the
518/// pretty representation of the type_sptr_sptr. The sorted result is
519/// put in a vector of type_base_sptr.
520///
521/// @param map the map to sort.
522///
523/// @param sorted the resulting vector of type_base_sptr
524/// lexicographically sorted using their pretty representation.
525void
527 vector<type_base_sptr>& sorted)
528{
529 for (string_type_base_sptr_map::const_iterator i = map.begin();
530 i != map.end();
531 ++i)
532 sorted.push_back(i->second);
533
535 std::sort(sorted.begin(), sorted.end(), comp);
536}
537
538/// Return the first underlying type that is not a qualified type.
539/// @param t the qualified type to consider.
540///
541/// @return the first underlying type that is not a qualified type, or
542/// NULL if t is NULL.
543type_base_sptr
544get_leaf_type(qualified_type_def_sptr t)
545{
546 if (!t)
547 return type_base_sptr();
548
549 type_base_sptr ut = t->get_underlying_type();
550 qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
551
552 if (!qut)
553 return ut;
554 return get_leaf_type(qut);
555}
556
557/// Tests if a given diff node is to represent the changes between two
558/// gobal decls.
559///
560/// @param d the diff node to consider.
561///
562/// @return true iff @p d represents the changes between two global
563/// decls.
564bool
566{
567 ABG_ASSERT(d != 0);
568
569 if (d == 0)
570 return false;
571
573 ABG_ASSERT(first);
574
576 ABG_ASSERT(second);
577
578 if (decl_base_sptr decl = is_decl(first))
579 if (is_at_global_scope(decl))
580 if ((decl = is_decl(second)))
581 if (is_at_global_scope(decl))
582 return true;
583
584 return false;
585}
586
587// -----------------------------------------
588// </private functions re-usable elsewhere>
589// -----------------------------------------
590
591/// The overloaded or operator for @ref visiting_kind.
594{return static_cast<visiting_kind>(static_cast<unsigned>(l)
595 | static_cast<unsigned>(r));}
596
597/// The overloaded and operator for @ref visiting_kind.
600{
601 return static_cast<visiting_kind>(static_cast<unsigned>(l)
602 & static_cast<unsigned>(r));
603}
604
605/// The overloaded 'bit inversion' operator for @ref visiting_kind.
608{return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
609
610/// Test if a diff node is about differences between types.
611///
612/// @param diff the diff node to test.
613///
614/// @return a pointer to the actual type_diff_base* that @p diff
615/// extends, iff it is about differences between types.
616const type_diff_base*
618{return dynamic_cast<const type_diff_base*>(diff);}
619
620/// Test if a diff node is about differences between declarations.
621///
622/// @param diff the diff node to test.
623///
624/// @return a pointer to the actual decl_diff_base @p diff extends,
625/// iff it is about differences between declarations.
626const decl_diff_base*
628{return dynamic_cast<const decl_diff_base*>(diff);}
629
630/// Test if a diff node is a @ref class_diff node.
631///
632/// @param diff the diff node to consider.
633///
634/// @return a non-nil pointer to a @ref class_diff iff @p diff is a
635/// @ref class_diff node.
636const class_diff*
638{return dynamic_cast<const class_diff*>(diff);}
639
640/// Test if a diff node is a @ref enum_diff node.
641///
642/// @param diff the diff node to consider.
643///
644/// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
645/// a @ref enum_diff node.
646const enum_diff*
648{return dynamic_cast<const enum_diff*>(diff);}
649
650/// Test if a diff node is a @ref union_diff node.
651///
652/// @param diff the diff node to consider.
653///
654/// @return a non-nil pointer to a @ref union_diff iff @p diff is a
655/// @ref union_diff node.
656const union_diff*
658{return dynamic_cast<const union_diff*>(diff);}
659
660/// Test if a diff node is a @ref class_or_union_diff node.
661///
662/// @param d the diff node to consider.
663///
664/// @return a non-nil pointer to the @ref class_or_union_diff denoted
665/// by @p d iff @p d is a @ref class_or_union_diff.
668{return dynamic_cast<const class_or_union_diff*>(d);}
669
670/// Test if a diff node is a @ref class_or_union_diff between two
671/// anonymous classes or unions.
672///
673/// @param d the diff node to consider.
674///
675/// @return a non-nil pointer to the @ref class_or_union_diff iff @p
676/// denoted by @p d iff @p is pointer to an anonymous class or union
677/// diff.
680{
682 if (dif->first_class_or_union()->get_is_anonymous())
683 return dif;
684 return 0;
685}
686
687/// Test if a diff node is a @ref typedef_diff node.
688///
689/// @param diff the diff node to consider.
690///
691/// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
692/// @ref typedef_diff node.
693const typedef_diff*
695{return dynamic_cast<const typedef_diff*>(diff);}
696
697/// Test if a diff node is a @ref subrange_diff node.
698///
699/// @param diff the diff node to consider.
700///
701/// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
702/// @ref subrange_diff node.
703const subrange_diff*
705{return dynamic_cast<const subrange_diff*>(diff);}
706
707/// Test if a diff node is a @ref array_diff node.
708///
709/// @param diff the diff node to consider.
710///
711/// @return a non-nil pointer to a @ref array_diff iff @p diff is a
712/// @ref array_diff node.
713const array_diff*
715{return dynamic_cast<const array_diff*>(diff);}
716
717/// Test if a diff node is a @ref function_type_diff node.
718///
719/// @param diff the diff node to consider.
720///
721/// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
722/// @ref function_type_diff node.
725{return dynamic_cast<const function_type_diff*>(diff);}
726
727/// Test if a given diff node carries a function type change with
728/// local changes.
729///
730/// @param diff the diff node to consider.
731///
732/// @return a non-nil pointer to a @ref function_type_diff iff @p diff
733/// is a function_type_diff node that carries a local change.
736{
738 if (d->has_local_changes())
739 return d;
740
741 return 0;
742}
743
744/// Test if a diff node is about differences between variables.
745///
746/// @param diff the diff node to test.
747///
748/// @return a pointer to the actual var_diff that @p diff is a type
749/// of, iff it is about differences between variables.
750const var_diff*
752{
753 const var_diff* d = dynamic_cast<const var_diff*>(diff);
754 if (d)
756 return d;
757}
758
759/// Test if a diff node is about differences between functions.
760///
761/// @param diff the diff node to test.
762///
763/// @return a pointer to the actual var_diff that @p diff is a type
764/// of, iff it is about differences between variables.
767{
768 const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
769 if (d)
771 return d;
772}
773
774/// Test if a diff node is about differences between two pointers.
775///
776/// @param diff the diff node to consider.
777///
778/// @return the @p diff converted into an instance of @ref
779/// pointer_diff iff @p diff is about differences between two
780/// pointers.
781const pointer_diff*
783{return dynamic_cast<const pointer_diff*>(diff);}
784
785/// Test if a diff node is about differences between two references.
786///
787/// @param diff the diff node to consider.
788///
789/// @return the @p diff converted into an instance of @ref
790/// reference_diff iff @p diff is about differences between two
791/// references.
792const reference_diff*
794{return dynamic_cast<const reference_diff*>(diff);}
795
796/// Test if a diff node is about differences between two qualified
797/// types.
798///
799/// @param diff the diff node to consider.
800///
801/// @return @p diff converted into an instance of @ref
802/// qualified_type_diff iff @p diff is about differences between two
803/// qualified types.
806{return dynamic_cast<const qualified_type_diff*>(diff);}
807
808/// Test if a diff node is a reference or pointer diff node to a
809/// change that is neither basic type change nor distinct type change.
810///
811/// Note that this function also works on diffs of typedefs of
812/// reference or pointer.
813///
814/// @param diff the diff node to consider.
815///
816/// @return true iff @p diff is a eference or pointer diff node to a
817/// change that is neither basic type change nor distinct type change.
818bool
820{
822 if (const reference_diff* d = is_reference_diff(diff))
823 {
826 return false;
827 return true;
828 }
829 else if (const pointer_diff *d = is_pointer_diff(diff))
830 {
833 return false;
834 return true;
835 }
836
837 return false;
838}
839
840/// Test if a diff node is about differences between two function
841/// parameters.
842///
843/// @param diff the diff node to consider.
844///
845/// @return the @p diff converted into an instance of @ref
846/// reference_diff iff @p diff is about differences between two
847/// function parameters.
848const fn_parm_diff*
850{return dynamic_cast<const fn_parm_diff*>(diff);}
851
852/// Test if a diff node is about differences between two base class
853/// specifiers.
854///
855/// @param diff the diff node to consider.
856///
857/// @return the @p diff converted into an instance of @ref base_diff
858/// iff @p diff is about differences between two base class
859/// specifiers.
860const base_diff*
862{return dynamic_cast<const base_diff*>(diff);}
863
864/// Test if a diff node is about differences between two diff nodes of
865/// different kinds.
866///
867/// @param diff the diff node to consider.
868///
869/// @return the @p diff converted into an instance of @ref
870/// distintc_diff iff @p diff is about differences between two diff
871/// nodes of different kinds.
872const distinct_diff*
874{return dynamic_cast<const distinct_diff*>(diff);}
875
876/// Test if a diff node is a @ref corpus_diff node.
877///
878/// @param diff the diff node to consider.
879///
880/// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
881/// @ref corpus_diff node.
882const corpus_diff*
884{return dynamic_cast<const corpus_diff*>(diff);}
885
886/// Test if a diff node is a child node of a function parameter diff node.
887///
888/// @param diff the diff node to test.
889///
890/// @return true iff @p diff is a child node of a function parameter
891/// diff node.
892bool
894{return diff && is_fn_parm_diff(diff->parent_node());}
895
896/// Test if a diff node is a child node of a base diff node.
897///
898/// @param diff the diff node to test.
899///
900/// @return true iff @p diff is a child node of a base diff node.
901bool
903{return diff && is_base_diff(diff->parent_node());}
904
905/// The default traverse function.
906///
907/// @return true.
908bool
910{return true;}
911
912diff_context::diff_context()
913 : priv_(new diff_context::priv)
914{
915 // Setup all the diff output filters we have.
917
919 add_diff_filter(f);
920
921 // f.reset(new filtering::harmless_filter);
922 // add_diff_filter(f);
923
924 // f.reset(new filtering::harmful_filter);
925 // add_diff_filter(f);
926}
927
928diff_context::~diff_context() = default;
929
930/// Test if logging was requested.
931///
932/// @return true iff logging was requested.
933bool
935{return priv_->do_log_;}
936
937/// Set logging as requested.
938///
939/// @param f the flag
940void
942{priv_->do_log_ = f;}
943
944/// Set the corpus diff relevant to this context.
945///
946/// @param d the corpus_diff we are interested in.
947void
949{priv_->corpus_diff_ = d;}
950
951/// Get the corpus diff for the current context.
952///
953/// @return the corpus diff of this context.
954const corpus_diff_sptr&
956{return priv_->corpus_diff_;}
957
958/// Getter for the first corpus of the corpus diff of the current context.
959///
960/// @return the first corpus of the corpus diff of the current
961/// context, if no corpus diff is associated to the context.
962corpus_sptr
964{
965 if (priv_->corpus_diff_)
966 return priv_->corpus_diff_->first_corpus();
967 return corpus_sptr();
968}
969
970/// Getter for the second corpus of the corpus diff of the current
971/// context.
972///
973/// @return the second corpus of the corpus diff of the current
974/// context, if no corpus diff is associated to the context.
975corpus_sptr
977{
978 if (priv_->corpus_diff_)
979 return priv_->corpus_diff_->second_corpus();
980 return corpus_sptr();
981}
982
983/// Getter of the reporter to be used in this context.
984///
985/// @return the reporter to be used in this context.
988{
989 if (!priv_->reporter_)
990 {
992 priv_->reporter_.reset(new leaf_reporter);
993 else
994 priv_->reporter_.reset(new default_reporter);
995 }
996 ABG_ASSERT(priv_->reporter_);
997 return priv_->reporter_;
998}
999
1000/// Setter of the reporter to be used in this context.
1001///
1002/// @param r the reporter to be used in this context.
1003void
1005{priv_->reporter_ = r;}
1006
1007/// Tests if the current diff context already has a diff for two decls.
1008///
1009/// @param first the first decl to consider.
1010///
1011/// @param second the second decl to consider.
1012///
1013/// @return a pointer to the diff for @p first @p second if found,
1014/// null otherwise.
1016diff_context::has_diff_for(const type_or_decl_base_sptr first,
1017 const type_or_decl_base_sptr second) const
1018{
1019 types_or_decls_diff_map_type::const_iterator i =
1020 priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1021 if (i != priv_->types_or_decls_diff_map.end())
1022 return i->second;
1023 return diff_sptr();
1024}
1025
1026/// Tests if the current diff context already has a diff for two types.
1027///
1028/// @param first the first type to consider.
1029///
1030/// @param second the second type to consider.
1031///
1032/// @return a pointer to the diff for @p first @p second if found,
1033/// null otherwise.
1035diff_context::has_diff_for_types(const type_base_sptr first,
1036 const type_base_sptr second) const
1037{return has_diff_for(first, second);}
1038
1039/// Tests if the current diff context already has a given diff.
1040///
1041///@param d the diff to consider.
1042///
1043/// @return a pointer to the diff found for @p d
1044const diff*
1045diff_context::has_diff_for(const diff* d) const
1046{return has_diff_for(d->first_subject(), d->second_subject()).get();}
1047
1048/// Tests if the current diff context already has a given diff.
1049///
1050///@param d the diff to consider.
1051///
1052/// @return a pointer to the diff found for @p d
1054diff_context::has_diff_for(const diff_sptr d) const
1055{return has_diff_for(d->first_subject(), d->second_subject());}
1056
1057/// Getter for the bitmap that represents the set of categories that
1058/// the user wants to see reported.
1059///
1060/// @return a bitmap that represents the set of categories that the
1061/// user wants to see reported.
1064{return priv_->allowed_category_;}
1065
1066/// Setter for the bitmap that represents the set of categories that
1067/// the user wants to see reported.
1068///
1069/// @param c a bitmap that represents the set of categories that the
1070/// user wants to see represented.
1071void
1073{priv_->allowed_category_ = c;}
1074
1075/// Setter for the bitmap that represents the set of categories that
1076/// the user wants to see reported
1077///
1078/// This function perform a bitwise or between the new set of
1079/// categories and the current ones, and then sets the current
1080/// categories to the result of the or.
1081///
1082/// @param c a bitmap that represents the set of categories that the
1083/// user wants to see represented.
1084void
1086{priv_->allowed_category_ = priv_->allowed_category_ | c;}
1087
1088/// Setter for the bitmap that represents the set of categories that
1089/// the user wants to see reported
1090///
1091/// This function actually unsets bits from the current categories.
1092///
1093/// @param c a bitmap that represents the set of categories to unset
1094/// from the current categories.
1095void
1097{priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1098
1099/// Add a diff for two decls to the cache of the current diff_context.
1100///
1101/// Doing this allows to later find the added diff from its two
1102/// subject decls.
1103///
1104/// @param first the first decl to consider.
1105///
1106/// @param second the second decl to consider.
1107///
1108/// @param the diff to add.
1109void
1110diff_context::add_diff(type_or_decl_base_sptr first,
1112 const diff_sptr d)
1113{priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1114
1115/// Add a diff tree node to the cache of the current diff_context
1116///
1117/// @param d the diff tree node to add.
1118void
1119diff_context::add_diff(const diff* d)
1120{
1121 if (d)
1122 {
1123 diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1124 add_diff(d->first_subject(), d->second_subject(), dif);
1125 }
1126}
1127
1128/// Add a diff tree node to the cache of the current diff_context
1129///
1130/// @param d the diff tree node to add.
1131void
1132diff_context::add_diff(const diff_sptr d)
1133{
1134 if (d)
1135 add_diff(d->first_subject(), d->second_subject(), d);
1136}
1137
1138/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1139/// @ref diff represented by their two subjects.
1140///
1141/// @param first the first subject of the diff.
1142///
1143/// @param second the second subject of the diff.
1144///
1145/// @return the canonical diff for the diff node represented by the
1146/// two diff subjects @p first and @p second. If no canonical diff
1147/// node was registered for these subjects, then a nil node is
1148/// returned.
1151 const type_or_decl_base_sptr second) const
1152{return has_diff_for(first, second);}
1153
1154/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1155/// @ref diff represented by the two subjects of a given diff node.
1156///
1157/// @param d the diff node to get the canonical node for.
1158///
1159/// @return the canonical diff for the diff node represented by the
1160/// two diff subjects of @p d. If no canonical diff node was
1161/// registered for these subjects, then a nil node is returned.
1164{return has_diff_for(d);}
1165
1166/// Setter for the @ref CanonicalDiff "canonical diff node" for the
1167/// @ref diff represented by their two subjects.
1168///
1169/// @param first the first subject of the diff.
1170///
1171/// @param second the second subject of the diff.
1172///
1173/// @param d the new canonical diff.
1174void
1175diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1176 const type_or_decl_base_sptr second,
1177 const diff_sptr d)
1178{
1179 ABG_ASSERT(d);
1180 if (!has_diff_for(first, second))
1181 {
1182 add_diff(first, second, d);
1183 priv_->canonical_diffs.push_back(d);
1184 }
1185}
1186
1187/// If there is is a @ref CanonicalDiff "canonical diff node"
1188/// registered for two diff subjects, return it. Otherwise, register
1189/// a canonical diff node for these two diff subjects and return it.
1190///
1191/// @param first the first subject of the diff.
1192///
1193/// @param second the second subject of the diff.
1194///
1195/// @param d the new canonical diff node.
1196///
1197/// @return the canonical diff node.
1199diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1200 const type_or_decl_base_sptr second,
1201 const diff_sptr canonical_diff)
1202{
1203 ABG_ASSERT(canonical_diff);
1204
1205 diff_sptr canonical = get_canonical_diff_for(first, second);
1206 if (!canonical)
1207 {
1208 canonical = canonical_diff;
1209 set_canonical_diff_for(first, second, canonical);
1210 }
1211 return canonical;
1212}
1213
1214/// Set the canonical diff node property of a given diff node
1215/// appropriately.
1216///
1217/// For a given diff node that has no canonical diff node, retrieve
1218/// the canonical diff node (by looking at its diff subjects and at
1219/// the current context) and set the canonical diff node property of
1220/// the diff node to that canonical diff node. If no canonical diff
1221/// node has been registered to the diff context for the subjects of
1222/// the diff node then, register the canonical diff node as being the
1223/// diff node itself; and set its canonical diff node property as
1224/// such. Otherwise, if the diff node already has a canonical diff
1225/// node, do nothing.
1226///
1227/// @param diff the diff node to initialize the canonical diff node
1228/// property for.
1229void
1231{
1232 if (diff->get_canonical_diff() == 0)
1233 {
1234 diff_sptr canonical =
1235 set_or_get_canonical_diff_for(diff->first_subject(),
1237 diff);
1238 diff->set_canonical_diff(canonical.get());
1239 }
1240}
1241
1242/// Add a diff node to the set of diff nodes that are kept alive for
1243/// the life time of the current instance of diff_context.
1244///
1245/// Note that diff added to the diff cache are kept alive as well, and
1246/// don't need to be passed to this function to be kept alive.
1247///
1248/// @param d the diff node to be kept alive during the life time of
1249/// the current instance of @ref diff_context.
1250void
1252{priv_->live_diffs_.insert(d);}
1253
1254/// Test if a diff node has been traversed.
1255///
1256/// @param d the diff node to consider.
1257///
1258/// @return the first diff node against which @p d is redundant.
1259diff*
1261{
1262 const diff* canonical = d->get_canonical_diff();
1263 ABG_ASSERT(canonical);
1264
1265 size_t ptr_value = reinterpret_cast<size_t>(canonical);
1266 pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1267 if (it != priv_->visited_diff_nodes_.end())
1268 return reinterpret_cast<diff*>(it->second);
1269 else
1270 return 0;
1271}
1272
1273/// Test if a diff node has been traversed.
1274///
1275/// @param d the diff node to consider.
1276///
1277/// @return the first diff node against which @p d is redundant.
1280{
1282 return diff;
1283}
1284
1285/// Mark a diff node as traversed by a traversing algorithm.
1286///
1287/// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1288/// node that is marked as traversed.
1289///
1290/// Subsequent invocations of diff_has_been_visited() on the diff node
1291/// will yield true.
1292void
1294{
1295 if (diff_has_been_visited(d))
1296 return;
1297
1298 const diff* canonical = d->get_canonical_diff();
1299 ABG_ASSERT(canonical);
1300
1301 size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1302 size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1303 priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1304}
1305
1306/// Unmark all the diff nodes that were marked as being traversed.
1307void
1309{priv_->visited_diff_nodes_.clear();}
1310
1311/// This sets a flag that, if it's true, then during the traversing of
1312/// a diff nodes tree each node is visited at most once.
1313///
1314/// @param f if true then during the traversing of a diff nodes tree
1315/// each node is visited at most once.
1316///
1317void
1319{priv_->forbid_visiting_a_node_twice_ = f;}
1320
1321/// This function sets a flag os that if @ref
1322/// forbid_visiting_a_node_twice() returns true, then each time the
1323/// node visitor starts visiting a new interface, it resets the
1324/// memory the systems has about already visited node.
1325///
1326/// @param f the flag to set.
1327void
1329{priv_->reset_visited_diffs_for_each_interface_ = f;}
1330
1331/// Return a flag that, if true, then during the traversing of a diff
1332/// nodes tree each node is visited at most once.
1333///
1334/// @return the boolean flag.
1335bool
1337{return priv_->forbid_visiting_a_node_twice_;}
1338
1339/// Return a flag that, if true, then during the traversing of a diff
1340/// nodes tree each node is visited at most once, while visiting the
1341/// diff tree underneath a given interface (public function or
1342/// variable). Each time a new interface is visited, the nodes
1343/// visited while visiting previous interfaces can be visited again.
1344///
1345/// @return the boolean flag.
1346///
1347/// @return the boolean flag.
1348bool
1350{
1351 return (priv_->forbid_visiting_a_node_twice_
1352 && priv_->reset_visited_diffs_for_each_interface_);
1353}
1354
1355/// Getter for the diff tree nodes filters to apply to diff sub-trees.
1356///
1357/// @return the vector of tree filters to apply to diff sub-trees.
1358const filtering::filters&
1360{return priv_->filters_;}
1361
1362/// Setter for the diff filters to apply to a given diff sub-tree.
1363///
1364/// @param f the new diff filter to add to the vector of diff filters
1365/// to apply to diff sub-trees.
1366void
1368{priv_->filters_.push_back(f);}
1369
1370/// Apply the diff filters to a given diff sub-tree.
1371///
1372/// If the current context is instructed to filter out some categories
1373/// then this function walks the given sub-tree and categorizes its
1374/// nodes by using the filters held by the context.
1375///
1376/// @param diff the diff sub-tree to apply the filters to.
1377void
1379{
1380 if (!diff)
1381 return;
1382
1384 return;
1385
1386 if (!diff->has_changes())
1387 return;
1388
1389 for (filtering::filters::const_iterator i = diff_filters().begin();
1390 i != diff_filters().end();
1391 ++i)
1392 {
1394 if (do_log())
1395 {
1396 std::cerr << "applying a filter to diff '"
1398 << "'...\n";
1399 t.start();
1400 }
1401
1403
1404 if (do_log())
1405 {
1406 t.stop();
1407 std::cerr << "filter applied!:" << t << "\n";
1408
1409 std::cerr << "propagating categories for the same diff node ... \n";
1410 t.start();
1411 }
1412
1414
1415 if (do_log())
1416 {
1417 t.stop();
1418 std::cerr << "category propagated!: " << t << "\n";
1419 }
1420 }
1421
1422 }
1423
1424/// Apply the diff filters to the diff nodes of a @ref corpus_diff
1425/// instance.
1426///
1427/// If the current context is instructed to filter out some categories
1428/// then this function walks the diff tree and categorizes its nodes
1429/// by using the filters held by the context.
1430///
1431/// @param diff the corpus diff to apply the filters to.
1432void
1434{
1435
1436 if (!diff || !diff->has_changes())
1437 return;
1438
1439 for (filtering::filters::const_iterator i = diff_filters().begin();
1440 i != diff_filters().end();
1441 ++i)
1442 {
1445 }
1446}
1447
1448/// Getter for the vector of suppressions that specify which diff node
1449/// reports should be dropped on the floor.
1450///
1451/// @return the set of suppressions.
1452const suppressions_type&
1454{return priv_->suppressions_;}
1455
1456/// Getter for the vector of suppressions that specify which diff node
1457/// reports should be dropped on the floor.
1458///
1459/// @return the set of suppressions.
1462{
1463 // Invalidate negated and direct suppressions caches that are built
1464 // from priv_->suppressions_;
1465 priv_->negated_suppressions_.clear();
1466 priv_->direct_suppressions_.clear();
1467 return priv_->suppressions_;
1468}
1469
1470/// Getter of the negated suppression specifications that are
1471/// comprised in the general vector of suppression specifications
1472/// returned by diff_context::suppressions().
1473///
1474/// Note that the first invocation of this function scans the vector
1475/// returned by diff_context::suppressions() and caches the negated
1476/// suppressions from there.
1477///
1478/// Subsequent invocations of this function just return the cached
1479/// negated suppressions.
1480///
1481/// @return the negated suppression specifications stored in this diff
1482/// context.
1485{
1486 if (priv_->negated_suppressions_.empty())
1487 for (auto s : suppressions())
1489 priv_->negated_suppressions_.push_back(s);
1490
1491 return priv_->negated_suppressions_;
1492}
1493
1494/// Getter of the direct suppression specification (those that are
1495/// not negated) comprised in the general vector of suppression
1496/// specifications returned by diff_context::suppression().
1497///
1498/// Note that the first invocation of this function scans the vector
1499/// returned by diff_context::suppressions() and caches the direct
1500/// suppressions from there.
1501///
1502/// Subsequent invocations of this function just return the cached
1503/// direct suppressions.
1504///
1505/// @return the direct suppression specifications.
1508{
1509 if (priv_->direct_suppressions_.empty())
1510 {
1511 for (auto s : suppressions())
1512 if (!is_negated_suppression(s))
1513 priv_->direct_suppressions_.push_back(s);
1514 }
1515 return priv_->direct_suppressions_;
1516}
1517
1518/// Add a new suppression specification that specifies which diff node
1519/// reports should be dropped on the floor.
1520///
1521/// @param suppr the new suppression specification to add to the
1522/// existing set of suppressions specifications of the diff context.
1523void
1525{
1526 priv_->suppressions_.push_back(suppr);
1527 // Invalidate negated and direct suppressions caches that are built
1528 // from priv_->suppressions_;
1529 priv_->negated_suppressions_.clear();
1530 priv_->direct_suppressions_.clear();
1531}
1532
1533/// Add new suppression specifications that specify which diff node
1534/// reports should be dropped on the floor.
1535///
1536/// @param supprs the new suppression specifications to add to the
1537/// existing set of suppression specifications of the diff context.
1538void
1540{
1541 priv_->suppressions_.insert(priv_->suppressions_.end(),
1542 supprs.begin(), supprs.end());
1543}
1544
1545/// Test if it's requested to perform diff node categorization.
1546///
1547/// @return true iff it's requested to perform diff node
1548/// categorization.
1549bool
1551{return priv_->perform_change_categorization_;}
1552
1553/// Request change categorization or not.
1554///
1555/// @param f true iff change categorization is requested.
1556void
1558{priv_->perform_change_categorization_ = f;}
1559
1560/// Set the flag that indicates if the diff using this context should
1561/// show only leaf changes or not.
1562///
1563/// @param f the new value of the flag that indicates if the diff
1564/// using this context should show only leaf changes or not.
1565void
1567{
1568 // This function can be called only if the reporter hasn't yet been
1569 // created. Once it's been created, we are supposed to live with
1570 // it.
1571 ABG_ASSERT(priv_->reporter_ == 0);
1572 priv_->leaf_changes_only_ = f;
1573}
1574
1575/// Get the flag that indicates if the diff using this context should
1576/// show only leaf changes or not.
1577///
1578/// @return the value of the flag that indicates if the diff using
1579/// this context should show only leaf changes or not.
1580bool
1582{return priv_->leaf_changes_only_;}
1583
1584/// Get the flag that indicates if the diff reports using this context
1585/// should show sizes and offsets in an hexadecimal base or not. If
1586/// not, then they are to be shown in a decimal base.
1587///
1588/// @return true iff sizes and offsets are to be shown in an
1589/// hexadecimal base.
1590bool
1592{return priv_->hex_values_;}
1593
1594/// Set the flag that indicates if diff reports using this context
1595/// should show sizes and offsets in an hexadecimal base or not. If
1596/// not, then they are to be shown in a decimal base.
1597///
1598/// @param f if true then sizes and offsets are to be shown in an
1599/// hexadecimal base.
1600void
1602{priv_->hex_values_ = f;}
1603
1604/// Get the flag that indicates if diff reports using this context
1605/// should show sizes and offsets in bits, rather than bytes.
1606///
1607/// @return true iff sizes and offsets are to be shown in bits.
1608/// Otherwise they are to be shown in bytes.
1609bool
1611{return priv_->show_offsets_sizes_in_bits_;}
1612
1613/// Set the flag that indicates if diff reports using this context
1614/// should show sizes and offsets in bits, rather than bytes.
1615///
1616/// @param f if true then sizes and offsets are to be shown in bits.
1617/// Otherwise they are to be shown in bytes.
1618void
1620{priv_->show_offsets_sizes_in_bits_ = f;}
1621
1622/// Set a flag saying if offset changes should be reported in a
1623/// relative way. That is, if the report should say how of many bits
1624/// a class/struct data member did move.
1625///
1626/// @param f the new boolean value of the flag.
1627void
1629{priv_->show_relative_offset_changes_ = f;}
1630
1631/// Get the flag saying if offset changes should be reported in a
1632/// relative way. That is, if the report should say how of many bits
1633/// a class/struct data member did move.
1634///
1635/// @return the boolean value of the flag.
1636bool
1638{return priv_->show_relative_offset_changes_;}
1639
1640/// Set a flag saying if the comparison module should only show the
1641/// diff stats.
1642///
1643/// @param f the flag to set.
1644void
1646{priv_->show_stats_only_ = f;}
1647
1648/// Test if the comparison module should only show the diff stats.
1649///
1650/// @return true if the comparison module should only show the diff
1651/// stats, false otherwise.
1652bool
1654{return priv_->show_stats_only_;}
1655
1656/// Setter for the property that says if the comparison module should
1657/// show the soname changes in its report.
1658///
1659/// @param f the new value of the property.
1660void
1662{priv_->show_soname_change_ = f;}
1663
1664/// Getter for the property that says if the comparison module should
1665/// show the soname changes in its report.
1666///
1667/// @return the value of the property.
1668bool
1670{return priv_->show_soname_change_;}
1671
1672/// Setter for the property that says if the comparison module should
1673/// show the architecture changes in its report.
1674///
1675/// @param f the new value of the property.
1676void
1678{priv_->show_architecture_change_ = f;}
1679
1680/// Getter for the property that says if the comparison module should
1681/// show the architecture changes in its report.
1682///
1683/// @return the value of the property.
1684bool
1686{return priv_->show_architecture_change_;}
1687
1688/// Set a flag saying to show the deleted functions.
1689///
1690/// @param f true to show deleted functions.
1691void
1693{priv_->show_deleted_fns_ = f;}
1694
1695/// @return true if we want to show the deleted functions, false
1696/// otherwise.
1697bool
1699{return priv_->show_deleted_fns_;}
1700
1701/// Set a flag saying to show the changed functions.
1702///
1703/// @param f true to show the changed functions.
1704void
1706{priv_->show_changed_fns_ = f;}
1707
1708/// @return true if we want to show the changed functions, false otherwise.
1709bool
1711{return priv_->show_changed_fns_;}
1712
1713/// Set a flag saying to show the added functions.
1714///
1715/// @param f true to show the added functions.
1716void
1718{priv_->show_added_fns_ = f;}
1719
1720/// @return true if we want to show the added functions, false
1721/// otherwise.
1722bool
1724{return priv_->show_added_fns_;}
1725
1726/// Set a flag saying to show the deleted variables.
1727///
1728/// @param f true to show the deleted variables.
1729void
1731{priv_->show_deleted_vars_ = f;}
1732
1733/// @return true if we want to show the deleted variables, false
1734/// otherwise.
1735bool
1737{return priv_->show_deleted_vars_;}
1738
1739/// Set a flag saying to show the changed variables.
1740///
1741/// @param f true to show the changed variables.
1742void
1744{priv_->show_changed_vars_ = f;}
1745
1746/// @return true if we want to show the changed variables, false otherwise.
1747bool
1749{return priv_->show_changed_vars_;}
1750
1751/// Set a flag saying to show the added variables.
1752///
1753/// @param f true to show the added variables.
1754void
1756{priv_->show_added_vars_ = f;}
1757
1758/// @return true if we want to show the added variables, false
1759/// otherwise.
1760bool
1762{return priv_->show_added_vars_;}
1763
1764bool
1765diff_context::show_linkage_names() const
1766{return priv_->show_linkage_names_;}
1767
1768void
1769diff_context::show_linkage_names(bool f)
1770{priv_->show_linkage_names_= f;}
1771
1772/// Set a flag saying to show location information.
1773///
1774/// @param f true to show location information.
1775void
1777{priv_->show_locs_= f;}
1778
1779/// @return true if we want to show location information, false
1780/// otherwise.
1781bool
1783{return priv_->show_locs_;}
1784
1785/// A getter for the flag that says if we should report about
1786/// functions or variables diff nodes that have *exclusively*
1787/// redundant diff tree children nodes.
1788///
1789/// @return the flag.
1790bool
1792{return priv_->show_redundant_changes_;}
1793
1794/// A setter for the flag that says if we should report about
1795/// functions or variables diff nodes that have *exclusively*
1796/// redundant diff tree children nodes.
1797///
1798/// @param f the flag to set.
1799void
1801{priv_->show_redundant_changes_ = f;}
1802
1803/// Getter for the flag that indicates if symbols not referenced by
1804/// any debug info are to be compared and reported about.
1805///
1806/// @return the boolean flag.
1807bool
1809{return priv_->show_syms_unreferenced_by_di_;}
1810
1811/// Setter for the flag that indicates if symbols not referenced by
1812/// any debug info are to be compared and reported about.
1813///
1814/// @param f the new flag to set.
1815void
1817{priv_->show_syms_unreferenced_by_di_ = f;}
1818
1819/// Getter for the flag that indicates if symbols not referenced by
1820/// any debug info and that got added are to be reported about.
1821///
1822/// @return true iff symbols not referenced by any debug info and that
1823/// got added are to be reported about.
1824bool
1826{return priv_->show_added_syms_unreferenced_by_di_;}
1827
1828/// Setter for the flag that indicates if symbols not referenced by
1829/// any debug info and that got added are to be reported about.
1830///
1831/// @param f the new flag that says if symbols not referenced by any
1832/// debug info and that got added are to be reported about.
1833void
1835{priv_->show_added_syms_unreferenced_by_di_ = f;}
1836
1837/// Setter for the flag that indicates if changes on types unreachable
1838/// from global functions and variables are to be reported.
1839///
1840/// @param f if true, then changes on types unreachable from global
1841/// functions and variables are to be reported.
1842void
1844{priv_->show_unreachable_types_ = f;}
1845
1846/// Getter for the flag that indicates if changes on types unreachable
1847/// from global functions and variables are to be reported.
1848///
1849/// @return true iff changes on types unreachable from global
1850/// functions and variables are to be reported.
1851bool
1853{return priv_->show_unreachable_types_;}
1854
1855/// Getter of the flag that indicates if the leaf reporter should
1856/// display a summary of the interfaces impacted by a given leaf
1857/// change or not.
1858///
1859/// @return the flag that indicates if the leaf reporter should
1860/// display a summary of the interfaces impacted by a given leaf
1861/// change or not.
1862bool
1864{return priv_->show_impacted_interfaces_;}
1865
1866/// Setter of the flag that indicates if the leaf reporter should
1867/// display a summary of the interfaces impacted by a given leaf
1868/// change or not.
1869///
1870/// @param f the new value of the flag that indicates if the leaf
1871/// reporter should display a summary of the interfaces impacted by a
1872/// given leaf change or not.
1873void
1875{priv_->show_impacted_interfaces_ = f;}
1876
1877/// Setter for the default output stream used by code of the
1878/// comparison engine. By default the default output stream is a NULL
1879/// pointer.
1880///
1881/// @param o a pointer to the default output stream.
1882void
1884{priv_->default_output_stream_ = o;}
1885
1886/// Getter for the default output stream used by code of the
1887/// comparison engine. By default the default output stream is a NULL
1888/// pointer.
1889///
1890/// @return a pointer to the default output stream.
1891ostream*
1893{return priv_->default_output_stream_;}
1894
1895/// Setter for the errror output stream used by code of the comparison
1896/// engine. By default the error output stream is a NULL pointer.
1897///
1898/// @param o a pointer to the error output stream.
1899void
1901{priv_->error_output_stream_ = o;}
1902
1903/// Getter for the errror output stream used by code of the comparison
1904/// engine. By default the error output stream is a NULL pointer.
1905///
1906/// @return a pointer to the error output stream.
1907ostream*
1909{return priv_->error_output_stream_;}
1910
1911/// Test if the comparison engine should dump the diff tree for the
1912/// changed functions and variables it has.
1913///
1914/// @return true if after the comparison, the engine should dump the
1915/// diff tree for the changed functions and variables it has.
1916bool
1918{return priv_->dump_diff_tree_;}
1919
1920/// Set if the comparison engine should dump the diff tree for the
1921/// changed functions and variables it has.
1922///
1923/// @param f true if after the comparison, the engine should dump the
1924/// diff tree for the changed functions and variables it has.
1925void
1927{priv_->dump_diff_tree_ = f;}
1928
1929/// Emit a textual representation of a diff tree to the error output
1930/// stream of the current context, for debugging purposes.
1931///
1932/// @param d the diff tree to serialize to the error output associated
1933/// to the current instance of @ref diff_context.
1934void
1936{
1937 if (error_output_stream())
1939}
1940
1941/// Emit a textual representation of a @ref corpus_diff tree to the error
1942/// output stream of the current context, for debugging purposes.
1943///
1944/// @param d the @ref corpus_diff tree to serialize to the error
1945/// output associated to the current instance of @ref diff_context.
1946void
1948{
1949 if (error_output_stream())
1951}
1952// </diff_context stuff>
1953
1954// <diff stuff>
1955
1956/// Constructor for the @ref diff type.
1957///
1958/// This constructs a diff between two subjects that are actually
1959/// declarations; the first and the second one.
1960///
1961/// @param first_subject the first decl (subject) of the diff.
1962///
1963/// @param second_subject the second decl (subject) of the diff.
1964diff::diff(type_or_decl_base_sptr first_subject,
1965 type_or_decl_base_sptr second_subject)
1966 : priv_(new priv(first_subject, second_subject,
1969 /*reported_once=*/false,
1970 /*currently_reporting=*/false))
1971{}
1972
1973/// Constructor for the @ref diff type.
1974///
1975/// This constructs a diff between two subjects that are actually
1976/// declarations; the first and the second one.
1977///
1978/// @param first_subject the first decl (subject) of the diff.
1979///
1980/// @param second_subject the second decl (subject) of the diff.
1981///
1982/// @param ctxt the context of the diff. Note that this context
1983/// object must stay alive during the entire life time of the current
1984/// instance of @ref diff. Otherwise, memory corruption issues occur.
1985diff::diff(type_or_decl_base_sptr first_subject,
1986 type_or_decl_base_sptr second_subject,
1987 diff_context_sptr ctxt)
1988 : priv_(new priv(first_subject, second_subject,
1989 ctxt, NO_CHANGE_CATEGORY,
1990 /*reported_once=*/false,
1991 /*currently_reporting=*/false))
1992{}
1993
1994/// Test if logging was requested
1995///
1996/// @return true iff logging was requested.
1997bool
1999{return context()->do_log();}
2000
2001/// Request logging (or not)
2002///
2003/// @param f true iff logging is to be requested.
2004void
2006{context()->do_log(f);}
2007
2008/// Flag a given diff node as being traversed.
2009///
2010/// For certain diff nodes like @ref class_diff, it's important to
2011/// avoid traversing the node again while it's already being
2012/// traversed; otherwise this leads to infinite loops. So the
2013/// diff::begin_traversing() and diff::end_traversing() methods flag a
2014/// given node as being traversed (or not), so that
2015/// diff::is_traversing() can tell if the node is being traversed.
2016///
2017/// Note that traversing a node means visiting it *and* visiting its
2018/// children nodes.
2019///
2020/// The canonical node is marked as being traversed too.
2021///
2022/// These functions are called by the traversing code.
2023void
2025{
2027 if (priv_->canonical_diff_)
2028 priv_->canonical_diff_->priv_->traversing_ = true;
2029 priv_->traversing_ = true;
2030}
2031
2032/// Tell if a given node is being traversed or not.
2033///
2034/// Note that traversing a node means visiting it *and* visiting its
2035/// children nodes.
2036///
2037/// It's the canonical node which is looked at, actually.
2038///
2039/// Please read the comments for the diff::begin_traversing() for mode
2040/// context.
2041///
2042/// @return true if the current instance of @diff is being traversed.
2043bool
2045{
2046 if (priv_->canonical_diff_)
2047 return priv_->canonical_diff_->priv_->traversing_;
2048 return priv_->traversing_;
2049}
2050
2051/// Flag a given diff node as not being traversed anymore.
2052///
2053/// Note that traversing a node means visiting it *and* visiting its
2054/// children nodes.
2055///
2056/// Please read the comments of the function diff::begin_traversing()
2057/// for mode context.
2058void
2060{
2062 if (priv_->canonical_diff_)
2063 priv_->canonical_diff_->priv_->traversing_ = false;
2064 priv_->traversing_ = false;
2065}
2066
2067/// Finish the insertion of a diff tree node into the diff graph.
2068///
2069/// This function might be called several times. It must perform the
2070/// insertion only once.
2071///
2072/// For instance, certain kinds of diff tree node have specific
2073/// children nodes that are populated after the constructor of the
2074/// diff tree node has been called. In that case, calling overloads
2075/// of this method ensures that these children nodes are properly
2076/// gathered and setup.
2077void
2079{
2080 if (diff::priv_->finished_)
2081 return;
2083 diff::priv_->finished_ = true;
2084}
2085
2086/// Getter of the first subject of the diff.
2087///
2088/// @return the first subject of the diff.
2091{return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2092
2093/// Getter of the second subject of the diff.
2094///
2095/// @return the second subject of the diff.
2098{return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2099
2100/// Getter for the children nodes of the current @ref diff node.
2101///
2102/// @return a vector of the children nodes.
2103const vector<diff*>&
2105{return priv_->children_;}
2106
2107/// Getter for the parent node of the current @ref diff node.
2108///
2109/// @return the parent node of the current @ref diff node.
2110const diff*
2112{return priv_->parent_;}
2113
2114/// Getter for the canonical diff of the current instance of @ref
2115/// diff.
2116///
2117/// Note that the canonical diff node for the current instanc eof diff
2118/// node must have been set by invoking
2119/// class_diff::initialize_canonical_diff() on the current instance of
2120/// diff node.
2121///
2122/// @return the canonical diff node or null if none was set.
2123diff*
2125{return priv_->canonical_diff_;}
2126
2127/// Setter for the canonical diff of the current instance of @ref
2128/// diff.
2129///
2130/// @param d the new canonical node to set.
2131void
2133{priv_->canonical_diff_ = d;}
2134
2135/// Add a new child node to the vector of children nodes for the
2136/// current @ref diff node.
2137///
2138/// @param d the new child node to add to the children nodes.
2139void
2141{
2142 ABG_ASSERT(d);
2143
2144 // Ensure 'd' is kept alive for the life time of the context of this
2145 // diff.
2146 context()->keep_diff_alive(d);
2147
2148 // Add the underlying pointer of 'd' to the vector of children.
2149 // Note that this vector holds no reference to 'd'. This is to avoid
2150 // reference cycles. The reference to 'd' is held by the context of
2151 // this diff, thanks to the call to context()->keep_diff_alive(d)
2152 // above.
2153 priv_->children_.push_back(d.get());
2154
2155 d->priv_->parent_ = this;
2156}
2157
2158/// Getter of the context of the current diff.
2159///
2160/// @return the context of the current diff.
2163{return priv_->get_context();}
2164
2165/// Setter of the context of the current diff.
2166///
2167/// @param c the new context to set.
2168void
2170{priv_->ctxt_ = c;}
2171
2172/// Tests if we are currently in the middle of emitting a report for
2173/// this diff.
2174///
2175/// @return true if we are currently emitting a report for the
2176/// current diff, false otherwise.
2177bool
2179{
2180 if (priv_->canonical_diff_)
2181 return priv_->canonical_diff_->priv_->currently_reporting_;
2182 return priv_->currently_reporting_;
2183}
2184
2185/// Sets a flag saying if we are currently in the middle of emitting
2186/// a report for this diff.
2187///
2188/// @param f true if we are currently emitting a report for the
2189/// current diff, false otherwise.
2190void
2192{
2193 if (priv_->canonical_diff_)
2194 priv_->canonical_diff_->priv_->currently_reporting_ = f;
2195 priv_->currently_reporting_ = f;
2196}
2197
2198/// Tests if a report has already been emitted for the current diff.
2199///
2200/// @return true if a report has already been emitted for the
2201/// current diff, false otherwise.
2202bool
2204{
2205 ABG_ASSERT(priv_->canonical_diff_);
2206 return priv_->canonical_diff_->priv_->reported_once_;
2207}
2208
2209/// The generic traversing code that walks a given diff sub-tree.
2210///
2211/// Note that there is a difference between traversing a diff node and
2212/// visiting it. Basically, traversing a diff node means visiting it
2213/// and visiting its children nodes too. So one can visit a node
2214/// without traversing it. But traversing a node without visiting it
2215/// is not possible.
2216///
2217/// Note that the insertion of the "generic view" of the diff node
2218/// into the graph being traversed is done "on the fly". The
2219/// insertion of the "typed view" of the diff node into the graph is
2220/// done implicitely. To learn more about the generic and typed view
2221/// of the diff node, please read the introductory comments of the
2222/// @ref diff class.
2223///
2224/// Note that by default this traversing code visits a given class of
2225/// equivalence of a diff node only once. This behaviour can been
2226/// changed by calling
2227/// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2228/// very risky as it might create endless loops while visiting a diff
2229/// tree graph that has changes that refer to themselves; that is,
2230/// diff tree graphs with cycles.
2231///
2232/// When a diff node is encountered, the
2233/// diff_node_visitor::visit_begin() method is invoked on the diff
2234/// node first.
2235///
2236/// If the diff node has already been visited, then
2237/// node_visitor::visit_end() is called on it and the node traversing
2238/// is done; the children of the diff node are not visited in this
2239/// case.
2240///
2241/// If the diff node has *NOT* been visited yet, then the
2242/// diff_node_visitor::visit() method is invoked with it's 'pre'
2243/// argument set to true. Then if the diff_node_visitor::visit()
2244/// returns true, then the children nodes of the diff node are
2245/// visited. Otherwise, no children nodes of the diff node is
2246/// visited and the diff_node_visitor::visit_end() is called.
2247
2248/// After the children nodes are visited (and only if they are
2249/// visited) the diff_node_visitor::visit() method is invoked with
2250/// it's 'pre' argument set to false. And then the
2251/// diff_node_visitor::visit_end() is called.
2252///
2253/// @param v the entity that visits each node of the diff sub-tree.
2254///
2255/// @return true to tell the caller that all of the sub-tree could be
2256/// walked. This instructs the caller to keep walking the rest of the
2257/// tree. Return false otherwise.
2258bool
2260{
2261 // Insert the "generic view" of the diff node into its graph.
2263
2264 v.visit_begin(this);
2265
2266 bool already_visited = false;
2267 if (context()->visiting_a_node_twice_is_forbidden()
2268 && context()->diff_has_been_visited(this))
2269 already_visited = true;
2270
2271 bool mark_visited_nodes_as_traversed =
2273
2274 if (!already_visited && !v.visit(this, /*pre=*/true))
2275 {
2276 v.visit_end(this);
2277 if (mark_visited_nodes_as_traversed)
2278 context()->mark_diff_as_visited(this);
2279 return false;
2280 }
2281
2283 && !is_traversing()
2284 && !already_visited)
2285 {
2287 for (vector<diff*>::const_iterator i = children_nodes().begin();
2288 i != children_nodes().end();
2289 ++i)
2290 {
2291 if (!(*i)->traverse(v))
2292 {
2293 v.visit_end(this);
2294 if (mark_visited_nodes_as_traversed)
2295 context()->mark_diff_as_visited(this);
2297 return false;
2298 }
2299 }
2301 }
2302
2303 if (!v.visit(this, /*pref=*/false))
2304 {
2305 v.visit_end(this);
2306 if (mark_visited_nodes_as_traversed)
2307 context()->mark_diff_as_visited(this);
2308 return false;
2309 }
2310
2311 v.visit_end(this);
2312 if (!already_visited && mark_visited_nodes_as_traversed)
2313 context()->mark_diff_as_visited(this);
2314
2315 return true;
2316}
2317
2318/// Sets a flag saying if a report has already been emitted for the
2319/// current diff.
2320///
2321/// @param f true if a report has already been emitted for the
2322/// current diff, false otherwise.
2323void
2325{
2326 ABG_ASSERT(priv_->canonical_diff_);
2327 priv_->canonical_diff_->priv_->reported_once_ = f;
2328 priv_->reported_once_ = f;
2329}
2330
2331/// Getter for the local category of the current diff tree node.
2332///
2333/// The local category represents the set of categories of a diff
2334/// node, not taking in account the categories inherited from its
2335/// children nodes.
2336///
2337/// @return the local category of the current diff tree node.
2340{return priv_->local_category_;}
2341
2342/// Getter of the category of the class of equivalence of the current
2343/// diff tree node.
2344///
2345/// That is, if the current diff tree node has a canonical node,
2346/// return the category of that canonical node. Otherwise, return the
2347/// category of the current node.
2348///
2349/// @return the category of the class of equivalence of the current
2350/// tree node.
2353{
2354 diff* canonical = get_canonical_diff();
2355 return canonical ? canonical->get_category() : get_category();
2356}
2357
2358/// Getter for the category of the current diff tree node.
2359///
2360/// This category represents the union of the local category and the
2361/// categories inherited from the children diff nodes.
2362///
2363/// @return the category of the current diff tree node.
2366{return priv_->category_;}
2367
2368/// Adds the current diff tree node to an additional set of
2369/// categories. Note that the categories include thoses inherited
2370/// from the children nodes of this diff node.
2371///
2372/// @param c a bit-map representing the set of categories to add the
2373/// current diff tree node to.
2374///
2375/// @return the resulting bit-map representing the categories this
2376/// current diff tree node belongs to, including those inherited from
2377/// its children nodes.
2380{
2381 priv_->category_ = priv_->category_ | c;
2382 return priv_->category_;
2383}
2384
2385/// Adds the current diff tree node to the categories resulting from
2386/// the local changes of the current diff node.
2387///
2388/// @param c a bit-map representing the set of categories to add the
2389/// current diff tree node to.
2390///
2391/// @return the resulting bit-map representing the categories this
2392/// current diff tree node belongs to.
2395{
2396 priv_->local_category_ = priv_->local_category_ | c;
2397 return priv_->local_category_;
2398}
2399
2400/// Adds the current diff tree node to the categories resulting from
2401/// the local and inherited changes of the current diff node.
2402///
2403/// @param c a bit-map representing the set of categories to add the
2404/// current diff tree node to.
2405void
2407{
2409 add_to_category(c);
2410}
2411
2412/// Remove the current diff tree node from an a existing sef of
2413/// categories. The categories include those inherited from the
2414/// children nodes of the current diff node.
2415///
2416/// @param c a bit-map representing the set of categories to add the
2417/// current diff tree node to.
2418///
2419/// @return the resulting bit-map representing the categories this
2420/// current diff tree onde belongs to, including the categories
2421/// inherited from the children nodes of the current diff node.
2424{
2425 priv_->category_ = priv_->category_ & ~c;
2426 return priv_->category_;
2427}
2428
2429/// Remove the current diff tree node from the categories resulting
2430/// from the local changes.
2431///
2432/// @param c a bit-map representing the set of categories to add the
2433/// current diff tree node to.
2434///
2435/// @return the resulting bit-map representing the categories this
2436/// current diff tree onde belongs to.
2439{
2440 priv_->local_category_ = priv_->local_category_ & ~c;
2441 return priv_->local_category_;
2442}
2443
2444/// Set the category of the current @ref diff node. This category
2445/// includes the categories inherited from the children nodes of the
2446/// current diff node.
2447///
2448/// @param c the new category for the current diff node.
2449void
2451{priv_->category_ = c;}
2452
2453/// Set the local category of the current @ref diff node.
2454///
2455/// @param c the new category for the current diff node.
2456void
2458{priv_->local_category_ = c;}
2459
2460/// Test if this diff tree node is to be filtered out for reporting
2461/// purposes.
2462///
2463/// There is a difference between a diff node being filtered out and
2464/// being suppressed. Being suppressed means that there is a
2465/// suppression specification that suppresses the diff node
2466/// specifically. Being filtered out mean the node is either
2467/// suppressed, or it's filtered out because the suppression of a set
2468/// of (children) nodes caused this node to be filtered out as well.
2469/// For instance, if a function diff has all its children diff nodes
2470/// suppressed and if the function diff node carries no local change,
2471/// then the function diff node itself is going to be filtered out.
2472///
2473/// The function tests if the categories of the diff tree node are
2474/// "forbidden" by the context or not.
2475///
2476/// @return true iff the current diff node should NOT be reported.
2477bool
2479{
2480 if (diff * canonical = get_canonical_diff())
2481 if ((canonical->get_category() & SUPPRESSED_CATEGORY
2482 || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2483 && !canonical->is_allowed_by_specific_negated_suppression()
2484 && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2485 && !canonical->has_parent_allowed_by_specific_negated_suppression())
2486 // The canonical type was suppressed either by a user-provided
2487 // suppression specification or by a "private-type" suppression
2488 // specification.. This means all the classes of equivalence of
2489 // that canonical type were suppressed. So this node should be
2490 // filtered out.
2491 return true;
2492 return priv_->is_filtered_out(get_category());
2493}
2494
2495/// Test if this diff tree node is to be filtered out for reporting
2496/// purposes, but by considering only the categories that were *NOT*
2497/// inherited from its children nodes.
2498///
2499/// The function tests if the local categories of the diff tree node
2500/// are "forbidden" by the context or not.
2501///
2502/// @return true iff the current diff node should NOT be reported,
2503/// with respect to its local categories.
2504bool
2506{return priv_->is_filtered_out(get_local_category());}
2507
2508/// Test if this diff tree node is to be filtered out for reporting
2509/// purposes, but without considering the categories that can /force/
2510/// the node to be unfiltered.
2511///
2512/// The function tests if the categories of the diff tree node are
2513/// "forbidden" by the context or not.
2514///
2515/// @return true iff the current diff node should should NOT be
2516/// reported, with respect to the categories that might filter it out
2517/// only.
2518bool
2520{
2525
2526 return priv_->is_filtered_out(c);
2527}
2528
2529/// Test if the current diff node has been suppressed by a
2530/// user-provided suppression specification.
2531///
2532/// @return true if the current diff node has been suppressed by a
2533/// user-provided suppression list.
2534bool
2536{
2537 bool is_private = false;
2538 return is_suppressed(is_private);
2539}
2540
2541/// Test if the current diff node has been suppressed by a
2542/// user-provided suppression specification or by an auto-generated
2543/// "private type" suppression specification.
2544///
2545/// Note that private type suppressions are auto-generated from the
2546/// path to where public headers are, as given by the user.
2547///
2548/// Here is the current algorithm:
2549///
2550/// First, suppress this diff node if it's not matched by any
2551/// negated suppression specifications. If it's not
2552/// suppressed, then suppress it if it's matched by direct
2553/// suppression specifications.
2554///
2555/// @param is_private_type out parameter if the current diff node was
2556/// suppressed because it's a private type then this parameter is set
2557/// to true.
2558///
2559/// @return true if the current diff node has been suppressed by a
2560/// user-provided suppression list.
2561bool
2562diff::is_suppressed(bool &is_private_type) const
2563{
2564 // If there is at least one negated suppression, then suppress the
2565 // current diff node by default ...
2566 bool do_suppress = !context()->negated_suppressions().empty();
2567
2568 // ... unless there is at least one negated suppression that
2569 // specifically asks to keep this diff node around (un-suppressed).
2570 for (auto n : context()->negated_suppressions())
2571 if (!n->suppresses_diff(this))
2572 {
2573 do_suppress = false;
2574 break;
2575 }
2576
2577 // Then walk the set of non-negated, AKA direct, suppressions. If at
2578 // least one suppression suppresses the current diff node then the
2579 // diff node must be suppressed.
2580 for (auto d : context()->direct_suppressions())
2581 if (d->suppresses_diff(this))
2582 {
2583 do_suppress = true;
2585 is_private_type = true;
2586 break;
2587 }
2588
2589 return do_suppress;
2590}
2591
2592/// Test if this diff tree node should be reported.
2593///
2594/// @return true iff the current node should be reported.
2595bool
2597{
2598 if (has_changes() && !is_filtered_out())
2599 return true;
2600 return false;
2601}
2602
2603/// Test if this diff tree node should be reported when considering
2604/// the categories that were *NOT* inherited from its children nodes.
2605///
2606/// @return true iff the current node should be reported.
2607bool
2609{
2610 if (has_local_changes()
2612 return true;
2613 return false;
2614}
2615
2616/// Test if this diff node is allowed (prevented from being
2617/// suppressed) by at least one negated suppression specification.
2618///
2619/// @return true if this diff node is meant to be allowed by at least
2620/// one negated suppression specification.
2621bool
2623{
2624 const suppressions_type& suppressions = context()->suppressions();
2625 for (suppressions_type::const_iterator i = suppressions.begin();
2626 i != suppressions.end();
2627 ++i)
2628 {
2630 && !(*i)->suppresses_diff(this))
2631 return true;
2632 }
2633 return false;
2634}
2635
2636/// Test if the current diff node has a descendant node which is
2637/// specifically allowed by a negated suppression specification.
2638///
2639/// @return true iff the current diff node has a descendant node
2640/// which is specifically allowed by a negated suppression
2641/// specification.
2642bool
2644{
2646 return result;
2647}
2648
2649/// Test if the current diff node has a parent node which is
2650/// specifically allowed by a negated suppression specification.
2651///
2652/// @return true iff the current diff node has a parent node which is
2653/// specifically allowed by a negated suppression specification.
2654bool
2656{
2658 return result;
2659}
2660
2661/// Get a pretty representation of the current @ref diff node.
2662///
2663/// This is suitable for e.g. emitting debugging traces for the diff
2664/// tree nodes.
2665///
2666/// @return the pretty representation of the diff node.
2667const string&
2669{
2670 if (priv_->pretty_representation_.empty())
2671 priv_->pretty_representation_ = "empty_diff";
2672 return priv_->pretty_representation_;
2673}
2674
2675/// Default implementation of the hierachy chaining virtual function.
2676///
2677/// There are several types of diff nodes that have logical children
2678/// nodes; for instance, a typedef_diff has the diff of the underlying
2679/// type as a child node. A var_diff has the diff of the types of the
2680/// variables as a child node, etc.
2681///
2682/// But because the @ref diff base has a generic representation for
2683/// children nodes of the all the types of @ref diff nodes (regardless
2684/// of the specific most-derived type of diff node) that one can get
2685/// using the method diff::children_nodes(), one need to populate that
2686/// vector of children node.
2687///
2688/// Populating that vector of children node is done by this function;
2689/// it must be overloaded by each most-derived type of diff node that
2690/// extends the @ref diff type.
2691void
2693{}
2694
2695// </diff stuff>
2696
2697// <type_diff_base stuff>
2698
2699type_diff_base::type_diff_base(type_base_sptr first_subject,
2700 type_base_sptr second_subject,
2701 diff_context_sptr ctxt)
2702 : diff(first_subject, second_subject, ctxt),
2703 priv_(new priv)
2704{}
2705
2706type_diff_base::~type_diff_base()
2707{}
2708// </type_diff_base stuff>
2709
2710// <decl_diff_base stuff>
2711
2712/// Constructor of @ref decl_diff_base.
2713///
2714/// @param first_subject the first subject of the diff.
2715///
2716/// @param second_subject the second subject of the diff.
2717///
2718/// @param ctxt the context of the diff. This object must stay alive
2719/// at least during the life time of the current instance of @ref
2720/// decl_diff_base, otherwise, memory corruption issues occur.
2721decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2722 decl_base_sptr second_subject,
2723 diff_context_sptr ctxt)
2724 : diff(first_subject, second_subject, ctxt),
2725 priv_(new priv)
2726{}
2727
2728decl_diff_base::~decl_diff_base()
2729{}
2730
2731// </decl_diff_base stuff>
2732
2733// <distinct_diff stuff>
2734
2735/// @return a pretty representation for the @ref distinct_diff node.
2736const string&
2738{
2739 if (diff::priv_->pretty_representation_.empty())
2740 {
2741 std::ostringstream o;
2742 o << "distinct_diff[";
2743 if (first_subject())
2744 o << first_subject()->get_pretty_representation();
2745 else
2746 o << "null";
2747 o << ", ";
2748 if (second_subject())
2749 o << second_subject()->get_pretty_representation() ;
2750 else
2751 o << "null";
2752 o << "]" ;
2753 diff::priv_->pretty_representation_ = o.str();
2754 }
2755 return diff::priv_->pretty_representation_;
2756}
2757
2758/// Populate the vector of children node of the @ref diff base type
2759/// sub-object of this instance of @distinct_diff.
2760///
2761/// The children nodes can then later be retrieved using
2762/// diff::children_nodes().
2763void
2765{
2767
2770}
2771
2772/// Constructor for @ref distinct_diff.
2773///
2774/// Note that the two entities considered for the diff (and passed in
2775/// parameter) must be of different kinds.
2776///
2777/// @param first the first entity to consider for the diff.
2778///
2779/// @param second the second entity to consider for the diff.
2780///
2781/// @param ctxt the context of the diff. Note that this context
2782/// object must stay alive at least during the life time of the
2783/// current instance of @ref distinct_diff. Otherwise memory
2784/// corruption issues occur.
2787 diff_context_sptr ctxt)
2788 : diff(first, second, ctxt),
2789 priv_(new priv)
2791
2792/// Getter for the first subject of the diff.
2793///
2794/// @return the first subject of the diff.
2797{return first_subject();}
2798
2799/// Getter for the second subject of the diff.
2800///
2801/// @return the second subject of the diff.
2804{return second_subject();}
2805
2806/// Getter for the child diff of this distinct_diff instance.
2807///
2808/// When a distinct_diff has two subjects that are different but
2809/// compatible, then the distinct_diff instance has a child diff node
2810/// (named the compatible child diff) that is the diff between the two
2811/// subjects stripped from their typedefs. Otherwise, the compatible
2812/// child diff is nul.
2813///
2814/// Note that two diff subjects (that compare different) are
2815/// considered compatible if stripping typedefs out of them makes them
2816/// comparing equal.
2817///
2818/// @return the compatible child diff node, if any. Otherwise, null.
2819const diff_sptr
2821{
2822 if (!priv_->compatible_child_diff)
2823 {
2824 type_base_sptr fs = strip_typedef(is_type(first())),
2825 ss = strip_typedef(is_type(second()));
2826
2827 if (fs && ss
2830 priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2832 context());
2833 }
2834 return priv_->compatible_child_diff;
2835}
2836
2837/// Test if the two arguments are of different kind, or that are both
2838/// NULL.
2839///
2840/// @param first the first argument to test for similarity in kind.
2841///
2842/// @param second the second argument to test for similarity in kind.
2843///
2844/// @return true iff the two arguments are of different kind.
2845bool
2848{
2849 if (!!first != !!second)
2850 return true;
2851 if (!first && !second)
2852 // We do consider diffs of two empty decls as a diff of distinct
2853 // kinds, for now.
2854 return true;
2855 if (first == second)
2856 return false;
2857
2858 const type_or_decl_base &f = *first, &s = *second;
2859 return typeid(f) != typeid(s);
2860}
2861
2862/// @return true if the two subjects of the diff are different, false
2863/// otherwise.
2864bool
2866{return first() != second();}
2867
2868/// @return the kind of local change carried by the current diff node.
2869/// The value returned is zero if the current node carries no local
2870/// change.
2871enum change_kind
2873{
2874 // Changes on a distinct_diff are all local.
2875 if (has_changes())
2877 return NO_CHANGE_KIND;
2878}
2879
2880/// Emit a report about the current diff instance.
2881///
2882/// @param out the output stream to send the diff report to.
2883///
2884/// @param indent the indentation string to use in the report.
2885void
2886distinct_diff::report(ostream& out, const string& indent) const
2887{
2888 context()->get_reporter()->report(*this, out, indent);
2889}
2890
2891/// Try to diff entities that are of distinct kinds.
2892///
2893/// @param first the first entity to consider for the diff.
2894///
2895/// @param second the second entity to consider for the diff.
2896///
2897/// @param ctxt the context of the diff.
2898///
2899/// @return a non-null diff if a diff object could be built, null
2900/// otherwise.
2903 const type_or_decl_base_sptr second,
2904 diff_context_sptr ctxt)
2905{
2907 return distinct_diff_sptr();
2908
2909 distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2910
2911 ctxt->initialize_canonical_diff(result);
2912
2913 return result;
2914}
2915
2916/// </distinct_diff stuff>
2917
2918/// Try to compute a diff on two instances of DiffType representation.
2919///
2920/// The function template performs the diff if and only if the decl
2921/// representations are of a DiffType.
2922///
2923/// @tparm DiffType the type of instances to diff.
2924///
2925/// @param first the first representation of decl to consider in the
2926/// diff computation.
2927///
2928/// @param second the second representation of decl to consider in the
2929/// diff computation.
2930///
2931/// @param ctxt the diff context to use.
2932///
2933///@return the diff of the two types @p first and @p second if and
2934///only if they represent the parametrized type DiffType. Otherwise,
2935///returns a NULL pointer value.
2936template<typename DiffType>
2939 const type_or_decl_base_sptr second,
2940 diff_context_sptr ctxt)
2941{
2942 if (shared_ptr<DiffType> f =
2943 dynamic_pointer_cast<DiffType>(first))
2944 {
2945 shared_ptr<DiffType> s =
2946 dynamic_pointer_cast<DiffType>(second);
2947 if (!s)
2948 return diff_sptr();
2949 return compute_diff(f, s, ctxt);
2950 }
2951 return diff_sptr();
2952}
2953
2954
2955/// This is a specialization of @ref try_to_diff() template to diff
2956/// instances of @ref class_decl.
2957///
2958/// @param first the first representation of decl to consider in the
2959/// diff computation.
2960///
2961/// @param second the second representation of decl to consider in the
2962/// diff computation.
2963///
2964/// @param ctxt the diff context to use.
2965template<>
2968 const type_or_decl_base_sptr second,
2969 diff_context_sptr ctxt)
2970{
2971 if (class_decl_sptr f =
2972 dynamic_pointer_cast<class_decl>(first))
2973 {
2974 class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2975 if (!s)
2976 return diff_sptr();
2977
2978 if (f->get_is_declaration_only())
2979 {
2980 class_decl_sptr f2 =
2981 is_class_type (f->get_definition_of_declaration());
2982 if (f2)
2983 f = f2;
2984 }
2985 if (s->get_is_declaration_only())
2986 {
2987 class_decl_sptr s2 =
2988 is_class_type(s->get_definition_of_declaration());
2989 if (s2)
2990 s = s2;
2991 }
2992 return compute_diff(f, s, ctxt);
2993 }
2994 return diff_sptr();
2995}
2996
2997/// Try to diff entities that are of distinct kinds.
2998///
2999/// @param first the first entity to consider for the diff.
3000///
3001/// @param second the second entity to consider for the diff.
3002///
3003/// @param ctxt the context of the diff.
3004///
3005/// @return a non-null diff if a diff object could be built, null
3006/// otherwise.
3007static diff_sptr
3008try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3009 const type_or_decl_base_sptr second,
3010 diff_context_sptr ctxt)
3011{return compute_diff_for_distinct_kinds(first, second, ctxt);}
3012
3013/// Compute the difference between two types.
3014///
3015/// The function considers every possible types known to libabigail
3016/// and runs the appropriate diff function on them.
3017///
3018/// Whenever a new kind of type decl is supported by abigail, if we
3019/// want to be able to diff two instances of it, we need to update
3020/// this function to support it.
3021///
3022/// @param first the first type decl to consider for the diff
3023///
3024/// @param second the second type decl to consider for the diff.
3025///
3026/// @param ctxt the diff context to use.
3027///
3028/// @return the resulting diff. It's a pointer to a descendent of
3029/// abigail::comparison::diff.
3030static diff_sptr
3031compute_diff_for_types(const type_or_decl_base_sptr& first,
3032 const type_or_decl_base_sptr& second,
3033 const diff_context_sptr& ctxt)
3034{
3035 type_or_decl_base_sptr f = first;
3036 type_or_decl_base_sptr s = second;
3037
3038 diff_sptr d;
3039
3040 ((d = try_to_diff<type_decl>(f, s, ctxt))
3041 ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3042 ||(d = try_to_diff<union_decl>(f, s,ctxt))
3043 ||(d = try_to_diff<class_decl>(f, s,ctxt))
3044 ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3045 ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3046 ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3047 ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3048 ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3049 ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3050 ||(d = try_to_diff<function_type>(f, s, ctxt))
3051 ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3052
3053 ABG_ASSERT(d);
3054
3055 return d;
3056}
3057
3060{return static_cast<diff_category>(static_cast<unsigned>(c1)
3061 | static_cast<unsigned>(c2));}
3062
3064operator|=(diff_category& c1, diff_category c2)
3065{
3066 c1 = c1 | c2;
3067 return c1;
3068}
3069
3071operator&=(diff_category& c1, diff_category c2)
3072{
3073 c1 = c1 & c2;
3074 return c1;
3075}
3076
3078operator^(diff_category c1, diff_category c2)
3079{return static_cast<diff_category>(static_cast<unsigned>(c1)
3080 ^ static_cast<unsigned>(c2));}
3081
3084{return static_cast<diff_category>(static_cast<unsigned>(c1)
3085 & static_cast<unsigned>(c2));}
3086
3089{return static_cast<diff_category>(~static_cast<unsigned>(c));}
3090
3091
3092/// Getter of a bitmap made of the set of change categories that are
3093/// considered harmless.
3094///
3095/// @return the bitmap made of the set of change categories that are
3096/// considered harmless.
3099{
3116}
3117
3118/// Getter of a bitmap made of the set of change categories that are
3119/// considered harmful.
3120///
3121/// @return the bitmap made of the set of change categories that are
3122/// considered harmful.
3125{
3129}
3130
3131/// Serialize an instance of @ref diff_category to an output stream.
3132///
3133/// @param o the output stream to serialize @p c to.
3134///
3135/// @param c the instance of diff_category to serialize.
3136///
3137/// @return the output stream to serialize @p c to.
3138ostream&
3139operator<<(ostream& o, diff_category c)
3140{
3141 bool emitted_a_category = false;
3142
3143 if (c == NO_CHANGE_CATEGORY)
3144 {
3145 o << "NO_CHANGE_CATEGORY";
3146 emitted_a_category = true;
3147 }
3148
3149 if (c & ACCESS_CHANGE_CATEGORY)
3150 {
3151 if (emitted_a_category)
3152 o << "|";
3153 o << "ACCESS_CHANGE_CATEGORY";
3154 emitted_a_category |= true;
3155 }
3156
3158 {
3159 if (emitted_a_category)
3160 o << "|";
3161 o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3162 emitted_a_category |= true;
3163 }
3164
3166 {
3167 if (emitted_a_category)
3168 o << "|";
3169 o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3170 emitted_a_category |= true;
3171 }
3172
3174 {
3175 if (emitted_a_category)
3176 o << "|";
3177 o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3178 emitted_a_category |= true;
3179 }
3180
3182 {
3183 if (emitted_a_category)
3184 o << "|";
3185 o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3186 emitted_a_category |= true;
3187 }
3188
3190 {
3191 if (emitted_a_category)
3192 o << "|";
3193 o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3194 emitted_a_category |= true;
3195 }
3196
3198 {
3199 if (emitted_a_category)
3200 o << "|";
3201 o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3202 emitted_a_category |= true;
3203 }
3204
3206 {
3207 if (emitted_a_category)
3208 o << "|";
3209 o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3210 emitted_a_category |= true;
3211 }
3212
3214 {
3215 if (emitted_a_category)
3216 o << "|";
3217 o << "HARMLESS_UNION_CHANGE_CATEGORY";
3218 emitted_a_category |= true;
3219 }
3220
3221 if (c & SUPPRESSED_CATEGORY)
3222 {
3223 if (emitted_a_category)
3224 o << "|";
3225 o << "SUPPRESSED_CATEGORY";
3226 emitted_a_category |= true;
3227 }
3228
3229 if (c & PRIVATE_TYPE_CATEGORY)
3230 {
3231 if (emitted_a_category)
3232 o << "|";
3233 o << "PRIVATE_TYPE_CATEGORY";
3234 emitted_a_category |= true;
3235 }
3236
3238 {
3239 if (emitted_a_category)
3240 o << "|";
3241 o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3242 emitted_a_category |= true;
3243 }
3244
3246 {
3247 if (emitted_a_category)
3248 o << "|";
3249 o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3250 emitted_a_category |= true;
3251 }
3252
3253 if (c & REDUNDANT_CATEGORY)
3254 {
3255 if (emitted_a_category)
3256 o << "|";
3257 o << "REDUNDANT_CATEGORY";
3258 emitted_a_category |= true;
3259 }
3260
3262 {
3263 if (emitted_a_category)
3264 o << "|";
3265 o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3266 emitted_a_category |= true;
3267 }
3268
3270 {
3271 if (emitted_a_category)
3272 o << "|";
3273 o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3274 emitted_a_category |= true;
3275 }
3276
3278 {
3279 if (emitted_a_category)
3280 o << "|";
3281 o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3282 emitted_a_category |= true;
3283 }
3284
3286 {
3287 if (emitted_a_category)
3288 o << "|";
3289 o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3290 emitted_a_category |= true;
3291 }
3292
3294 {
3295 if (emitted_a_category)
3296 o << "|";
3297 o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3298 emitted_a_category |= true;
3299 }
3300
3302 {
3303 if (emitted_a_category)
3304 o << "|";
3305 o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3306 emitted_a_category |= true;
3307 }
3308
3310 {
3311 if (emitted_a_category)
3312 o << "|";
3313 o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3314 emitted_a_category |= true;
3315 }
3316
3318 {
3319 if (emitted_a_category)
3320 o << "|";
3321 o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3322 emitted_a_category |= true;
3323 }
3324
3326 {
3327 if (emitted_a_category)
3328 o << "|";
3329 o << "HAS_ALLOWED_CHANGE_CATEGORY";
3330 emitted_a_category |= true;
3331 }
3332
3334 {
3335 if (emitted_a_category)
3336 o << "|";
3337 o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3338 emitted_a_category |= true;
3339 }
3340
3342 {
3343 if (emitted_a_category)
3344 o << "|";
3345 o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3346 emitted_a_category |= true;
3347 }
3348
3349 return o;
3350}
3351
3352/// Compute the difference between two decls.
3353///
3354/// The function consider every possible decls known to libabigail and
3355/// runs the appropriate diff function on them.
3356///
3357/// Whenever a new kind of non-type decl is supported by abigail, if
3358/// we want to be able to diff two instances of it, we need to update
3359/// this function to support it.
3360///
3361/// @param first the first decl to consider for the diff
3362///
3363/// @param second the second decl to consider for the diff.
3364///
3365/// @param ctxt the diff context to use.
3366///
3367/// @return the resulting diff.
3368static diff_sptr
3369compute_diff_for_decls(const decl_base_sptr first,
3370 const decl_base_sptr second,
3371 diff_context_sptr ctxt)
3372{
3373
3374 diff_sptr d;
3375
3376 ((d = try_to_diff<function_decl>(first, second, ctxt))
3377 || (d = try_to_diff<var_decl>(first, second, ctxt))
3378 || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3379
3380 ABG_ASSERT(d);
3381
3382 return d;
3383}
3384
3385/// Compute the difference between two decls. The decls can represent
3386/// either type declarations, or non-type declaration.
3387///
3388/// Note that the two decls must have been created in the same @ref
3389/// environment, otherwise, this function aborts.
3390///
3391/// @param first the first decl to consider.
3392///
3393/// @param second the second decl to consider.
3394///
3395/// @param ctxt the diff context to use.
3396///
3397/// @return the resulting diff, or NULL if the diff could not be
3398/// computed.
3400compute_diff(const decl_base_sptr first,
3401 const decl_base_sptr second,
3402 diff_context_sptr ctxt)
3403{
3404 if (!first || !second)
3405 return diff_sptr();
3406
3407 diff_sptr d;
3408 if (is_type(first) && is_type(second))
3409 d = compute_diff_for_types(first, second, ctxt);
3410 else
3411 d = compute_diff_for_decls(first, second, ctxt);
3412 ABG_ASSERT(d);
3413 return d;
3414}
3415
3416/// Compute the difference between two types.
3417///
3418/// Note that the two types must have been created in the same @ref
3419/// environment, otherwise, this function aborts.
3420///
3421/// @param first the first type to consider.
3422///
3423/// @param second the second type to consider.
3424///
3425/// @param ctxt the diff context to use.
3426///
3427/// @return the resulting diff, or NULL if the diff couldn't be
3428/// computed.
3430compute_diff(const type_base_sptr first,
3431 const type_base_sptr second,
3432 diff_context_sptr ctxt)
3433{
3434 decl_base_sptr f = get_type_declaration(first),
3435 s = get_type_declaration(second);
3436
3437 diff_sptr d = compute_diff_for_types(f,s, ctxt);
3438 ABG_ASSERT(d);
3439 return d;
3440}
3441
3442/// Get a copy of the pretty representation of a diff node.
3443///
3444/// @param d the diff node to consider.
3445///
3446/// @return the pretty representation string.
3447string
3449{
3450 if (!d)
3451 return "";
3452 string prefix= "diff of ";
3453 return prefix + get_pretty_representation(d->first_subject());
3454}
3455
3456// <var_diff stuff>
3457
3458/// Populate the vector of children node of the @ref diff base type
3459/// sub-object of this instance of @ref var_diff.
3460///
3461/// The children node can then later be retrieved using
3462/// diff::children_node().
3463void
3466
3467/// @return the pretty representation for this current instance of
3468/// @ref var_diff.
3469const string&
3471{
3472 if (diff::priv_->pretty_representation_.empty())
3473 {
3474 std::ostringstream o;
3475 o << "var_diff["
3476 << first_subject()->get_pretty_representation()
3477 << ", "
3478 << second_subject()->get_pretty_representation()
3479 << "]";
3480 diff::priv_->pretty_representation_ = o.str();
3481 }
3482 return diff::priv_->pretty_representation_;
3483}
3484/// Constructor for @ref var_diff.
3485///
3486/// @param first the first instance of @ref var_decl to consider in
3487/// the diff.
3488///
3489/// @param second the second instance of @ref var_decl to consider in
3490/// the diff.
3491///
3492/// @param type_diff the diff between types of the instances of
3493/// var_decl.
3494///
3495/// @param ctxt the diff context to use.
3497 var_decl_sptr second,
3498 diff_sptr type_diff,
3499 diff_context_sptr ctxt)
3500 : decl_diff_base(first, second, ctxt),
3501 priv_(new priv)
3502{priv_->type_diff_ = type_diff;}
3503
3504/// Getter for the first @ref var_decl of the diff.
3505///
3506/// @return the first @ref var_decl of the diff.
3509{return dynamic_pointer_cast<var_decl>(first_subject());}
3510
3511/// Getter for the second @ref var_decl of the diff.
3512///
3513/// @return the second @ref var_decl of the diff.
3516{return dynamic_pointer_cast<var_decl>(second_subject());}
3517
3518/// Getter for the diff of the types of the instances of @ref
3519/// var_decl.
3520///
3521/// @return the diff of the types of the instances of @ref var_decl.
3524{
3525 if (diff_sptr result = priv_->type_diff_.lock())
3526 return result;
3527 else
3528 {
3529 result = compute_diff(first_var()->get_type(),
3530 second_var()->get_type(),
3531 context());
3532 context()->keep_diff_alive(result);
3533 priv_->type_diff_ = result;
3534 return result;
3535 }
3536}
3537
3538/// Return true iff the diff node has a change.
3539///
3540/// @return true iff the diff node has a change.
3541bool
3543{return *first_var() != *second_var();}
3544
3545/// @return the kind of local change carried by the current diff node.
3546/// The value returned is zero if the current node carries no local
3547/// change.
3548enum change_kind
3550{
3551 ir::change_kind k = ir::NO_CHANGE_KIND;
3552 if (!equals(*first_var(), *second_var(), &k))
3553 return k & ir::ALL_LOCAL_CHANGES_MASK;
3554 return ir::NO_CHANGE_KIND;
3555}
3556
3557/// Report the diff in a serialized form.
3558///
3559/// @param out the stream to serialize the diff to.
3560///
3561/// @param indent the prefix to use for the indentation of this
3562/// serialization.
3563void
3564var_diff::report(ostream& out, const string& indent) const
3565{
3566 context()->get_reporter()->report(*this, out, indent);
3567}
3568
3569/// Compute the diff between two instances of @ref var_decl.
3570///
3571/// Note that the two decls must have been created in the same @ref
3572/// environment, otherwise, this function aborts.
3573///
3574/// @param first the first @ref var_decl to consider for the diff.
3575///
3576/// @param second the second @ref var_decl to consider for the diff.
3577///
3578/// @param ctxt the diff context to use.
3579///
3580/// @return the resulting diff between the two @ref var_decl.
3583 const var_decl_sptr second,
3584 diff_context_sptr ctxt)
3585{
3586 var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3587 ctxt->initialize_canonical_diff(d);
3588
3589 return d;
3590}
3591
3592// </var_diff stuff>
3593
3594// <pointer_type_def stuff>
3595
3596/// Populate the vector of children node of the @ref diff base type
3597/// sub-object of this instance of @ref pointer_diff.
3598///
3599/// The children node can then later be retrieved using
3600/// diff::children_node().
3601void
3604
3605/// Constructor for a pointer_diff.
3606///
3607/// @param first the first pointer to consider for the diff.
3608///
3609/// @param second the secon pointer to consider for the diff.
3610///
3611/// @param ctxt the diff context to use.
3613 pointer_type_def_sptr second,
3614 diff_sptr underlying,
3615 diff_context_sptr ctxt)
3616 : type_diff_base(first, second, ctxt),
3617 priv_(new priv(underlying))
3618{}
3619
3620/// Getter for the first subject of a pointer diff
3621///
3622/// @return the first pointer considered in this pointer diff.
3625{return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3626
3627/// Getter for the second subject of a pointer diff
3628///
3629/// @return the second pointer considered in this pointer diff.
3632{return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3633
3634/// @return the pretty represenation for the current instance of @ref
3635/// pointer_diff.
3636const string&
3638{
3639 if (diff::priv_->pretty_representation_.empty())
3640 {
3641 std::ostringstream o;
3642 o << "pointer_diff["
3643 << first_subject()->get_pretty_representation()
3644 << ", "
3645 << second_subject()->get_pretty_representation()
3646 << "]";
3647 diff::priv_->pretty_representation_ = o.str();
3648 }
3649 return diff::priv_->pretty_representation_;
3650}
3651
3652/// Return true iff the current diff node carries a change.
3653///
3654/// @return true iff the current diff node carries a change.
3655bool
3657{return first_pointer() != second_pointer();}
3658
3659/// @return the kind of local change carried by the current diff node.
3660/// The value returned is zero if the current node carries no local
3661/// change.
3662enum change_kind
3664{
3665 ir::change_kind k = ir::NO_CHANGE_KIND;
3666 if (!equals(*first_pointer(), *second_pointer(), &k))
3667 return k & ir::ALL_LOCAL_CHANGES_MASK;
3668 return ir::NO_CHANGE_KIND;
3669}
3670
3671/// Getter for the diff between the pointed-to types of the pointers
3672/// of this diff.
3673///
3674/// @return the diff between the pointed-to types.
3677{return priv_->underlying_type_diff_;}
3678
3679/// Setter for the diff between the pointed-to types of the pointers
3680/// of this diff.
3681///
3682/// @param d the new diff between the pointed-to types of the pointers
3683/// of this diff.
3684void
3686{priv_->underlying_type_diff_ = d;}
3687
3688/// Report the diff in a serialized form.
3689///
3690/// @param out the stream to serialize the diff to.
3691///
3692/// @param indent the prefix to use for the indentation of this
3693/// serialization.
3694void
3695pointer_diff::report(ostream& out, const string& indent) const
3696{
3697 context()->get_reporter()->report(*this, out, indent);
3698}
3699
3700/// Compute the diff between between two pointers.
3701///
3702/// Note that the two types must have been created in the same @ref
3703/// environment, otherwise, this function aborts.
3704///
3705/// @param first the pointer to consider for the diff.
3706///
3707/// @param second the pointer to consider for the diff.
3708///
3709/// @return the resulting diff between the two pointers.
3710///
3711/// @param ctxt the diff context to use.
3714 pointer_type_def_sptr second,
3715 diff_context_sptr ctxt)
3716{
3717 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3718 second->get_pointed_to_type(),
3719 ctxt);
3720 pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3721 ctxt->initialize_canonical_diff(result);
3722
3723 return result;
3724}
3725
3726// </pointer_type_def>
3727
3728// <subrange_diff >
3729
3730/// Constructor of the @ref subrange_diff diff node type.
3731///
3732/// @param first the first subrange type to consider for the diff.
3733///
3734/// @param second the second subrange type to consider for the diff.
3735///
3736/// @param underlying_type_diff the underlying type diff between @p
3737/// first and @p second.
3738///
3739/// @param ctxt the diff context to use.
3741(const array_type_def::subrange_sptr& first,
3742 const array_type_def::subrange_sptr& second,
3743 const diff_sptr& underlying_type_diff,
3744 const diff_context_sptr ctxt)
3745 : type_diff_base(first, second, ctxt),
3746 priv_(new priv(underlying_type_diff))
3747{}
3748
3749
3750/// Getter of the first subrange of the current instance @ref
3751/// subrange_diff.
3752///
3753/// @return The first subrange of the current instance @ref subrange_diff.
3757
3758/// Getter of the second subrange of the current instance @ref
3759/// subrange_diff.
3760///
3761/// @return The second subrange of the current instance @ref
3762/// subrange_diff.
3766
3767/// Getter of the diff node of the underlying types of the current
3768/// @ref subrange_diff diff node.
3769///
3770/// @return The diff node of the underlying types of the current @ref
3771/// subrange_diff diff node.
3772const diff_sptr
3774{return priv_->underlying_type_diff_;}
3775
3776/// Getter the pretty representation of the @ref subrange_diff diff
3777/// node.
3778///
3779/// @return The pretty representation of the @ref subrange_diff diff node.
3780const string&
3782{
3783 if (diff::priv_->pretty_representation_.empty())
3784 {
3785 std::ostringstream o;
3786 o << "subrange_diff["
3787 << first_subject()->get_pretty_representation()
3788 << ","
3789 << second_subject()->get_pretty_representation()
3790 << "]";
3791 diff::priv_->pretty_representation_ = o.str();
3792 }
3793 return diff::priv_->pretty_representation_;
3794}
3795
3796/// Test if the current @ref subrange_diff node carries any change.
3797///
3798/// @return true iff the current @ref subrange_diff node carries any
3799/// change.
3800bool
3802{return *first_subrange() != *second_subrange();}
3803
3804/// Test if the current @ref subrange_diff node carries any local
3805/// change.
3806///
3807/// @return true iff the current @ref subrange_diff node carries any
3808/// local change.
3809enum change_kind
3811{
3812 ir::change_kind k = ir::NO_CHANGE_KIND;
3813 if (!equals(*first_subrange(), *second_subrange(), &k))
3814 return k & ir::ALL_LOCAL_CHANGES_MASK;
3815 return ir::NO_CHANGE_KIND;
3816}
3817
3818/// Report about the changes carried by this node.
3819///
3820/// @param out the output stream to send the report to.
3821///
3822/// @param indent the indentation string to use.
3823void
3824subrange_diff::report(ostream& out, const string& indent) const
3825{context()->get_reporter()->report(*this, out, indent);}
3826
3827/// Populate the vector of children node of the @ref diff base type
3828/// sub-object of this instance of @ref subrange_diff.
3829///
3830/// The children node can then later be retrieved using
3831/// diff::children_node().
3832void
3835
3836/// Compute the diff between two instances of @ref subrange_diff.
3837///
3838/// Note that the two decls must have been created in the same @ref
3839/// environment, otherwise, this function aborts.
3840///
3841/// @param first the first @ref subrange_diff to consider for the diff.
3842///
3843/// @param second the second @ref subrange_diff to consider for the diff.
3844///
3845/// @param ctxt the diff context to use.
3846///
3847/// @return the resulting diff between the two @ref subrange_diff.
3851 diff_context_sptr ctxt)
3852{
3853 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3854 second->get_underlying_type(),
3855 ctxt);
3856
3857 subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
3858 ctxt->initialize_canonical_diff(result);
3859 return result;
3860}
3861
3862//</subrange_diff >
3863
3864
3865// <array_type_def>
3866
3867/// Populate the vector of children node of the @ref diff base type
3868/// sub-object of this instance of @ref array_diff.
3869///
3870/// The children node can then later be retrieved using
3871/// diff::children_node().
3872void
3875
3876/// Constructor for array_diff
3877///
3878/// @param first the first array_type of the diff.
3879///
3880/// @param second the second array_type of the diff.
3881///
3882/// @param element_type_diff the diff between the two array element
3883/// types.
3884///
3885/// @param ctxt the diff context to use.
3887 const array_type_def_sptr second,
3888 diff_sptr element_type_diff,
3889 diff_context_sptr ctxt)
3890 : type_diff_base(first, second, ctxt),
3891 priv_(new priv(element_type_diff))
3892{}
3893
3894/// Getter for the first array of the diff.
3895///
3896/// @return the first array of the diff.
3899{return dynamic_pointer_cast<array_type_def>(first_subject());}
3900
3901/// Getter for the second array of the diff.
3902///
3903/// @return for the second array of the diff.
3906{return dynamic_pointer_cast<array_type_def>(second_subject());}
3907
3908/// Getter for the diff between the two types of array elements.
3909///
3910/// @return the diff between the two types of array elements.
3911const diff_sptr&
3913{return priv_->element_type_diff_;}
3914
3915/// Setter for the diff between the two array element types.
3916///
3917/// @param d the new diff betweend the two array element types.
3918void
3920{priv_->element_type_diff_ = d;}
3921
3922/// @return the pretty representation for the current instance of @ref
3923/// array_diff.
3924const string&
3926{
3927 if (diff::priv_->pretty_representation_.empty())
3928 {
3929 std::ostringstream o;
3930 o << "array_diff["
3931 << first_subject()->get_pretty_representation()
3932 << ", "
3933 << second_subject()->get_pretty_representation()
3934 << "]";
3935 diff::priv_->pretty_representation_ = o.str();
3936 }
3937 return diff::priv_->pretty_representation_;
3938}
3939
3940/// Return true iff the current diff node carries a change.
3941///
3942/// @return true iff the current diff node carries a change.
3943bool
3945{
3946 bool l = false;
3947
3948 // the array element types match check for differing dimensions
3949 // etc...
3951 f = dynamic_pointer_cast<array_type_def>(first_subject()),
3952 s = dynamic_pointer_cast<array_type_def>(second_subject());
3953
3954 if (f->get_name() != s->get_name())
3955 l |= true;
3956 if (f->get_size_in_bits() != s->get_size_in_bits())
3957 l |= true;
3958 if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3959 l |= true;
3960
3961 l |= element_type_diff()
3962 ? element_type_diff()->has_changes()
3963 : false;
3964
3965 return l;
3966}
3967
3968
3969/// @return the kind of local change carried by the current diff node.
3970/// The value returned is zero if the current node carries no local
3971/// change.
3972enum change_kind
3974{
3975 ir::change_kind k = ir::NO_CHANGE_KIND;
3976 if (!equals(*first_array(), *second_array(), &k))
3977 return k & ir::ALL_LOCAL_CHANGES_MASK;
3978 return ir::NO_CHANGE_KIND;
3979}
3980
3981/// Report the diff in a serialized form.
3982///
3983/// @param out the output stream to serialize the dif to.
3984///
3985/// @param indent the string to use for indenting the report.
3986void
3987array_diff::report(ostream& out, const string& indent) const
3988{
3989 context()->get_reporter()->report(*this, out, indent);
3990}
3991
3992/// Compute the diff between two arrays.
3993///
3994/// Note that the two types must have been created in the same @ref
3995/// environment, otherwise, this function aborts.
3996///
3997/// @param first the first array to consider for the diff.
3998///
3999/// @param second the second array to consider for the diff.
4000///
4001/// @param ctxt the diff context to use.
4004 array_type_def_sptr second,
4005 diff_context_sptr ctxt)
4006{
4007 diff_sptr d = compute_diff_for_types(first->get_element_type(),
4008 second->get_element_type(),
4009 ctxt);
4010 array_diff_sptr result(new array_diff(first, second, d, ctxt));
4011 ctxt->initialize_canonical_diff(result);
4012 return result;
4013}
4014// </array_type_def>
4015
4016// <reference_type_def>
4017
4018/// Populate the vector of children node of the @ref diff base type
4019/// sub-object of this instance of @ref reference_diff.
4020///
4021/// The children node can then later be retrieved using
4022/// diff::children_node().
4023void
4026
4027/// Constructor for reference_diff
4028///
4029/// @param first the first reference_type of the diff.
4030///
4031/// @param second the second reference_type of the diff.
4032///
4033/// @param ctxt the diff context to use.
4035 const reference_type_def_sptr second,
4036 diff_sptr underlying,
4037 diff_context_sptr ctxt)
4038 : type_diff_base(first, second, ctxt),
4039 priv_(new priv(underlying))
4040{}
4041
4042/// Getter for the first reference of the diff.
4043///
4044/// @return the first reference of the diff.
4047{return dynamic_pointer_cast<reference_type_def>(first_subject());}
4048
4049/// Getter for the second reference of the diff.
4050///
4051/// @return for the second reference of the diff.
4054{return dynamic_pointer_cast<reference_type_def>(second_subject());}
4055
4056
4057/// Getter for the diff between the two referred-to types.
4058///
4059/// @return the diff between the two referred-to types.
4060const diff_sptr&
4062{return priv_->underlying_type_diff_;}
4063
4064/// Setter for the diff between the two referred-to types.
4065///
4066/// @param d the new diff betweend the two referred-to types.
4067diff_sptr&
4069{
4070 priv_->underlying_type_diff_ = d;
4071 return priv_->underlying_type_diff_;
4072}
4073
4074/// @return the pretty representation for the current instance of @ref
4075/// reference_diff.
4076const string&
4078{
4079 if (diff::priv_->pretty_representation_.empty())
4080 {
4081 std::ostringstream o;
4082 o << "reference_diff["
4083 << first_subject()->get_pretty_representation()
4084 << ", "
4085 << second_subject()->get_pretty_representation()
4086 << "]";
4087 diff::priv_->pretty_representation_ = o.str();
4088 }
4089 return diff::priv_->pretty_representation_;
4090}
4091
4092/// Return true iff the current diff node carries a change.
4093///
4094/// @return true iff the current diff node carries a change.
4095bool
4097{
4098 return first_reference() != second_reference();
4099}
4100
4101/// @return the kind of local change carried by the current diff node.
4102/// The value returned is zero if the current node carries no local
4103/// change.
4104enum change_kind
4106{
4107 ir::change_kind k = ir::NO_CHANGE_KIND;
4108 if (!equals(*first_reference(), *second_reference(), &k))
4109 return k & ir::ALL_LOCAL_CHANGES_MASK;
4110 return ir::NO_CHANGE_KIND;
4111}
4112
4113/// Report the diff in a serialized form.
4114///
4115/// @param out the output stream to serialize the dif to.
4116///
4117/// @param indent the string to use for indenting the report.
4118void
4119reference_diff::report(ostream& out, const string& indent) const
4120{
4121 context()->get_reporter()->report(*this, out, indent);
4122}
4123
4124/// Compute the diff between two references.
4125///
4126/// Note that the two types must have been created in the same @ref
4127/// environment, otherwise, this function aborts.
4128///
4129/// @param first the first reference to consider for the diff.
4130///
4131/// @param second the second reference to consider for the diff.
4132///
4133/// @param ctxt the diff context to use.
4137 diff_context_sptr ctxt)
4138{
4139 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4140 second->get_pointed_to_type(),
4141 ctxt);
4142 reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4143 ctxt->initialize_canonical_diff(result);
4144 return result;
4145}
4146// </reference_type_def>
4147
4148// <qualified_type_diff stuff>
4149
4150/// Populate the vector of children node of the @ref diff base type
4151/// sub-object of this instance of @ref qualified_type_diff.
4152///
4153/// The children node can then later be retrieved using
4154/// diff::children_node().
4155void
4158
4159/// Constructor for qualified_type_diff.
4160///
4161/// @param first the first qualified type of the diff.
4162///
4163/// @param second the second qualified type of the diff.
4164///
4165/// @param ctxt the diff context to use.
4166qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4167 qualified_type_def_sptr second,
4168 diff_sptr under,
4169 diff_context_sptr ctxt)
4170 : type_diff_base(first, second, ctxt),
4171 priv_(new priv(under))
4172{}
4173
4174/// Getter for the first qualified type of the diff.
4175///
4176/// @return the first qualified type of the diff.
4177const qualified_type_def_sptr
4179{return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4180
4181/// Getter for the second qualified type of the diff.
4182///
4183/// @return the second qualified type of the diff.
4184const qualified_type_def_sptr
4186{return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4187
4188/// Getter for the diff between the underlying types of the two
4189/// qualified types.
4190///
4191/// @return the diff between the underlying types of the two qualified
4192/// types.
4195{return priv_->underlying_type_diff;}
4196
4197/// Getter for the diff between the most underlying non-qualified
4198/// types of two qualified types.
4199///
4200/// @return the diff between the most underlying non-qualified types
4201/// of two qualified types.
4204{
4205 if (!priv_->leaf_underlying_type_diff)
4206 priv_->leaf_underlying_type_diff
4207 = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4209 context());
4210
4211 return priv_->leaf_underlying_type_diff;
4212}
4213
4214/// Setter for the diff between the underlying types of the two
4215/// qualified types.
4216///
4217/// @return the diff between the underlying types of the two qualified
4218/// types.
4219void
4221{priv_->underlying_type_diff = d;}
4222
4223/// @return the pretty representation of the current instance of @ref
4224/// qualified_type_diff.
4225const string&
4227{
4228 if (diff::priv_->pretty_representation_.empty())
4229 {
4230 std::ostringstream o;
4231 o << "qualified_type_diff["
4232 << first_subject()->get_pretty_representation()
4233 << ", "
4234 << second_subject()->get_pretty_representation()
4235 << "]";
4236 diff::priv_->pretty_representation_ = o.str();
4237 }
4238 return diff::priv_->pretty_representation_;
4239}
4240
4241/// Return true iff the current diff node carries a change.
4242///
4243/// @return true iff the current diff node carries a change.
4244bool
4247
4248/// @return the kind of local change carried by the current diff node.
4249/// The value returned is zero if the current node carries no local
4250/// change.
4251enum change_kind
4253{
4254 ir::change_kind k = ir::NO_CHANGE_KIND;
4256 return k & ir::ALL_LOCAL_CHANGES_MASK;
4257 return ir::NO_CHANGE_KIND;
4258}
4259
4260/// Report the diff in a serialized form.
4261///
4262/// @param out the output stream to serialize to.
4263///
4264/// @param indent the string to use to indent the lines of the report.
4265void
4266qualified_type_diff::report(ostream& out, const string& indent) const
4267{
4268 context()->get_reporter()->report(*this, out, indent);
4269}
4270
4271/// Compute the diff between two qualified types.
4272///
4273/// Note that the two types must have been created in the same @ref
4274/// environment, otherwise, this function aborts.
4275///
4276/// @param first the first qualified type to consider for the diff.
4277///
4278/// @param second the second qualified type to consider for the diff.
4279///
4280/// @param ctxt the diff context to use.
4281qualified_type_diff_sptr
4282compute_diff(const qualified_type_def_sptr first,
4283 const qualified_type_def_sptr second,
4284 diff_context_sptr ctxt)
4285{
4286 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4287 second->get_underlying_type(),
4288 ctxt);
4289 qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4290 d, ctxt));
4291 ctxt->initialize_canonical_diff(result);
4292 return result;
4293}
4294
4295// </qualified_type_diff stuff>
4296
4297// <enum_diff stuff>
4298
4299/// Clear the lookup tables useful for reporting an enum_diff.
4300///
4301/// This function must be updated each time a lookup table is added or
4302/// removed from the class_diff::priv.
4303void
4304enum_diff::clear_lookup_tables()
4305{
4306 priv_->deleted_enumerators_.clear();
4307 priv_->inserted_enumerators_.clear();
4308 priv_->changed_enumerators_.clear();
4309}
4310
4311/// Tests if the lookup tables are empty.
4312///
4313/// @return true if the lookup tables are empty, false otherwise.
4314bool
4315enum_diff::lookup_tables_empty() const
4316{
4317 return (priv_->deleted_enumerators_.empty()
4318 && priv_->inserted_enumerators_.empty()
4319 && priv_->changed_enumerators_.empty());
4320}
4321
4322/// If the lookup tables are not yet built, walk the differences and
4323/// fill the lookup tables.
4324void
4325enum_diff::ensure_lookup_tables_populated()
4326{
4327 if (!lookup_tables_empty())
4328 return;
4329
4330 {
4331 edit_script e = priv_->enumerators_changes_;
4332
4333 for (vector<deletion>::const_iterator it = e.deletions().begin();
4334 it != e.deletions().end();
4335 ++it)
4336 {
4337 unsigned i = it->index();
4338 const enum_type_decl::enumerator& n =
4339 first_enum()->get_enumerators()[i];
4340 const string& name = n.get_name();
4341 ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4342 == priv_->deleted_enumerators_.end());
4343 priv_->deleted_enumerators_[name] = n;
4344 }
4345
4346 for (vector<insertion>::const_iterator it = e.insertions().begin();
4347 it != e.insertions().end();
4348 ++it)
4349 {
4350 for (vector<unsigned>::const_iterator iit =
4351 it->inserted_indexes().begin();
4352 iit != it->inserted_indexes().end();
4353 ++iit)
4354 {
4355 unsigned i = *iit;
4356 const enum_type_decl::enumerator& n =
4357 second_enum()->get_enumerators()[i];
4358 const string& name = n.get_name();
4359 ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4360 == priv_->inserted_enumerators_.end());
4361 string_enumerator_map::const_iterator j =
4362 priv_->deleted_enumerators_.find(name);
4363 if (j == priv_->deleted_enumerators_.end())
4364 priv_->inserted_enumerators_[name] = n;
4365 else
4366 {
4367 if (j->second != n)
4368 priv_->changed_enumerators_[j->first] =
4369 std::make_pair(j->second, n);
4370 priv_->deleted_enumerators_.erase(j);
4371 }
4372 }
4373 }
4374 }
4375}
4376
4377/// Populate the vector of children node of the @ref diff base type
4378/// sub-object of this instance of @ref enum_diff.
4379///
4380/// The children node can then later be retrieved using
4381/// diff::children_node().
4382void
4385
4386/// Constructor for enum_diff.
4387///
4388/// @param first the first enum type of the diff.
4389///
4390/// @param second the second enum type of the diff.
4391///
4392/// @param underlying_type_diff the diff of the two underlying types
4393/// of the two enum types.
4394///
4395/// @param ctxt the diff context to use.
4397 const enum_type_decl_sptr second,
4398 const diff_sptr underlying_type_diff,
4399 const diff_context_sptr ctxt)
4400 : type_diff_base(first, second, ctxt),
4401 priv_(new priv(underlying_type_diff))
4402{}
4403
4404/// @return the first enum of the diff.
4407{return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4408
4409/// @return the second enum of the diff.
4412{return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4413
4414/// @return the diff of the two underlying enum types.
4417{return priv_->underlying_type_diff_;}
4418
4419/// @return a map of the enumerators that were deleted.
4422{return priv_->deleted_enumerators_;}
4423
4424/// @return a map of the enumerators that were inserted
4427{return priv_->inserted_enumerators_;}
4428
4429/// @return a map of the enumerators that were changed
4432{return priv_->changed_enumerators_;}
4433
4434/// @return the pretty representation of the current instance of @ref
4435/// enum_diff.
4436const string&
4438{
4439 if (diff::priv_->pretty_representation_.empty())
4440 {
4441 std::ostringstream o;
4442 o << "enum_diff["
4443 << first_subject()->get_pretty_representation()
4444 << ", "
4445 << second_subject()->get_pretty_representation()
4446 << "]";
4447 diff::priv_->pretty_representation_ = o.str();
4448 }
4449 return diff::priv_->pretty_representation_;
4450}
4451
4452/// Return true iff the current diff node carries a change.
4453///
4454/// @return true iff the current diff node carries a change.
4455bool
4457{return first_enum() != second_enum();}
4458
4459/// @return the kind of local change carried by the current diff node.
4460/// The value returned is zero if the current node carries no local
4461/// change.
4462enum change_kind
4464{
4465 ir::change_kind k = ir::NO_CHANGE_KIND;
4466 if (!equals(*first_enum(), *second_enum(), &k))
4467 return k & ir::ALL_LOCAL_CHANGES_MASK;
4468 return ir::NO_CHANGE_KIND;
4469}
4470
4471/// Report the differences between the two enums.
4472///
4473/// @param out the output stream to send the report to.
4474///
4475/// @param indent the string to use for indentation.
4476void
4477enum_diff::report(ostream& out, const string& indent) const
4478{
4479 context()->get_reporter()->report(*this, out, indent);
4480}
4481
4482/// Compute the set of changes between two instances of @ref
4483/// enum_type_decl.
4484///
4485/// Note that the two types must have been created in the same @ref
4486/// environment, otherwise, this function aborts.
4487///
4488/// @param first a pointer to the first enum_type_decl to consider.
4489///
4490/// @param second a pointer to the second enum_type_decl to consider.
4491///
4492/// @return the resulting diff of the two enums @p first and @p
4493/// second.
4494///
4495/// @param ctxt the diff context to use.
4496enum_diff_sptr
4498 const enum_type_decl_sptr second,
4499 diff_context_sptr ctxt)
4500{
4501 diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4502 second->get_underlying_type(),
4503 ctxt);
4504 enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4505 if (first != second)
4506 {
4507 compute_diff(first->get_enumerators().begin(),
4508 first->get_enumerators().end(),
4509 second->get_enumerators().begin(),
4510 second->get_enumerators().end(),
4511 d->priv_->enumerators_changes_);
4512 d->ensure_lookup_tables_populated();
4513 }
4514 ctxt->initialize_canonical_diff(d);
4515
4516 return d;
4517}
4518// </enum_diff stuff>
4519
4520// <class_or_union_diff stuff>
4521
4522/// Test if the current diff node carries a member type change for a
4523/// member type which name is the same as the name of a given type
4524/// declaration.
4525///
4526/// @param d the type declaration which name should be equal to the
4527/// name of the member type that might have changed.
4528///
4529/// @return the member type that has changed, iff there were a member
4530/// type (which name is the same as the name of @p d) that changed.
4531/// Note that the member type that is returned is the new value of the
4532/// member type that changed.
4535{
4536 string qname = d->get_qualified_name();
4537 string_diff_sptr_map::const_iterator it =
4538 changed_member_types_.find(qname);
4539
4540 return ((it == changed_member_types_.end())
4542 : it->second->second_subject());
4543}
4544
4545/// Test if the current diff node carries a data member change for a
4546/// data member which name is the same as the name of a given type
4547/// declaration.
4548///
4549/// @param d the type declaration which name should be equal to the
4550/// name of the data member that might have changed.
4551///
4552/// @return the data member that has changed, iff there were a data
4553/// member type (which name is the same as the name of @p d) that
4554/// changed. Note that the data member that is returned is the new
4555/// value of the data member that changed.
4556decl_base_sptr
4558{
4559 string qname = d->get_qualified_name();
4560 string_var_diff_sptr_map::const_iterator it =
4561 subtype_changed_dm_.find(qname);
4562
4563 if (it == subtype_changed_dm_.end())
4564 return decl_base_sptr();
4565 return it->second->second_var();
4566}
4567
4568/// Test if the current diff node carries a member class template
4569/// change for a member class template which name is the same as the
4570/// name of a given type declaration.
4571///
4572/// @param d the type declaration which name should be equal to the
4573/// name of the member class template that might have changed.
4574///
4575/// @return the member class template that has changed, iff there were
4576/// a member class template (which name is the same as the name of @p
4577/// d) that changed. Note that the member class template that is
4578/// returned is the new value of the member class template that
4579/// changed.
4580decl_base_sptr
4582{
4583 string qname = d->get_qualified_name();
4584 string_diff_sptr_map::const_iterator it =
4585 changed_member_class_tmpls_.find(qname);
4586
4587 return ((it == changed_member_class_tmpls_.end())
4588 ? decl_base_sptr()
4589 : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4590}
4591
4592/// Get the number of non static data members that were deleted.
4593///
4594/// @return the number of non static data members that were deleted.
4595size_t
4597{
4598 size_t result = 0;
4599
4600 for (string_decl_base_sptr_map::const_iterator i =
4601 deleted_data_members_.begin();
4602 i != deleted_data_members_.end();
4603 ++i)
4604 if (is_member_decl(i->second)
4605 && !get_member_is_static(i->second))
4606 ++result;
4607
4608 return result;
4609}
4610
4611/// Get the number of non static data members that were inserted.
4612///
4613/// @return the number of non static data members that were inserted.
4614size_t
4616{
4617 size_t result = 0;
4618
4619 for (string_decl_base_sptr_map::const_iterator i =
4620 inserted_data_members_.begin();
4621 i != inserted_data_members_.end();
4622 ++i)
4623 if (is_member_decl(i->second)
4624 && !get_member_is_static(i->second))
4625 ++result;
4626
4627 return result;
4628}
4629
4630/// Get the number of data member sub-type changes carried by the
4631/// current diff node that were filtered out.
4632///
4633/// @param local_only if true, it means that only (filtered) local
4634/// changes are considered.
4635///
4636/// @return the number of data member sub-type changes carried by the
4637/// current diff node that were filtered out.
4638size_t
4640{
4641 size_t num_filtered= 0;
4642 for (var_diff_sptrs_type::const_iterator i =
4643 sorted_subtype_changed_dm_.begin();
4644 i != sorted_subtype_changed_dm_.end();
4645 ++i)
4646 {
4647 if (local_only)
4648 {
4649 if ((*i)->has_changes()
4650 && !(*i)->has_local_changes_to_be_reported())
4651 ++num_filtered;
4652 }
4653 else
4654 {
4655 if ((*i)->is_filtered_out())
4656 ++num_filtered;
4657 }
4658 }
4659 return num_filtered;
4660}
4661
4662/// Get the number of data member changes carried by the current diff
4663/// node that were filtered out.
4664///
4665/// @param local_only if true, it means that only (filtered) local
4666/// changes are considered.
4667///
4668/// @return the number of data member changes carried by the current
4669/// diff node that were filtered out.
4670size_t
4672{
4673 size_t num_filtered= 0;
4674
4675 for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4676 i != changed_dm_.end();
4677 ++i)
4678 {
4679 diff_sptr diff = i->second;
4680 if (local_only)
4681 {
4683 || diff->is_filtered_out())
4684 ++num_filtered;
4685 }
4686 else
4687 {
4688 if (diff->is_filtered_out())
4689 ++num_filtered;
4690 }
4691 }
4692 return num_filtered;
4693}
4694
4695/// Skip the processing of the current member function if its
4696/// virtual-ness is disallowed by the user.
4697///
4698/// This is to be used in the member functions below that are used to
4699/// count the number of filtered inserted, deleted and changed member
4700/// functions.
4701#define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
4702 do { \
4703 if (get_member_function_is_virtual(f) \
4704 || get_member_function_is_virtual(s)) \
4705 { \
4706 if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
4707 continue; \
4708 } \
4709 else \
4710 { \
4711 if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
4712 continue; \
4713 } \
4714 } while (false)
4715
4716/// Get the number of member functions changes carried by the current
4717/// diff node that were filtered out.
4718///
4719/// @return the number of member functions changes carried by the
4720/// current diff node that were filtered out.
4721size_t
4723(const diff_context_sptr& ctxt)
4724{
4725 size_t count = 0;
4726 diff_category allowed_category = ctxt->get_allowed_category();
4727
4728 for (function_decl_diff_sptrs_type::const_iterator i =
4729 sorted_changed_member_functions_.begin();
4730 i != sorted_changed_member_functions_.end();
4731 ++i)
4732 {
4733 method_decl_sptr f =
4734 dynamic_pointer_cast<method_decl>
4735 ((*i)->first_function_decl());
4736 ABG_ASSERT(f);
4737
4738 method_decl_sptr s =
4739 dynamic_pointer_cast<method_decl>
4740 ((*i)->second_function_decl());
4741 ABG_ASSERT(s);
4742
4744
4745 diff_sptr diff = *i;
4746 ctxt->maybe_apply_filters(diff);
4747
4748 if (diff->is_filtered_out())
4749 ++count;
4750 }
4751
4752 return count;
4753}
4754
4755/// Get the number of member functions insertions carried by the current
4756/// diff node that were filtered out.
4757///
4758/// @return the number of member functions insertions carried by the
4759/// current diff node that were filtered out.
4760size_t
4762(const diff_context_sptr& ctxt)
4763{
4764 size_t count = 0;
4765 diff_category allowed_category = ctxt->get_allowed_category();
4766
4767 for (string_member_function_sptr_map::const_iterator i =
4768 inserted_member_functions_.begin();
4769 i != inserted_member_functions_.end();
4770 ++i)
4771 {
4772 method_decl_sptr f = i->second,
4773 s = i->second;
4774
4776
4777 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4778 ctxt->maybe_apply_filters(diff);
4779
4781 && diff->is_filtered_out())
4782 ++count;
4783 }
4784
4785 return count;
4786}
4787
4788/// Get the number of member functions deletions carried by the current
4789/// diff node that were filtered out.
4790///
4791/// @return the number of member functions deletions carried by the
4792/// current diff node that were filtered out.
4793size_t
4795(const diff_context_sptr& ctxt)
4796{
4797 size_t count = 0;
4798 diff_category allowed_category = ctxt->get_allowed_category();
4799
4800 for (string_member_function_sptr_map::const_iterator i =
4801 deleted_member_functions_.begin();
4802 i != deleted_member_functions_.end();
4803 ++i)
4804 {
4805 method_decl_sptr f = i->second,
4806 s = i->second;
4807
4809
4810 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4811 ctxt->maybe_apply_filters(diff);
4812
4814 && diff->is_filtered_out())
4815 ++count;
4816 }
4817
4818 return count;
4819}
4820
4821/// Clear the lookup tables useful for reporting.
4822///
4823/// This function must be updated each time a lookup table is added or
4824/// removed from the class_or_union_diff::priv.
4825void
4827{
4828 priv_->deleted_member_types_.clear();
4829 priv_->inserted_member_types_.clear();
4830 priv_->changed_member_types_.clear();
4831 priv_->deleted_data_members_.clear();
4832 priv_->inserted_data_members_.clear();
4833 priv_->subtype_changed_dm_.clear();
4834 priv_->deleted_member_functions_.clear();
4835 priv_->inserted_member_functions_.clear();
4836 priv_->changed_member_functions_.clear();
4837 priv_->deleted_member_class_tmpls_.clear();
4838 priv_->inserted_member_class_tmpls_.clear();
4839 priv_->changed_member_class_tmpls_.clear();
4840}
4841
4842/// Tests if the lookup tables are empty.
4843///
4844/// @return true if the lookup tables are empty, false otherwise.
4845bool
4847{
4848 return (priv_->deleted_member_types_.empty()
4849 && priv_->inserted_member_types_.empty()
4850 && priv_->changed_member_types_.empty()
4851 && priv_->deleted_data_members_.empty()
4852 && priv_->inserted_data_members_.empty()
4853 && priv_->subtype_changed_dm_.empty()
4854 && priv_->inserted_member_functions_.empty()
4855 && priv_->deleted_member_functions_.empty()
4856 && priv_->changed_member_functions_.empty()
4857 && priv_->deleted_member_class_tmpls_.empty()
4858 && priv_->inserted_member_class_tmpls_.empty()
4859 && priv_->changed_member_class_tmpls_.empty());
4860}
4861
4862/// If the lookup tables are not yet built, walk the differences and
4863/// fill them.
4864void
4866{
4867 {
4868 edit_script& e = priv_->member_types_changes_;
4869
4870 for (vector<deletion>::const_iterator it = e.deletions().begin();
4871 it != e.deletions().end();
4872 ++it)
4873 {
4874 unsigned i = it->index();
4875 decl_base_sptr d =
4876 get_type_declaration(first_class_or_union()->get_member_types()[i]);
4877 class_or_union_sptr record_type = is_class_or_union_type(d);
4878 if (record_type && record_type->get_is_declaration_only())
4879 continue;
4880 string name = d->get_name();
4881 priv_->deleted_member_types_[name] = d;
4882 }
4883
4884 for (vector<insertion>::const_iterator it = e.insertions().begin();
4885 it != e.insertions().end();
4886 ++it)
4887 {
4888 for (vector<unsigned>::const_iterator iit =
4889 it->inserted_indexes().begin();
4890 iit != it->inserted_indexes().end();
4891 ++iit)
4892 {
4893 unsigned i = *iit;
4894 decl_base_sptr d =
4895 get_type_declaration(second_class_or_union()->get_member_types()[i]);
4896 class_or_union_sptr record_type = is_class_or_union_type(d);
4897 if (record_type && record_type->get_is_declaration_only())
4898 continue;
4899 string name = d->get_name();
4900 string_decl_base_sptr_map::const_iterator j =
4901 priv_->deleted_member_types_.find(name);
4902 if (j != priv_->deleted_member_types_.end())
4903 {
4904 if (*j->second != *d)
4905 priv_->changed_member_types_[name] =
4906 compute_diff(j->second, d, context());
4907
4908 priv_->deleted_member_types_.erase(j);
4909 }
4910 else
4911 priv_->inserted_member_types_[name] = d;
4912 }
4913 }
4914 }
4915
4916 {
4917 edit_script& e = priv_->data_members_changes_;
4918
4919 for (vector<deletion>::const_iterator it = e.deletions().begin();
4920 it != e.deletions().end();
4921 ++it)
4922 {
4923 unsigned i = it->index();
4924 var_decl_sptr data_member =
4925 is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
4926 string name = data_member->get_anon_dm_reliable_name();
4927
4928 ABG_ASSERT(priv_->deleted_data_members_.find(name)
4929 == priv_->deleted_data_members_.end());
4930 priv_->deleted_data_members_[name] = data_member;
4931 }
4932
4933 for (vector<insertion>::const_iterator it = e.insertions().begin();
4934 it != e.insertions().end();
4935 ++it)
4936 {
4937 for (vector<unsigned>::const_iterator iit =
4938 it->inserted_indexes().begin();
4939 iit != it->inserted_indexes().end();
4940 ++iit)
4941 {
4942 unsigned i = *iit;
4943 decl_base_sptr d =
4944 second_class_or_union()->get_non_static_data_members()[i];
4945 var_decl_sptr added_dm = is_var_decl(d);
4946 string name = added_dm->get_anon_dm_reliable_name();
4947 ABG_ASSERT(priv_->inserted_data_members_.find(name)
4948 == priv_->inserted_data_members_.end());
4949
4950 bool ignore_added_anonymous_data_member = false;
4951 if (is_anonymous_data_member(added_dm))
4952 {
4953 //
4954 // Handle insertion of anonymous data member to
4955 // replace existing data members.
4956 //
4957 // For instance consider this:
4958 // struct S
4959 // {
4960 // int a;
4961 // int b;
4962 // int c;
4963 // };// end struct S
4964 //
4965 // Where the data members 'a' and 'b' are replaced
4966 // by an anonymous data member without changing the
4967 // effective bit layout of the structure:
4968 //
4969 // struct S
4970 // {
4971 // struct
4972 // {
4973 // union
4974 // {
4975 // int a;
4976 // char a_1;
4977 // };
4978 // union
4979 // {
4980 // int b;
4981 // char b_1;
4982 // };
4983 // };
4984 // int c;
4985 // }; // end struct S
4986 //
4987 var_decl_sptr replaced_dm, replacing_dm;
4988 bool added_anon_dm_changes_dm = false;
4989 // The vector of data members replaced by anonymous
4990 // data members.
4991 vector<var_decl_sptr> dms_replaced_by_anon_dm;
4992
4993 //
4994 // Let's start collecting the set of data members
4995 // which have been replaced by anonymous types in a
4996 // harmless way. These are going to be collected into
4997 // dms_replaced_by_anon_dm and, ultimately, into
4998 // priv_->dms_replaced_by_adms_
4999 //
5000 for (string_decl_base_sptr_map::const_iterator it =
5001 priv_->deleted_data_members_.begin();
5002 it != priv_->deleted_data_members_.end();
5003 ++it)
5004 {
5005 // We don't support this pattern for anonymous
5006 // data members themselves being replaced. If
5007 // that occurs then we'll just report it verbatim.
5008 if (is_anonymous_data_member(it->second))
5009 continue;
5010
5011 string deleted_dm_name = it->second->get_name();
5012 if ((replacing_dm =
5014 deleted_dm_name)))
5015 {
5016 // So it looks like replacing_dm might have
5017 // replaced the data member which name is
5018 // 'deleted_dm_name'. Let's look deeper to be
5019 // sure.
5020 //
5021 // Note that replacing_dm is part (member) of
5022 // an anonymous data member that might replace
5023 // replaced_dm.
5024
5025 // So let's get that replaced data member.
5026 replaced_dm = is_var_decl(it->second);
5027 size_t replaced_dm_offset =
5028 get_data_member_offset(replaced_dm),
5029 replacing_dm_offset =
5030 get_absolute_data_member_offset(replacing_dm);
5031
5032 if (replaced_dm_offset != replacing_dm_offset)
5033 {
5034 // So the replacing data member and the
5035 // replaced data member don't have the
5036 // same offset. This is not the pattern we
5037 // are looking for. Rather, it looks like
5038 // the anonymous data member has *changed*
5039 // the data member.
5040 added_anon_dm_changes_dm = true;
5041 break;
5042 }
5043
5044 if (replaced_dm->get_type()->get_size_in_bits()
5045 == replaced_dm->get_type()->get_size_in_bits())
5046 dms_replaced_by_anon_dm.push_back(replaced_dm);
5047 else
5048 {
5049 added_anon_dm_changes_dm = true;
5050 break;
5051 }
5052 }
5053 }
5054
5055 // Now walk dms_replaced_by_anon_dm to fill up
5056 // priv_->dms_replaced_by_adms_ with the set of data
5057 // members replaced by anonymous data members.
5058 if (!added_anon_dm_changes_dm
5059 && !dms_replaced_by_anon_dm.empty())
5060 {
5061 // See if the added data member isn't too big.
5062 type_base_sptr added_dm_type = added_dm->get_type();
5063 ABG_ASSERT(added_dm_type);
5064 var_decl_sptr new_next_dm =
5066 added_dm);
5067 var_decl_sptr old_next_dm =
5068 first_class_or_union()->find_data_member(new_next_dm);
5069
5070 if (!old_next_dm
5071 || (old_next_dm
5072 && (get_absolute_data_member_offset(old_next_dm)
5073 == get_absolute_data_member_offset(new_next_dm))))
5074 {
5075 // None of the data members that are replaced
5076 // by the added union should be considered as
5077 // having been deleted.
5078 ignore_added_anonymous_data_member = true;
5079 for (vector<var_decl_sptr>::const_iterator i =
5080 dms_replaced_by_anon_dm.begin();
5081 i != dms_replaced_by_anon_dm.end();
5082 ++i)
5083 {
5084 string n = (*i)->get_name();
5085 priv_->dms_replaced_by_adms_[n] =
5086 added_dm;
5087 priv_->deleted_data_members_.erase(n);
5088 }
5089 }
5090 }
5091 }
5092
5093 if (!ignore_added_anonymous_data_member)
5094 {
5095 // Detect changed data members.
5096 //
5097 // A changed data member (that we shall name D) is a data
5098 // member that satisfies the conditions below:
5099 //
5100 // 1/ It must have been added.
5101 //
5102 // 2/ It must have been deleted as well.
5103 //
5104 // 3/ It there must be a non-empty difference between the
5105 // deleted D and the added D.
5106 string_decl_base_sptr_map::const_iterator j =
5107 priv_->deleted_data_members_.find(name);
5108 if (j != priv_->deleted_data_members_.end())
5109 {
5110 if (*j->second != *d)
5111 {
5112 var_decl_sptr old_dm = is_var_decl(j->second);
5113 priv_->subtype_changed_dm_[name]=
5114 compute_diff(old_dm, added_dm, context());
5115 }
5116 priv_->deleted_data_members_.erase(j);
5117 }
5118 else
5119 priv_->inserted_data_members_[name] = d;
5120 }
5121 }
5122 }
5123
5124 // Now detect when a data member is deleted from offset N and
5125 // another one is added to offset N. In that case, we want to be
5126 // able to say that the data member at offset N changed.
5127 for (string_decl_base_sptr_map::const_iterator i =
5128 priv_->deleted_data_members_.begin();
5129 i != priv_->deleted_data_members_.end();
5130 ++i)
5131 {
5132 unsigned offset = get_data_member_offset(i->second);
5133 priv_->deleted_dm_by_offset_[offset] = i->second;
5134 }
5135
5136 for (string_decl_base_sptr_map::const_iterator i =
5137 priv_->inserted_data_members_.begin();
5138 i != priv_->inserted_data_members_.end();
5139 ++i)
5140 {
5141 unsigned offset = get_data_member_offset(i->second);
5142 priv_->inserted_dm_by_offset_[offset] = i->second;
5143 }
5144
5145 for (unsigned_decl_base_sptr_map::const_iterator i =
5146 priv_->inserted_dm_by_offset_.begin();
5147 i != priv_->inserted_dm_by_offset_.end();
5148 ++i)
5149 {
5150 unsigned_decl_base_sptr_map::const_iterator j =
5151 priv_->deleted_dm_by_offset_.find(i->first);
5152 if (j != priv_->deleted_dm_by_offset_.end())
5153 {
5154 var_decl_sptr old_dm = is_var_decl(j->second);
5155 var_decl_sptr new_dm = is_var_decl(i->second);
5156 priv_->changed_dm_[i->first] =
5157 compute_diff(old_dm, new_dm, context());
5158 }
5159 }
5160
5161 for (unsigned_var_diff_sptr_map::const_iterator i =
5162 priv_->changed_dm_.begin();
5163 i != priv_->changed_dm_.end();
5164 ++i)
5165 {
5166 priv_->deleted_dm_by_offset_.erase(i->first);
5167 priv_->inserted_dm_by_offset_.erase(i->first);
5168 priv_->deleted_data_members_.erase
5169 (i->second->first_var()->get_anon_dm_reliable_name());
5170 priv_->inserted_data_members_.erase
5171 (i->second->second_var()->get_anon_dm_reliable_name());
5172 }
5173 }
5174 sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5175 priv_->sorted_subtype_changed_dm_);
5176 sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5177 priv_->sorted_changed_dm_);
5178
5179 {
5180 edit_script& e = priv_->member_class_tmpls_changes_;
5181
5182 for (vector<deletion>::const_iterator it = e.deletions().begin();
5183 it != e.deletions().end();
5184 ++it)
5185 {
5186 unsigned i = it->index();
5187 decl_base_sptr d =
5188 first_class_or_union()->get_member_class_templates()[i]->
5189 as_class_tdecl();
5190 string name = d->get_name();
5191 ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5192 == priv_->deleted_member_class_tmpls_.end());
5193 priv_->deleted_member_class_tmpls_[name] = d;
5194 }
5195
5196 for (vector<insertion>::const_iterator it = e.insertions().begin();
5197 it != e.insertions().end();
5198 ++it)
5199 {
5200 for (vector<unsigned>::const_iterator iit =
5201 it->inserted_indexes().begin();
5202 iit != it->inserted_indexes().end();
5203 ++iit)
5204 {
5205 unsigned i = *iit;
5206 decl_base_sptr d =
5207 second_class_or_union()->get_member_class_templates()[i]->
5208 as_class_tdecl();
5209 string name = d->get_name();
5210 ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5211 == priv_->inserted_member_class_tmpls_.end());
5212 string_decl_base_sptr_map::const_iterator j =
5213 priv_->deleted_member_class_tmpls_.find(name);
5214 if (j != priv_->deleted_member_class_tmpls_.end())
5215 {
5216 if (*j->second != *d)
5217 priv_->changed_member_types_[name]=
5218 compute_diff(j->second, d, context());
5219 priv_->deleted_member_class_tmpls_.erase(j);
5220 }
5221 else
5222 priv_->inserted_member_class_tmpls_[name] = d;
5223 }
5224 }
5225 }
5226 sort_string_diff_sptr_map(priv_->changed_member_types_,
5227 priv_->sorted_changed_member_types_);
5228}
5229
5230/// Allocate the memory for the priv_ pimpl data member of the @ref
5231/// class_or_union_diff class.
5232void
5234{
5235 if (!priv_)
5236 priv_.reset(new priv);
5237}
5238
5239/// Constructor for the @ref class_or_union_diff class.
5240///
5241/// @param first_scope the first @ref class_or_union of the diff node.
5242///
5243/// @param second_scope the second @ref class_or_union of the diff node.
5244///
5245/// @param ctxt the context of the diff.
5246class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5247 class_or_union_sptr second_scope,
5248 diff_context_sptr ctxt)
5249 : type_diff_base(first_scope, second_scope, ctxt)
5250 //priv_(new priv)
5251{}
5252
5253/// Getter of the private data of the @ref class_or_union_diff type.
5254///
5255/// Note that due to an optimization, the private data of @ref
5256/// class_or_union_diff can be shared among several instances of
5257/// class_or_union_diff, so you should never try to access
5258/// class_or_union_diff::priv directly.
5259///
5260/// When class_or_union_diff::priv is shared, this function returns
5261/// the correct shared one.
5262///
5263/// @return the (possibly) shared private data of the current instance
5264/// of @ref class_or_union_diff.
5265const class_or_union_diff::priv_ptr&
5267{
5268 if (priv_)
5269 return priv_;
5270
5271 // If the current class_or_union_diff::priv member is empty, then look for
5272 // the shared one, from the canonical type.
5273 class_or_union_diff *canonical =
5274 dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5275 ABG_ASSERT(canonical);
5276 ABG_ASSERT(canonical->priv_);
5277
5278 return canonical->priv_;
5279}
5280
5281/// Destructor of class_or_union_diff.
5283{
5284}
5285
5286/// @return the first @ref class_or_union involved in the diff.
5287class_or_union_sptr
5290
5291/// @return the second @ref class_or_union involved in the diff.
5292class_or_union_sptr
5295
5296/// @return the edit script of the member types of the two @ref
5297/// class_or_union.
5298const edit_script&
5300{return get_priv()->member_types_changes_;}
5301
5302/// @return the edit script of the member types of the two @ref
5303/// class_or_union.
5306{return get_priv()->member_types_changes_;}
5307
5308/// @return the edit script of the data members of the two @ref
5309/// class_or_union.
5310const edit_script&
5312{return get_priv()->data_members_changes_;}
5313
5314/// @return the edit script of the data members of the two @ref
5315/// class_or_union.
5318{return get_priv()->data_members_changes_;}
5319
5320/// Getter for the data members that got inserted.
5321///
5322/// @return a map of data members that got inserted.
5325{return get_priv()->inserted_data_members_;}
5326
5327/// Getter for the data members that got deleted.
5328///
5329/// @return a map of data members that got deleted.
5332{return get_priv()->deleted_data_members_;}
5333
5334/// @return the edit script of the member functions of the two @ref
5335/// class_or_union.
5336const edit_script&
5338{return get_priv()->member_fns_changes_;}
5339
5340/// Getter for the virtual members functions that have had a change in
5341/// a sub-type, without having a change in their symbol name.
5342///
5343/// @return a sorted vector of virtual member functions that have a
5344/// sub-type change.
5347{return get_priv()->sorted_changed_member_functions_;}
5348
5349/// @return the edit script of the member functions of the two
5350/// classes.
5353{return get_priv()->member_fns_changes_;}
5354
5355/// @return a map of member functions that got deleted.
5358{return get_priv()->deleted_member_functions_;}
5359
5360/// @return a map of member functions that got inserted.
5363{return get_priv()->inserted_member_functions_;}
5364
5365/// Getter of the sorted vector of data members that got replaced by
5366/// another data member.
5367///
5368/// @return sorted vector of changed data member.
5371{return get_priv()->sorted_changed_dm_;}
5372
5373/// Count the number of /filtered/ data members that got replaced by
5374/// another data member.
5375///
5376/// @return the number of changed data member that got filtered out.
5377size_t
5379{return get_priv()->count_filtered_changed_dm(local);}
5380
5381/// Getter of the sorted vector of data members with a (sub-)type change.
5382///
5383/// @return sorted vector of changed data member.
5386{return get_priv()->sorted_subtype_changed_dm_;}
5387
5388/// Count the number of /filtered/ data members with a sub-type change.
5389///
5390/// @return the number of changed data member that got filtered out.
5391size_t
5393{return get_priv()->count_filtered_subtype_changed_dm(local);}
5394
5395/// Get the map of data members that got replaced by anonymous data
5396/// members.
5397///
5398/// The key of a map entry is the name of the replaced data member and
5399/// the value is the anonymous data member that replaces it.
5400///
5401/// @return the map of data members replaced by anonymous data
5402/// members.
5405{return get_priv()->dms_replaced_by_adms_;}
5406
5407/// Get an ordered vector of of data members that got replaced by
5408/// anonymous data members.
5409///
5410/// This returns a vector of pair of two data members: the one that
5411/// was replaced, and the anonymous data member that replaced it.
5412///
5413/// @return the sorted vector data members replaced by anonymous data members.
5416{
5417 if (priv_->dms_replaced_by_adms_ordered_.empty())
5418 {
5419 for (string_decl_base_sptr_map::const_iterator it =
5420 priv_->dms_replaced_by_adms_.begin();
5421 it != priv_->dms_replaced_by_adms_.end();
5422 ++it)
5423 {
5424 const var_decl_sptr dm =
5425 first_class_or_union()->find_data_member(it->first);
5426 ABG_ASSERT(dm);
5427 changed_var_sptr changed_dm(dm, is_data_member(it->second));
5428 priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5429 }
5430 sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5431 }
5432
5433 return priv_->dms_replaced_by_adms_ordered_;
5434}
5435
5436/// @return the edit script of the member function templates of the two
5437/// @ref class_or_union.
5438const edit_script&
5440{return get_priv()->member_fn_tmpls_changes_;}
5441
5442/// @return the edit script of the member function templates of the
5443/// two @ref class_or_union.
5446{return get_priv()->member_fn_tmpls_changes_;}
5447
5448/// @return the edit script of the member class templates of the two
5449/// @ref class_or_union.
5450const edit_script&
5452{return get_priv()->member_class_tmpls_changes_;}
5453
5454/// @return the edit script of the member class templates of the two
5455/// @ref class_or_union.
5458{return get_priv()->member_class_tmpls_changes_;}
5459
5460/// Test if the current diff node carries a change.
5461bool
5464
5465/// @return the kind of local change carried by the current diff node.
5466/// The value returned is zero if the current node carries no local
5467/// change.
5468enum change_kind
5470{
5471 ir::change_kind k = ir::NO_CHANGE_KIND;
5473 return k & ir::ALL_LOCAL_CHANGES_MASK;
5474 return ir::NO_CHANGE_KIND;
5475}
5476
5477
5478/// Report the changes carried by the current @ref class_or_union_diff
5479/// node in a textual format.
5480///
5481/// @param out the output stream to write the textual report to.
5482///
5483/// @param indent the number of white space to use as indentation.
5484void
5485class_or_union_diff::report(ostream& out, const string& indent) const
5486{
5487 context()->get_reporter()->report(*this, out, indent);
5488}
5489
5490/// Populate the vector of children node of the @ref diff base type
5491/// sub-object of this instance of @ref class_or_union_diff.
5492///
5493/// The children node can then later be retrieved using
5494/// diff::children_node().
5495void
5497{
5498 // data member changes
5499 for (var_diff_sptrs_type::const_iterator i =
5500 get_priv()->sorted_subtype_changed_dm_.begin();
5501 i != get_priv()->sorted_subtype_changed_dm_.end();
5502 ++i)
5503 if (diff_sptr d = *i)
5505
5506 for (var_diff_sptrs_type::const_iterator i =
5507 get_priv()->sorted_changed_dm_.begin();
5508 i != get_priv()->sorted_changed_dm_.end();
5509 ++i)
5510 if (diff_sptr d = *i)
5512
5513 // member types changes
5514 for (diff_sptrs_type::const_iterator i =
5515 get_priv()->sorted_changed_member_types_.begin();
5516 i != get_priv()->sorted_changed_member_types_.end();
5517 ++i)
5518 if (diff_sptr d = *i)
5520
5521 // member function changes
5522 for (function_decl_diff_sptrs_type::const_iterator i =
5523 get_priv()->sorted_changed_member_functions_.begin();
5524 i != get_priv()->sorted_changed_member_functions_.end();
5525 ++i)
5526 if (diff_sptr d = *i)
5528}
5529
5530// </class_or_union_diff stuff>
5531
5532//<class_diff stuff>
5533
5534/// Clear the lookup tables useful for reporting.
5535///
5536/// This function must be updated each time a lookup table is added or
5537/// removed from the class_diff::priv.
5538void
5539class_diff::clear_lookup_tables(void)
5540{
5541 priv_->deleted_bases_.clear();
5542 priv_->inserted_bases_.clear();
5543 priv_->changed_bases_.clear();
5544}
5545
5546/// Tests if the lookup tables are empty.
5547///
5548/// @return true if the lookup tables are empty, false otherwise.
5549bool
5550class_diff::lookup_tables_empty(void) const
5551{
5552 return (priv_->deleted_bases_.empty()
5553 && priv_->inserted_bases_.empty()
5554 && priv_->changed_bases_.empty());
5555}
5556
5557/// Find a virtual destructor in a map of member functions
5558///
5559/// @param map the map of member functions. Note that the key of the
5560/// map is the member function name. The key is the member function.
5561///
5562/// @return an iterator to the destructor found or, if no virtual destructor
5563/// was found, return map.end()
5564static string_member_function_sptr_map::const_iterator
5565find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
5566{
5567 for (string_member_function_sptr_map::const_iterator i = map.begin();
5568 i !=map.end();
5569 ++i)
5570 {
5571 if (get_member_function_is_dtor(i->second)
5572 && get_member_function_is_virtual(i->second))
5573 return i;
5574 }
5575 return map.end();
5576}
5577
5578/// If the lookup tables are not yet built, walk the differences and
5579/// fill them.
5580void
5581class_diff::ensure_lookup_tables_populated(void) const
5582{
5584
5585 if (!lookup_tables_empty())
5586 return;
5587
5588 {
5589 edit_script& e = get_priv()->base_changes_;
5590
5591 for (vector<deletion>::const_iterator it = e.deletions().begin();
5592 it != e.deletions().end();
5593 ++it)
5594 {
5595 unsigned i = it->index();
5597 first_class_decl()->get_base_specifiers()[i];
5598 string name = b->get_base_class()->get_qualified_name();
5599 ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5600 == get_priv()->deleted_bases_.end());
5601 get_priv()->deleted_bases_[name] = b;
5602 }
5603
5604 for (vector<insertion>::const_iterator it = e.insertions().begin();
5605 it != e.insertions().end();
5606 ++it)
5607 {
5608 for (vector<unsigned>::const_iterator iit =
5609 it->inserted_indexes().begin();
5610 iit != it->inserted_indexes().end();
5611 ++iit)
5612 {
5613 unsigned i = *iit;
5615 second_class_decl()->get_base_specifiers()[i];
5616 string name = b->get_base_class()->get_qualified_name();
5617 ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5618 == get_priv()->inserted_bases_.end());
5619 string_base_sptr_map::const_iterator j =
5620 get_priv()->deleted_bases_.find(name);
5621 if (j != get_priv()->deleted_bases_.end())
5622 {
5623 if (j->second != b)
5624 get_priv()->changed_bases_[name] =
5625 compute_diff(j->second, b, context());
5626 else
5627 // The base class changed place. IOW, the base
5628 // classes got re-arranged. Let's keep track of the
5629 // base classes that moved.
5630 get_priv()->moved_bases_.push_back(b);
5631 get_priv()->deleted_bases_.erase(j);
5632 }
5633 else
5634 get_priv()->inserted_bases_[name] = b;
5635 }
5636 }
5637 }
5638
5639 sort_string_base_sptr_map(get_priv()->deleted_bases_,
5640 get_priv()->sorted_deleted_bases_);
5641 sort_string_base_sptr_map(get_priv()->inserted_bases_,
5642 get_priv()->sorted_inserted_bases_);
5643 sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5644 get_priv()->sorted_changed_bases_);
5645
5646 {
5647 const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5648
5649 edit_script& e = p->member_fns_changes_;
5650
5651 for (vector<deletion>::const_iterator it = e.deletions().begin();
5652 it != e.deletions().end();
5653 ++it)
5654 {
5655 unsigned i = it->index();
5656 method_decl_sptr mem_fn =
5657 first_class_decl()->get_virtual_mem_fns()[i];
5658 string name = mem_fn->get_linkage_name();
5659 if (name.empty())
5660 name = mem_fn->get_pretty_representation();
5661 ABG_ASSERT(!name.empty());
5662 if (p->deleted_member_functions_.find(name)
5663 != p->deleted_member_functions_.end())
5664 continue;
5665 p->deleted_member_functions_[name] = mem_fn;
5666 }
5667
5668 for (vector<insertion>::const_iterator it = e.insertions().begin();
5669 it != e.insertions().end();
5670 ++it)
5671 {
5672 for (vector<unsigned>::const_iterator iit =
5673 it->inserted_indexes().begin();
5674 iit != it->inserted_indexes().end();
5675 ++iit)
5676 {
5677 unsigned i = *iit;
5678
5679 method_decl_sptr mem_fn =
5680 second_class_decl()->get_virtual_mem_fns()[i];
5681 string name = mem_fn->get_linkage_name();
5682 if (name.empty())
5683 name = mem_fn->get_pretty_representation();
5684 ABG_ASSERT(!name.empty());
5685 if (p->inserted_member_functions_.find(name)
5686 != p->inserted_member_functions_.end())
5687 continue;
5688 string_member_function_sptr_map::const_iterator j =
5689 p->deleted_member_functions_.find(name);
5690
5691 if (j != p->deleted_member_functions_.end())
5692 {
5693 if (*j->second != *mem_fn)
5694 p->changed_member_functions_[name] =
5695 compute_diff(static_pointer_cast<function_decl>(j->second),
5696 static_pointer_cast<function_decl>(mem_fn),
5697 context());
5698 p->deleted_member_functions_.erase(j);
5699 }
5700 else
5701 p->inserted_member_functions_[name] = mem_fn;
5702 }
5703 }
5704
5705 // Now walk the allegedly deleted member functions; check if their
5706 // underlying symbols are deleted as well; otherwise, consider
5707 // that the member function in question hasn't been deleted.
5708
5709 // Also, while walking the deleted member functions, we attend at
5710 // a particular cleanup business related to (virtual) C++
5711 // destructors:
5712 //
5713 // In the binary, there can be at least three types of
5714 // destructors, defined in the document
5715 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
5716 //
5717 // 1/ Base object destructor (aka D2 destructor):
5718 //
5719 // "A function that runs the destructors for non-static data
5720 // members of T and non-virtual direct base classes of T. "
5721 //
5722 // 2/ Complete object destructor (aka D1 destructor):
5723 //
5724 // "A function that, in addition to the actions required of a
5725 // base object destructor, runs the destructors for the
5726 // virtual base classes of T."
5727 //
5728 // 3/ Deleting destructor (aka D0 destructor):
5729 //
5730 // "A function that, in addition to the actions required of a
5731 // complete object destructor, calls the appropriate
5732 // deallocation function (i.e,. operator delete) for T."
5733 //
5734 // With binaries generated by GCC, these destructors might be ELF
5735 // clones of each others, meaning, their ELF symbols can be
5736 // aliases.
5737 //
5738 // Also, note that because the actual destructor invoked by user
5739 // code is virtual, it's invoked through the vtable. So the
5740 // presence of the underlying D0, D1, D2 in the binary might vary
5741 // without that variation being an ABI issue, provided that the
5742 // destructor invoked through the vtable is present.
5743 //
5744 // So, a particular virtual destructor implementation for a class
5745 // might disapear and be replaced by another one in a subsequent
5746 // version of the binary. If all versions of the binary have an
5747 // actual virtual destructor, things might be considered fine.
5748 vector<string> to_delete;
5749 corpus_sptr f = context()->get_first_corpus(),
5750 s = context()->get_second_corpus();
5751 if (s)
5752 for (string_member_function_sptr_map::const_iterator i =
5753 deleted_member_fns().begin();
5754 i != deleted_member_fns().end();
5755 ++i)
5756 {
5757 if (get_member_function_is_virtual(i->second))
5758 {
5759 if (get_member_function_is_dtor(i->second))
5760 {
5761 // If a particular virtual destructor is deleted,
5762 // but the new binary still have a virtual
5763 // destructor for that class we consider that things
5764 // are fine. For instance, in the
5765 // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
5766 // test, a new D4 destructor replaces the old ones.
5767 // But because the virtual destructor is still
5768 // there, this is not an ABI issue. So let's detect
5769 // this case.
5770 auto it =
5771 find_virtual_dtor_in_map(p->inserted_member_functions_);
5772 if (it != p->inserted_member_functions_.end())
5773 {
5774 // So the deleted virtual destructor is not
5775 // really deleted, because a proper virtual
5776 // destructor was added to the new version.
5777 // Let's remove the deleted/added virtual
5778 // destructor then.
5779 string name =
5780 (!i->second->get_linkage_name().empty())
5781 ? i->second->get_linkage_name()
5782 : i->second->get_pretty_representation();
5783 to_delete.push_back(name);
5784 p->inserted_member_functions_.erase(it);
5785 }
5786 }
5787 continue;
5788 }
5789 // We assume that all non-virtual member functions functions
5790 // we look at here have ELF symbols.
5791 if (!i->second->get_symbol()
5792 || s->lookup_function_symbol(*i->second->get_symbol()))
5793 to_delete.push_back(i->first);
5794 }
5795
5796
5797 for (vector<string>::const_iterator i = to_delete.begin();
5798 i != to_delete.end();
5799 ++i)
5800 p->deleted_member_functions_.erase(*i);
5801
5802 // Do something similar for added functions.
5803 to_delete.clear();
5804 if (f)
5805 for (string_member_function_sptr_map::const_iterator i =
5806 inserted_member_fns().begin();
5807 i != inserted_member_fns().end();
5808 ++i)
5809 {
5810 if (get_member_function_is_virtual(i->second))
5811 continue;
5812 // We assume that all non-virtual member functions functions
5813 // we look at here have ELF symbols.
5814 if (!i->second->get_symbol()
5815 || f->lookup_function_symbol(*i->second->get_symbol()))
5816 to_delete.push_back(i->first);
5817 }
5818
5819 for (vector<string>::const_iterator i = to_delete.begin();
5820 i != to_delete.end();
5821 ++i)
5822 p->inserted_member_functions_.erase(*i);
5823
5824 sort_string_member_function_sptr_map(p->deleted_member_functions_,
5825 p->sorted_deleted_member_functions_);
5826
5827 sort_string_member_function_sptr_map(p->inserted_member_functions_,
5828 p->sorted_inserted_member_functions_);
5829
5831 (p->changed_member_functions_,
5832 p->sorted_changed_member_functions_);
5833 }
5834}
5835
5836/// Allocate the memory for the priv_ pimpl data member of the @ref
5837/// class_diff class.
5838void
5839class_diff::allocate_priv_data()
5840{
5842 if (!priv_)
5843 priv_.reset(new priv);
5844}
5845
5846/// Test whether a given base class has changed. A base class has
5847/// changed if it's in both in deleted *and* inserted bases.
5848///
5849///@param d the declaration for the base class to consider.
5850///
5851/// @return the new base class if the given base class has changed, or
5852/// NULL if it hasn't.
5855{
5856 string qname = d->get_base_class()->get_qualified_name();
5857 string_base_diff_sptr_map::const_iterator it =
5858 changed_bases_.find(qname);
5859
5860 return (it == changed_bases_.end())
5862 : it->second->second_base();
5863
5864}
5865
5866/// Count the number of bases classes whose changes got filtered out.
5867///
5868/// @return the number of bases classes whose changes got filtered
5869/// out.
5870size_t
5872{
5873 size_t num_filtered = 0;
5874 for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
5875 i != sorted_changed_bases_.end();
5876 ++i)
5877 {
5878 diff_sptr diff = *i;
5879 if (diff && diff->is_filtered_out())
5880 ++num_filtered;
5881 }
5882 return num_filtered;
5883}
5884
5885/// Populate the vector of children node of the @ref diff base type
5886/// sub-object of this instance of @ref class_diff.
5887///
5888/// The children node can then later be retrieved using
5889/// diff::children_node().
5890void
5892{
5894
5895 // base class changes.
5896 for (base_diff_sptrs_type::const_iterator i =
5897 get_priv()->sorted_changed_bases_.begin();
5898 i != get_priv()->sorted_changed_bases_.end();
5899 ++i)
5900 if (diff_sptr d = *i)
5902}
5903
5904/// Constructor of class_diff
5905///
5906/// @param first_scope the first class of the diff.
5907///
5908/// @param second_scope the second class of the diff.
5909///
5910/// @param ctxt the diff context to use.
5912 class_decl_sptr second_scope,
5913 diff_context_sptr ctxt)
5914 : class_or_union_diff(first_scope, second_scope, ctxt)
5915 // We don't initialize the priv_ data member here. This is an
5916 // optimization to reduce memory consumption (and also execution
5917 // time) for cases where there are a lot of instances of
5918 // class_diff in the same equivalence class. In compute_diff(),
5919 // the priv_ is set to the priv_ of the canonical diff node.
5920 // See PR libabigail/17948.
5921{}
5922
5923class_diff::~class_diff()
5924{}
5925
5926/// Getter of the private data of the @ref class_diff type.
5927///
5928/// Note that due to an optimization, the private data of @ref
5929/// class_diff can be shared among several instances of class_diff, so
5930/// you should never try to access class_diff::priv directly.
5931///
5932/// When class_diff::priv is shared, this function returns the correct
5933/// shared one.
5934///
5935/// @return the (possibly) shared private data of the current instance
5936/// of class_diff.
5937const class_diff::priv_ptr&
5938class_diff::get_priv() const
5939{
5940 if (priv_)
5941 return priv_;
5942
5943 // If the current class_diff::priv member is empty, then look for
5944 // the shared one, from the canonical type.
5945 class_diff *canonical =
5946 dynamic_cast<class_diff*>(get_canonical_diff());
5947 ABG_ASSERT(canonical);
5948 ABG_ASSERT(canonical->priv_);
5949
5950 return canonical->priv_;
5951}
5952
5953/// @return the pretty representation of the current instance of @ref
5954/// class_diff.
5955const string&
5957{
5958 if (diff::priv_->pretty_representation_.empty())
5959 {
5960 std::ostringstream o;
5961 o << "class_diff["
5962 << first_subject()->get_pretty_representation()
5963 << ", "
5964 << second_subject()->get_pretty_representation()
5965 << "]";
5966 diff::priv_->pretty_representation_ = o.str();
5967 }
5968 return diff::priv_->pretty_representation_;
5969}
5970
5971/// Return true iff the current diff node carries a change.
5972///
5973/// @return true iff the current diff node carries a change.
5974bool
5976{return (first_class_decl() != second_class_decl());}
5977
5978/// @return the kind of local change carried by the current diff node.
5979/// The value returned is zero if the current node carries no local
5980/// change.
5981enum change_kind
5983{
5984 ir::change_kind k = ir::NO_CHANGE_KIND;
5985 if (!equals(*first_class_decl(), *second_class_decl(), &k))
5986 return k & ir::ALL_LOCAL_CHANGES_MASK;
5987 return ir::NO_CHANGE_KIND;
5988}
5989
5990/// @return the first class invoveld in the diff.
5991shared_ptr<class_decl>
5993{return dynamic_pointer_cast<class_decl>(first_subject());}
5994
5995/// Getter of the second class involved in the diff.
5996///
5997/// @return the second class invoveld in the diff
5998shared_ptr<class_decl>
6000{return dynamic_pointer_cast<class_decl>(second_subject());}
6001
6002/// @return the edit script of the bases of the two classes.
6003const edit_script&
6005{return get_priv()->base_changes_;}
6006
6007/// Getter for the deleted base classes of the diff.
6008///
6009/// @return a map containing the deleted base classes, keyed with
6010/// their pretty representation.
6013{return get_priv()->deleted_bases_;}
6014
6015/// Getter for the inserted base classes of the diff.
6016///
6017/// @return a map containing the inserted base classes, keyed with
6018/// their pretty representation.
6021{return get_priv()->inserted_bases_;}
6022
6023/// Getter for the changed base classes of the diff.
6024///
6025/// @return a sorted vector containing the changed base classes
6028{return get_priv()->sorted_changed_bases_;}
6029
6030/// Getter for the vector of bases that "moved".
6031/// That is, the vector of base types which position changed. If this
6032/// vector is not empty, it means the bases of the underlying class
6033/// type got re-ordered.
6034///
6035/// @return the vector of bases that moved.
6036const vector<class_decl::base_spec_sptr>&
6038{return get_priv()->moved_bases_;}
6039
6040/// @return the edit script of the bases of the two classes.
6043{return get_priv()->base_changes_;}
6044
6045/// Produce a basic report about the changes between two class_decl.
6046///
6047/// @param out the output stream to report the changes to.
6048///
6049/// @param indent the string to use as an indentation prefix in the
6050/// report.
6051void
6052class_diff::report(ostream& out, const string& indent) const
6053{
6054 context()->get_reporter()->report(*this, out, indent);
6055}
6056
6057/// Compute the set of changes between two instances of class_decl.
6058///
6059/// Note that the two types must have been created in the same @ref
6060/// environment, otherwise, this function aborts.
6061///
6062/// @param first the first class_decl to consider.
6063///
6064/// @param second the second class_decl to consider.
6065///
6066/// @return changes the resulting changes.
6067///
6068/// @param ctxt the diff context to use.
6071 const class_decl_sptr second,
6072 diff_context_sptr ctxt)
6073{
6076
6077 class_diff_sptr changes(new class_diff(f, s, ctxt));
6078
6079 ctxt->initialize_canonical_diff(changes);
6080 ABG_ASSERT(changes->get_canonical_diff());
6081
6082 if (!ctxt->get_canonical_diff_for(first, second))
6083 {
6084 // Either first or second is a decl-only class; let's set the
6085 // canonical diff here in that case.
6086 diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6087 ABG_ASSERT(canonical_diff);
6088 ctxt->set_canonical_diff_for(first, second, canonical_diff);
6089 }
6090
6091 // Ok, so this is an optimization. Do not freak out if it looks
6092 // weird, because, well, it does look weird. This speeds up
6093 // greatly, for instance, the test case given at PR
6094 // libabigail/17948.
6095 //
6096 // We are setting the private data of the new instance of class_diff
6097 // (which is 'changes') to the private data of its canonical
6098 // instance. That is, we are sharing the private data of 'changes'
6099 // with the private data of its canonical instance to consume less
6100 // memory in cases where the equivalence class of 'changes' is huge.
6101 //
6102 // But if changes is its own canonical instance, then we initialize
6103 // its private data properly
6104 if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6105 // changes is its own canonical instance, so it gets a brand new
6106 // private data.
6107 changes->allocate_priv_data();
6108 else
6109 {
6110 // changes has a non-empty equivalence class so it's going to
6111 // share its private data with its canonical instance. Next
6112 // time class_diff::get_priv() is invoked, it's going to return
6113 // the shared private data of the canonical instance.
6114 return changes;
6115 }
6116
6117 // Compare base specs
6118 compute_diff(f->get_base_specifiers().begin(),
6119 f->get_base_specifiers().end(),
6120 s->get_base_specifiers().begin(),
6121 s->get_base_specifiers().end(),
6122 changes->base_changes());
6123
6124 // Do *not* compare member types because it generates lots of noise
6125 // and I doubt it's really useful.
6126#if 0
6127 compute_diff(f->get_member_types().begin(),
6128 f->get_member_types().end(),
6129 s->get_member_types().begin(),
6130 s->get_member_types().end(),
6131 changes->member_types_changes());
6132#endif
6133
6134 // Compare data member
6135 compute_diff(f->get_non_static_data_members().begin(),
6136 f->get_non_static_data_members().end(),
6137 s->get_non_static_data_members().begin(),
6138 s->get_non_static_data_members().end(),
6139 changes->data_members_changes());
6140
6141 // Compare virtual member functions
6142 compute_diff(f->get_virtual_mem_fns().begin(),
6143 f->get_virtual_mem_fns().end(),
6144 s->get_virtual_mem_fns().begin(),
6145 s->get_virtual_mem_fns().end(),
6146 changes->member_fns_changes());
6147
6148 // Compare member function templates
6149 compute_diff(f->get_member_function_templates().begin(),
6150 f->get_member_function_templates().end(),
6151 s->get_member_function_templates().begin(),
6152 s->get_member_function_templates().end(),
6153 changes->member_fn_tmpls_changes());
6154
6155 // Likewise, do not compare member class templates
6156#if 0
6157 compute_diff(f->get_member_class_templates().begin(),
6158 f->get_member_class_templates().end(),
6159 s->get_member_class_templates().begin(),
6160 s->get_member_class_templates().end(),
6161 changes->member_class_tmpls_changes());
6162#endif
6163
6164 changes->ensure_lookup_tables_populated();
6165
6166 return changes;
6167}
6168
6169//</class_diff stuff>
6170
6171// <base_diff stuff>
6172
6173/// Populate the vector of children node of the @ref diff base type
6174/// sub-object of this instance of @ref base_diff.
6175///
6176/// The children node can then later be retrieved using
6177/// diff::children_node().
6178void
6181
6182/// @param first the first base spec to consider.
6183///
6184/// @param second the second base spec to consider.
6185///
6186/// @param ctxt the context of the diff. Note that this context
6187/// object must stay alive at least during the life time of the
6188/// current instance of @ref base_diff. Otherwise memory corruption
6189/// issues occur.
6192 class_diff_sptr underlying,
6193 diff_context_sptr ctxt)
6194 : diff(first, second, ctxt),
6195 priv_(new priv(underlying))
6196{}
6197
6198/// Getter for the first base spec of the diff object.
6199///
6200/// @return the first base specifier for the diff object.
6203{return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6204
6205/// Getter for the second base spec of the diff object.
6206///
6207/// @return the second base specifier for the diff object.
6210{return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6211
6212/// Getter for the diff object for the diff of the underlying base
6213/// classes.
6214///
6215/// @return the diff object for the diff of the underlying base
6216/// classes.
6217const class_diff_sptr
6219{return priv_->underlying_class_diff_;}
6220
6221/// Setter for the diff object for the diff of the underlyng base
6222/// classes.
6223///
6224/// @param d the new diff object for the diff of the underlying base
6225/// classes.
6226void
6228{priv_->underlying_class_diff_ = d;}
6229
6230/// @return the pretty representation for the current instance of @ref
6231/// base_diff.
6232const string&
6234{
6235 if (diff::priv_->pretty_representation_.empty())
6236 {
6237 std::ostringstream o;
6238 o << "base_diff["
6239 << first_subject()->get_pretty_representation()
6240 << ", "
6241 << second_subject()->get_pretty_representation()
6242 << "]";
6243 diff::priv_->pretty_representation_ = o.str();
6244 }
6245 return diff::priv_->pretty_representation_;
6246}
6247
6248/// Return true iff the current diff node carries a change.
6249///
6250/// Return true iff the current diff node carries a change.
6251bool
6253{return first_base() != second_base();}
6254
6255/// @return the kind of local change carried by the current diff node.
6256/// The value returned is zero if the current node carries no local
6257/// change.
6258enum change_kind
6260{
6261 ir::change_kind k = ir::NO_CHANGE_KIND;
6262 if (!equals(*first_base(), *second_base(), &k))
6263 return k & ir::ALL_LOCAL_CHANGES_MASK;
6264 return ir::NO_CHANGE_KIND;
6265}
6266
6267/// Generates a report for the current instance of base_diff.
6268///
6269/// @param out the output stream to send the report to.
6270///
6271/// @param indent the string to use for indentation.
6272void
6273base_diff::report(ostream& out, const string& indent) const
6274{
6275 context()->get_reporter()->report(*this, out, indent);
6276}
6277
6278/// Constructs the diff object representing a diff between two base
6279/// class specifications.
6280///
6281/// Note that the two artifacts must have been created in the same
6282/// @ref environment, otherwise, this function aborts.
6283///
6284/// @param first the first base class specification.
6285///
6286/// @param second the second base class specification.
6287///
6288/// @param ctxt the content of the diff.
6289///
6290/// @return the resulting diff object.
6293 const class_decl::base_spec_sptr second,
6294 diff_context_sptr ctxt)
6295{
6296 class_diff_sptr cl = compute_diff(first->get_base_class(),
6297 second->get_base_class(),
6298 ctxt);
6299 base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6300
6301 ctxt->initialize_canonical_diff(changes);
6302
6303 return changes;
6304}
6305
6306// </base_diff stuff>
6307
6308
6309// <union_diff stuff>
6310
6311/// Clear the lookup tables useful for reporting.
6312///
6313/// This function must be updated each time a lookup table is added or
6314/// removed from the union_diff::priv.
6315void
6316union_diff::clear_lookup_tables(void)
6318
6319/// Tests if the lookup tables are empty.
6320///
6321/// @return true if the lookup tables are empty, false otherwise.
6322bool
6323union_diff::lookup_tables_empty(void) const
6325
6326/// If the lookup tables are not yet built, walk the differences and
6327/// fill them.
6328void
6329union_diff::ensure_lookup_tables_populated(void) const
6331
6332/// Allocate the memory for the priv_ pimpl data member of the @ref
6333/// union_diff class.
6334void
6335union_diff::allocate_priv_data()
6336{
6338}
6339
6340/// Constructor for the @ref union_diff type.
6341///
6342/// @param first_union the first object of the comparison.
6343///
6344/// @param second_union the second object of the comparison.
6345///
6346/// @param ctxt the context of the comparison.
6347union_diff::union_diff(union_decl_sptr first_union,
6348 union_decl_sptr second_union,
6349 diff_context_sptr ctxt)
6350 : class_or_union_diff(first_union, second_union, ctxt)
6351{}
6352
6353/// Destructor of the union_diff node.
6355{}
6356
6357/// @return the first object of the comparison.
6358union_decl_sptr
6360{return is_union_type(first_subject());}
6361
6362/// @return the second object of the comparison.
6363union_decl_sptr
6365{return is_union_type(second_subject());}
6366
6367/// @return the pretty representation of the current diff node.
6368const string&
6370{
6371 if (diff::priv_->pretty_representation_.empty())
6372 {
6373 std::ostringstream o;
6374 o << "union_diff["
6375 << first_subject()->get_pretty_representation()
6376 << ", "
6377 << second_subject()->get_pretty_representation()
6378 << "]";
6379 diff::priv_->pretty_representation_ = o.str();
6380 }
6381 return diff::priv_->pretty_representation_;
6382}
6383
6384/// Report the changes carried by the current @ref union_diff node in
6385/// a textual format.
6386///
6387/// @param out the output stream to write the textual report to.
6388///
6389/// @param indent the number of white space to use as indentation.
6390void
6391union_diff::report(ostream& out, const string& indent) const
6392{
6393 context()->get_reporter()->report(*this, out, indent);
6394}
6395
6396/// Compute the difference between two @ref union_decl types.
6397///
6398/// Note that the two types must hav been created in the same
6399/// environment, otherwise, this function aborts.
6400///
6401/// @param first the first @ref union_decl to consider.
6402///
6403/// @param second the second @ref union_decl to consider.
6404///
6405/// @param ctxt the context of the diff to use.
6406union_diff_sptr
6407compute_diff(const union_decl_sptr first,
6408 const union_decl_sptr second,
6409 diff_context_sptr ctxt)
6410{
6411 union_diff_sptr changes(new union_diff(first, second, ctxt));
6412
6413 ctxt->initialize_canonical_diff(changes);
6414 ABG_ASSERT(changes->get_canonical_diff());
6415
6416 // Ok, so this is an optimization. Do not freak out if it looks
6417 // weird, because, well, it does look weird. This speeds up
6418 // greatly, for instance, the test case given at PR
6419 // libabigail/17948.
6420 //
6421 // We are setting the private data of the new instance of class_diff
6422 // (which is 'changes') to the private data of its canonical
6423 // instance. That is, we are sharing the private data of 'changes'
6424 // with the private data of its canonical instance to consume less
6425 // memory in cases where the equivalence class of 'changes' is huge.
6426 //
6427 // But if changes is its own canonical instance, then we initialize
6428 // its private data properly.
6429 if (is_union_diff(changes->get_canonical_diff()) == changes.get())
6430 // changes is its own canonical instance, so it gets a brand new
6431 // private data.
6432 changes->allocate_priv_data();
6433 else
6434 {
6435 // changes has a non-empty equivalence class so it's going to
6436 // share its private data with its canonical instance. Next
6437 // time class_diff::get_priv() is invoked, it's going to return
6438 // the shared private data of the canonical instance.
6439 return changes;
6440 }
6441
6442 // Compare data member
6443 compute_diff(first->get_non_static_data_members().begin(),
6444 first->get_non_static_data_members().end(),
6445 second->get_non_static_data_members().begin(),
6446 second->get_non_static_data_members().end(),
6447 changes->data_members_changes());
6448
6449#if 0
6450 // Compare member functions
6451 compute_diff(first->get_mem_fns().begin(),
6452 first->get_mem_fns().end(),
6453 second->get_mem_fns().begin(),
6454 second->get_mem_fns().end(),
6455 changes->member_fns_changes());
6456
6457 // Compare member function templates
6458 compute_diff(first->get_member_function_templates().begin(),
6459 first->get_member_function_templates().end(),
6460 second->get_member_function_templates().begin(),
6461 second->get_member_function_templates().end(),
6462 changes->member_fn_tmpls_changes());
6463#endif
6464
6465 changes->ensure_lookup_tables_populated();
6466
6467 return changes;
6468}
6469
6470// </union_diff stuff>
6471
6472//<scope_diff stuff>
6473
6474/// Clear the lookup tables that are useful for reporting.
6475///
6476/// This function must be updated each time a lookup table is added or
6477/// removed.
6478void
6479scope_diff::clear_lookup_tables()
6480{
6481 priv_->deleted_types_.clear();
6482 priv_->deleted_decls_.clear();
6483 priv_->inserted_types_.clear();
6484 priv_->inserted_decls_.clear();
6485 priv_->changed_types_.clear();
6486 priv_->changed_decls_.clear();
6487 priv_->removed_types_.clear();
6488 priv_->removed_decls_.clear();
6489 priv_->added_types_.clear();
6490 priv_->added_decls_.clear();
6491}
6492
6493/// Tests if the lookup tables are empty.
6494///
6495/// This function must be updated each time a lookup table is added or
6496/// removed.
6497///
6498/// @return true iff all the lookup tables are empty.
6499bool
6500scope_diff::lookup_tables_empty() const
6501{
6502 return (priv_->deleted_types_.empty()
6503 && priv_->deleted_decls_.empty()
6504 && priv_->inserted_types_.empty()
6505 && priv_->inserted_decls_.empty()
6506 && priv_->changed_types_.empty()
6507 && priv_->changed_decls_.empty()
6508 && priv_->removed_types_.empty()
6509 && priv_->removed_decls_.empty()
6510 && priv_->added_types_.empty()
6511 && priv_->added_decls_.empty());
6512}
6513
6514/// If the lookup tables are not yet built, walk the member_changes_
6515/// member and fill the lookup tables.
6516void
6517scope_diff::ensure_lookup_tables_populated()
6518{
6519 if (!lookup_tables_empty())
6520 return;
6521
6522 edit_script& e = priv_->member_changes_;
6523
6524 // Populate deleted types & decls lookup tables.
6525 for (const auto& deletion : e.deletions())
6526 {
6527 unsigned i = deletion.index();
6528 decl_base_sptr decl = deleted_member_at(i);
6529 string qname = decl->get_qualified_name();
6530 if (is_type(decl))
6531 {
6532 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6533 if (klass_decl && klass_decl->get_is_declaration_only())
6534 continue;
6535
6536 // Unique types are artifically put in a scope because they
6537 // have to belong somewhere, but they should not be
6538 // considered added/removed from any scope because they are
6539 // artificial and always present in the system.
6540 if (is_unique_type(is_type(decl)))
6541 continue;
6542
6543 ABG_ASSERT(priv_->deleted_types_.find(qname)
6544 == priv_->deleted_types_.end());
6545 priv_->deleted_types_[qname] = decl;
6546 }
6547 else
6548 {
6549 ABG_ASSERT(priv_->deleted_decls_.find(qname)
6550 == priv_->deleted_decls_.end());
6551 priv_->deleted_decls_[qname] = decl;
6552 }
6553 }
6554
6555 // Populate inserted types & decls as well as chagned types & decls
6556 // lookup tables.
6557 for (vector<insertion>::const_iterator it = e.insertions().begin();
6558 it != e.insertions().end();
6559 ++it)
6560 {
6561 for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6562 i != it->inserted_indexes().end();
6563 ++i)
6564 {
6565 decl_base_sptr decl = inserted_member_at(i);
6566 string qname = decl->get_qualified_name();
6567 if (is_type(decl))
6568 {
6569 class_decl_sptr klass_decl =
6570 dynamic_pointer_cast<class_decl>(decl);
6571 if (klass_decl && klass_decl->get_is_declaration_only())
6572 continue;
6573
6574 // Unique types are artifically put in a scope because they
6575 // have to belong somewhere, but they should not be
6576 // considered added/removed from any scope because they are
6577 // artificial and always present in the system.
6578 if (is_unique_type(is_type(decl)))
6579 continue;
6580
6581 ABG_ASSERT(priv_->inserted_types_.find(qname)
6582 == priv_->inserted_types_.end());
6583 string_decl_base_sptr_map::const_iterator j =
6584 priv_->deleted_types_.find(qname);
6585 if (j != priv_->deleted_types_.end())
6586 {
6587 if (*j->second != *decl)
6588 priv_->changed_types_[qname] =
6589 compute_diff(j->second, decl, context());
6590 priv_->deleted_types_.erase(j);
6591 }
6592 else
6593 priv_->inserted_types_[qname] = decl;
6594 }
6595 else
6596 {
6597 ABG_ASSERT(priv_->inserted_decls_.find(qname)
6598 == priv_->inserted_decls_.end());
6599 string_decl_base_sptr_map::const_iterator j =
6600 priv_->deleted_decls_.find(qname);
6601 if (j != priv_->deleted_decls_.end())
6602 {
6603 if (*j->second != *decl)
6604 priv_->changed_decls_[qname] =
6605 compute_diff(j->second, decl, context());
6606 priv_->deleted_decls_.erase(j);
6607 }
6608 else
6609 priv_->inserted_decls_[qname] = decl;
6610 }
6611 }
6612 }
6613
6614 sort_string_diff_sptr_map(priv_->changed_decls_,
6615 priv_->sorted_changed_decls_);
6616 sort_string_diff_sptr_map(priv_->changed_types_,
6617 priv_->sorted_changed_types_);
6618
6619 // Populate removed types/decls lookup tables
6620 for (string_decl_base_sptr_map::const_iterator i =
6621 priv_->deleted_types_.begin();
6622 i != priv_->deleted_types_.end();
6623 ++i)
6624 {
6625 string_decl_base_sptr_map::const_iterator r =
6626 priv_->inserted_types_.find(i->first);
6627 if (r == priv_->inserted_types_.end())
6628 priv_->removed_types_[i->first] = i->second;
6629 }
6630 for (string_decl_base_sptr_map::const_iterator i =
6631 priv_->deleted_decls_.begin();
6632 i != priv_->deleted_decls_.end();
6633 ++i)
6634 {
6635 string_decl_base_sptr_map::const_iterator r =
6636 priv_->inserted_decls_.find(i->first);
6637 if (r == priv_->inserted_decls_.end())
6638 priv_->removed_decls_[i->first] = i->second;
6639 }
6640
6641 // Populate added types/decls.
6642 for (string_decl_base_sptr_map::const_iterator i =
6643 priv_->inserted_types_.begin();
6644 i != priv_->inserted_types_.end();
6645 ++i)
6646 {
6647 string_decl_base_sptr_map::const_iterator r =
6648 priv_->deleted_types_.find(i->first);
6649 if (r == priv_->deleted_types_.end())
6650 priv_->added_types_[i->first] = i->second;
6651 }
6652 for (string_decl_base_sptr_map::const_iterator i =
6653 priv_->inserted_decls_.begin();
6654 i != priv_->inserted_decls_.end();
6655 ++i)
6656 {
6657 string_decl_base_sptr_map::const_iterator r =
6658 priv_->deleted_decls_.find(i->first);
6659 if (r == priv_->deleted_decls_.end())
6660 priv_->added_decls_[i->first] = i->second;
6661 }
6662}
6663
6664/// Populate the vector of children node of the @ref diff base type
6665/// sub-object of this instance of @ref scope_diff.
6666///
6667/// The children node can then later be retrieved using
6668/// diff::children_node().
6669void
6671{
6672 for (diff_sptrs_type::const_iterator i = changed_types().begin();
6673 i != changed_types().end();
6674 ++i)
6675 if (*i)
6677
6678 for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6679 i != changed_decls().end();
6680 ++i)
6681 if (*i)
6683}
6684
6685/// Constructor for scope_diff
6686///
6687/// @param first_scope the first scope to consider for the diff.
6688///
6689/// @param second_scope the second scope to consider for the diff.
6690///
6691/// @param ctxt the diff context to use. Note that this context
6692/// object must stay alive at least during the life time of the
6693/// current instance of @ref scope_diff. Otherwise memory corruption
6694/// issues occur.
6696 scope_decl_sptr second_scope,
6697 diff_context_sptr ctxt)
6698 : diff(first_scope, second_scope, ctxt),
6699 priv_(new priv)
6700{}
6701
6702/// Getter for the first scope of the diff.
6703///
6704/// @return the first scope of the diff.
6705const scope_decl_sptr
6707{return dynamic_pointer_cast<scope_decl>(first_subject());}
6708
6709/// Getter for the second scope of the diff.
6710///
6711/// @return the second scope of the diff.
6712const scope_decl_sptr
6714{return dynamic_pointer_cast<scope_decl>(second_subject());}
6715
6716/// Accessor of the edit script of the members of a scope.
6717///
6718/// This edit script is computed using the equality operator that
6719/// applies to shared_ptr<decl_base>.
6720///
6721/// That has interesting consequences. For instance, consider two
6722/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
6723/// S0'. C0 and C0' have the same qualified name, but have different
6724/// members. The edit script will consider that C0 has been deleted
6725/// from S0 and that S0' has been inserted. This is a low level
6726/// canonical representation of the changes; a higher level
6727/// representation would give us a simpler way to say "the class C0
6728/// has been modified into C0'". But worry not. We do have such
6729/// higher representation as well; that is what changed_types() and
6730/// changed_decls() is for.
6731///
6732/// @return the edit script of the changes encapsulatd in this
6733/// instance of scope_diff.
6734const edit_script&
6736{return priv_->member_changes_;}
6737
6738/// Accessor of the edit script of the members of a scope.
6739///
6740/// This edit script is computed using the equality operator that
6741/// applies to shared_ptr<decl_base>.
6742///
6743/// That has interesting consequences. For instance, consider two
6744/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
6745/// S0'. C0 and C0' have the same qualified name, but have different
6746/// members. The edit script will consider that C0 has been deleted
6747/// from S0 and that S0' has been inserted. This is a low level
6748/// canonical representation of the changes; a higher level
6749/// representation would give us a simpler way to say "the class C0
6750/// has been modified into C0'". But worry not. We do have such
6751/// higher representation as well; that is what changed_types() and
6752/// changed_decls() is for.
6753///
6754/// @return the edit script of the changes encapsulatd in this
6755/// instance of scope_diff.
6758{return priv_->member_changes_;}
6759
6760/// Accessor that eases the manipulation of the edit script associated
6761/// to this instance. It returns the scope member that is reported
6762/// (in the edit script) as deleted at a given index.
6763///
6764/// @param i the index (in the edit script) of an element of the first
6765/// scope that has been reported as being delete.
6766///
6767/// @return the scope member that has been reported by the edit script
6768/// as being deleted at index i.
6769const decl_base_sptr
6771{
6772 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
6773 return scope->get_member_decls()[i];
6774}
6775
6776/// Accessor that eases the manipulation of the edit script associated
6777/// to this instance. It returns the scope member (of the first scope
6778/// of this diff instance) that is reported (in the edit script) as
6779/// deleted at a given iterator.
6780///
6781/// @param i the iterator of an element of the first scope that has
6782/// been reported as being delete.
6783///
6784/// @return the scope member of the first scope of this diff that has
6785/// been reported by the edit script as being deleted at iterator i.
6786const decl_base_sptr
6787scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
6788{return deleted_member_at(i->index());}
6789
6790/// Accessor that eases the manipulation of the edit script associated
6791/// to this instance. It returns the scope member (of the second
6792/// scope of this diff instance) that is reported as being inserted
6793/// from a given index.
6794///
6795/// @param i the index of an element of the second scope this diff
6796/// that has been reported by the edit script as being inserted.
6797///
6798/// @return the scope member of the second scope of this diff that has
6799/// been reported as being inserted from index i.
6800const decl_base_sptr
6802{
6803 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
6804 return scope->get_member_decls()[i];
6805}
6806
6807/// Accessor that eases the manipulation of the edit script associated
6808/// to this instance. It returns the scope member (of the second
6809/// scope of this diff instance) that is reported as being inserted
6810/// from a given iterator.
6811///
6812/// @param i the iterator of an element of the second scope this diff
6813/// that has been reported by the edit script as being inserted.
6814///
6815/// @return the scope member of the second scope of this diff that has
6816/// been reported as being inserted from iterator i.
6817const decl_base_sptr
6818scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
6819{return inserted_member_at(*i);}
6820
6821/// @return a sorted vector of the types which content has changed
6822/// from the first scope to the other.
6823const diff_sptrs_type&
6825{return priv_->sorted_changed_types_;}
6826
6827/// @return a sorted vector of the decls which content has changed
6828/// from the first scope to the other.
6829const diff_sptrs_type&
6831{return priv_->sorted_changed_decls_;}
6832
6834scope_diff::removed_types() const
6835{return priv_->removed_types_;}
6836
6838scope_diff::removed_decls() const
6839{return priv_->removed_decls_;}
6840
6842scope_diff::added_types() const
6843{return priv_->added_types_;}
6844
6846scope_diff::added_decls() const
6847{return priv_->added_decls_;}
6848
6849/// @return the pretty representation for the current instance of @ref
6850/// scope_diff.
6851const string&
6853{
6854 if (diff::priv_->pretty_representation_.empty())
6855 {
6856 std::ostringstream o;
6857 o << "scope_diff["
6858 << first_subject()->get_pretty_representation()
6859 << ", "
6860 << second_subject()->get_pretty_representation()
6861 << "]";
6862 diff::priv_->pretty_representation_ = o.str();
6863 }
6864 return diff::priv_->pretty_representation_;
6865}
6866
6867/// Return true iff the current diff node carries a change.
6868///
6869/// Return true iff the current diff node carries a change.
6870bool
6872{
6873 // TODO: add the number of really removed/added stuff.
6874 return changed_types().size() + changed_decls().size();
6875}
6876
6877/// @return the kind of local change carried by the current diff node.
6878/// The value returned is zero if the current node carries no local
6879/// change.
6880enum change_kind
6882{
6883 ir::change_kind k = ir::NO_CHANGE_KIND;
6884 if (!equals(*first_scope(), *second_scope(), &k))
6885 return k & ir::ALL_LOCAL_CHANGES_MASK;
6886 return ir::NO_CHANGE_KIND;
6887}
6888
6889/// Report the changes of one scope against another.
6890///
6891/// @param out the out stream to report the changes to.
6892///
6893/// @param indent the string to use for indentation.
6894void
6895scope_diff::report(ostream& out, const string& indent) const
6896{
6897 context()->get_reporter()->report(*this, out, indent);
6898}
6899
6900/// Compute the diff between two scopes.
6901///
6902/// Note that the two decls must have been created in the same @ref
6903/// environment, otherwise, this function aborts.
6904///
6905/// @param first the first scope to consider in computing the diff.
6906///
6907/// @param second the second scope to consider in the diff
6908/// computation. The second scope is diffed against the first scope.
6909///
6910/// @param d a pointer to the diff object to populate with the
6911/// computed diff.
6912///
6913/// @return return the populated \a d parameter passed to this
6914/// function.
6915///
6916/// @param ctxt the diff context to use.
6919 const scope_decl_sptr second,
6921 diff_context_sptr ctxt)
6922{
6923 ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
6924
6925 compute_diff(first->get_member_decls().begin(),
6926 first->get_member_decls().end(),
6927 second->get_member_decls().begin(),
6928 second->get_member_decls().end(),
6929 d->member_changes());
6930
6931 d->ensure_lookup_tables_populated();
6932 d->context(ctxt);
6933
6934 return d;
6935}
6936
6937/// Compute the diff between two scopes.
6938///
6939/// Note that the two decls must have been created in the same @ref
6940/// environment, otherwise, this function aborts.
6941///
6942/// @param first_scope the first scope to consider in computing the diff.
6943///
6944/// @param second_scope the second scope to consider in the diff
6945/// computation. The second scope is diffed against the first scope.
6946///
6947/// @param ctxt the diff context to use.
6948///
6949/// @return return the resulting diff
6952 const scope_decl_sptr second_scope,
6953 diff_context_sptr ctxt)
6954{
6955 scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
6956 d = compute_diff(first_scope, second_scope, d, ctxt);
6957 ctxt->initialize_canonical_diff(d);
6958 return d;
6959}
6960
6961//</scope_diff stuff>
6962
6963// <fn_parm_diff stuff>
6964
6965/// Constructor for the fn_parm_diff type.
6966///
6967/// @param first the first subject of the diff.
6968///
6969/// @param second the second subject of the diff.
6970///
6971/// @param ctxt the context of the diff. Note that this context
6972/// object must stay alive at least during the life time of the
6973/// current instance of @ref fn_parm_diff. Otherwise memory
6974/// corruption issues occur.
6975fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
6976 const function_decl::parameter_sptr second,
6977 diff_context_sptr ctxt)
6978 : decl_diff_base(first, second, ctxt),
6979 priv_(new priv)
6980{
6981 ABG_ASSERT(first->get_index() == second->get_index());
6982 priv_->type_diff = compute_diff(first->get_type(),
6983 second->get_type(),
6984 ctxt);
6985 ABG_ASSERT(priv_->type_diff);
6986}
6987
6988/// Getter for the first subject of this diff node.
6989///
6990/// @return the first function_decl::parameter_sptr subject of this
6991/// diff node.
6994{return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
6995
6996/// Getter for the second subject of this diff node.
6997///
6998/// @return the second function_decl::parameter_sptr subject of this
6999/// diff node.
7002{return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7003
7004/// Getter for the diff representing the changes on the type of the
7005/// function parameter involved in the current instance of @ref
7006/// fn_parm_diff.
7007///
7008/// @return a diff_sptr representing the changes on the type of the
7009/// function parameter we are interested in.
7012{return priv_->type_diff;}
7013
7014/// Build and return a textual representation of the current instance
7015/// of @ref fn_parm_diff.
7016///
7017/// @return the string representing the current instance of
7018/// fn_parm_diff.
7019const string&
7021{
7022 if (diff::priv_->pretty_representation_.empty())
7023 {
7024 std::ostringstream o;
7025 o << "function_parameter_diff["
7026 << first_subject()->get_pretty_representation()
7027 << ", "
7028 << second_subject()->get_pretty_representation()
7029 << "]";
7030 diff::priv_->pretty_representation_ = o.str();
7031 }
7032 return diff::priv_->pretty_representation_;
7033}
7034
7035/// Return true iff the current diff node carries a change.
7036///
7037/// @return true iff the current diff node carries a change.
7038bool
7040{return *first_parameter() != *second_parameter();}
7041
7042/// Check if the current diff node carries a local change.
7043///
7044/// @return the kind of local change carried by the current diff node.
7045/// The value returned is zero if the current node carries no local
7046/// change.
7047enum change_kind
7049{
7050 ir::change_kind k = ir::NO_CHANGE_KIND;
7051 if (!equals(*first_parameter(), *second_parameter(), &k))
7052 return k & ir::ALL_LOCAL_CHANGES_MASK;
7053 return ir::NO_CHANGE_KIND;
7054}
7055
7056/// Emit a textual report about the current fn_parm_diff instance.
7057///
7058/// @param out the output stream to emit the textual report to.
7059///
7060/// @param indent the indentation string to use in the report.
7061void
7062fn_parm_diff::report(ostream& out, const string& indent) const
7063{
7064 context()->get_reporter()->report(*this, out, indent);
7065}
7066
7067/// Populate the vector of children nodes of the @ref diff base type
7068/// sub-object of this instance of @ref fn_parm_diff.
7069///
7070/// The children nodes can then later be retrieved using
7071/// diff::children_nodes()
7072void
7074{
7075 if (type_diff())
7077}
7078
7079/// Compute the difference between two function_decl::parameter_sptr;
7080/// that is, between two function parameters. Return a resulting
7081/// fn_parm_diff_sptr that represents the changes.
7082///
7083/// Note that the two decls must have been created in the same @ref
7084/// environment, otherwise, this function aborts.
7085///
7086/// @param first the first subject of the diff.
7087///
7088/// @param second the second subject of the diff.
7089///
7090/// @param ctxt the context of the diff.
7091///
7092/// @return fn_parm_diff_sptr the resulting diff node.
7095 const function_decl::parameter_sptr second,
7096 diff_context_sptr ctxt)
7097{
7098 if (!first || !second)
7099 return fn_parm_diff_sptr();
7100
7101 fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7102 ctxt->initialize_canonical_diff(result);
7103
7104 return result;
7105}
7106// </fn_parm_diff stuff>
7107
7108// <function_type_diff stuff>
7109
7110void
7111function_type_diff::ensure_lookup_tables_populated()
7112{
7113 priv_->return_type_diff_ =
7114 compute_diff(first_function_type()->get_return_type(),
7115 second_function_type()->get_return_type(),
7116 context());
7117
7118 string parm_name;
7120 for (vector<deletion>::const_iterator i =
7121 priv_->parm_changes_.deletions().begin();
7122 i != priv_->parm_changes_.deletions().end();
7123 ++i)
7124 {
7125 parm = *(first_function_type()->get_first_parm()
7126 + i->index());
7127 parm_name = parm->get_name_id();
7128 // If for a reason the type name is empty we want to know and
7129 // fix that.
7130 ABG_ASSERT(!parm_name.empty());
7131 priv_->deleted_parms_[parm_name] = parm;
7132 priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7133 }
7134
7135 for (vector<insertion>::const_iterator i =
7136 priv_->parm_changes_.insertions().begin();
7137 i != priv_->parm_changes_.insertions().end();
7138 ++i)
7139 {
7140 for (vector<unsigned>::const_iterator j =
7141 i->inserted_indexes().begin();
7142 j != i->inserted_indexes().end();
7143 ++j)
7144 {
7145 parm = *(second_function_type()->get_first_parm() + *j);
7146 parm_name = parm->get_name_id();
7147 // If for a reason the type name is empty we want to know and
7148 // fix that.
7149 ABG_ASSERT(!parm_name.empty());
7150 {
7151 string_parm_map::const_iterator k =
7152 priv_->deleted_parms_.find(parm_name);
7153 if (k != priv_->deleted_parms_.end())
7154 {
7155 if (*k->second != *parm)
7156 priv_->subtype_changed_parms_[parm_name] =
7157 compute_diff(k->second, parm, context());
7158 priv_->deleted_parms_.erase(parm_name);
7159 }
7160 else
7161 priv_->added_parms_[parm_name] = parm;
7162 }
7163 {
7164 unsigned_parm_map::const_iterator k =
7165 priv_->deleted_parms_by_id_.find(parm->get_index());
7166 if (k != priv_->deleted_parms_by_id_.end())
7167 {
7168 if (*k->second != *parm
7169 && (k->second->get_name_id() != parm_name))
7170 priv_->changed_parms_by_id_[parm->get_index()] =
7171 compute_diff(k->second, parm, context());
7172 priv_->added_parms_.erase(parm_name);
7173 priv_->deleted_parms_.erase(k->second->get_name_id());
7174 priv_->deleted_parms_by_id_.erase(parm->get_index());
7175 }
7176 else
7177 priv_->added_parms_by_id_[parm->get_index()] = parm;
7178 }
7179 }
7180 }
7181
7182 sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7183 priv_->sorted_subtype_changed_parms_);
7184 sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7185 priv_->sorted_changed_parms_by_id_);
7186 sort_string_parm_map(priv_->deleted_parms_,
7187 priv_->sorted_deleted_parms_);
7188
7189 sort_string_parm_map(priv_->added_parms_,
7190 priv_->sorted_added_parms_);
7191}
7192
7193/// In the vector of deleted parameters, get the one that is at a given
7194/// index.
7195///
7196/// @param i the index of the deleted parameter to get.
7197///
7198/// @return the parameter returned.
7200function_type_diff::deleted_parameter_at(int i) const
7201{return first_function_type()->get_parameters()[i];}
7202
7203/// Getter for the sorted vector of deleted parameters.
7204///
7205/// @return the sorted vector of deleted parameters.
7206const vector<function_decl::parameter_sptr>&
7208{return priv_->sorted_deleted_parms_;}
7209
7210/// Getter for the sorted vector of added parameters .
7211///
7212/// @return the sorted vector of added parameters.
7213const vector<function_decl::parameter_sptr>&
7215{return priv_->sorted_added_parms_;}
7216
7217/// In the vector of inserted parameters, get the one that is at a
7218/// given index.
7219///
7220/// @param i the index of the inserted parameter to get.
7221///
7222/// @return the parameter returned.
7224function_type_diff::inserted_parameter_at(int i) const
7225{return second_function_type()->get_parameters()[i];}
7226
7227/// Consutrctor of the @ref function_type type.
7228///
7229/// @param first the first @ref function_type subject of the diff to
7230/// create.
7231///
7232/// @param second the second @ref function_type subject of the diff to
7233/// create.
7234///
7235/// @param ctxt the diff context to be used by the newly created
7236/// instance of function_type_diff. Note that this context object
7237/// must stay alive at least during the life time of the current
7238/// instance of @ref function_type_diff. Otherwise memory corruption
7239/// issues occur.
7241 const function_type_sptr second,
7242 diff_context_sptr ctxt)
7243 : type_diff_base(first, second, ctxt),
7244 priv_(new priv)
7245{}
7246
7247/// Getter for the first subject of the diff.
7248///
7249/// @return the first function type involved in the diff.
7252{return dynamic_pointer_cast<function_type>(first_subject());}
7253
7254/// Getter for the second subject of the diff.
7255///
7256/// @return the second function type involved in the diff.
7259{return dynamic_pointer_cast<function_type>(second_subject());}
7260
7261/// Getter for the diff of the return types of the two function types
7262/// of the current diff.
7263///
7264/// @return the diff of the return types of the two function types of
7265/// the current diff.
7266const diff_sptr
7268{return priv_->return_type_diff_;}
7269
7270/// Getter for the map of function parameter changes of the current diff.
7271///
7272/// @return a map of function parameter changes of the current diff.
7275{return priv_->subtype_changed_parms_;}
7276
7277/// Getter for the map of parameters that got removed.
7278///
7279/// @return the map of parameters that got removed.
7280const string_parm_map&
7282{return priv_->deleted_parms_;}
7283
7284/// Getter for the map of parameters that got added.
7285///
7286/// @return the map of parameters that got added.
7287const string_parm_map&
7289{return priv_->added_parms_;}
7290
7291/// Build and return a copy of a pretty representation of the current
7292/// instance of @ref function_type_diff.
7293///
7294/// @return a copy of the pretty representation of the current
7295/// instance of @ref function_type_diff.
7296const string&
7298{
7299 if (diff::priv_->pretty_representation_.empty())
7300 {
7301 std::ostringstream o;
7302 o << "function_type_diff["
7304 << ", "
7306 << "]";
7307 diff::priv_->pretty_representation_ = o.str();
7308 }
7309 return diff::priv_->pretty_representation_;
7310}
7311
7312/// Test if the current diff node carries changes.
7313///
7314/// @return true iff the current diff node carries changes.
7315bool
7318
7319/// Test if the current diff node carries local changes.
7320///
7321/// A local change is a change that is carried by this diff node, not
7322/// by any of its children nodes.
7323///
7324/// @return the kind of local change carried by the current diff node.
7325/// The value returned is zero if the current node carries no local
7326/// change.
7327enum change_kind
7329{
7330 ir::change_kind k = ir::NO_CHANGE_KIND;
7332 return k & ir::ALL_LOCAL_CHANGES_MASK;
7333 return ir::NO_CHANGE_KIND;
7334}
7335
7336/// Build and emit a textual report about the current @ref
7337/// function_type_diff instance.
7338///
7339/// @param out the output stream.
7340///
7341/// @param indent the indentation string to use.
7342void
7343function_type_diff::report(ostream& out, const string& indent) const
7344{
7345 context()->get_reporter()->report(*this, out, indent);
7346}
7347
7348/// Populate the vector of children node of the @ref diff base type
7349/// sub-object of this instance of @ref function_type_diff.
7350///
7351/// The children node can then later be retrieved using
7352/// diff::children_node().
7353void
7355{
7356 if (diff_sptr d = return_type_diff())
7358
7359 for (vector<fn_parm_diff_sptr>::const_iterator i =
7360 priv_->sorted_subtype_changed_parms_.begin();
7361 i != priv_->sorted_subtype_changed_parms_.end();
7362 ++i)
7363 if (diff_sptr d = *i)
7365
7366 for (vector<fn_parm_diff_sptr>::const_iterator i =
7367 priv_->sorted_changed_parms_by_id_.begin();
7368 i != priv_->sorted_changed_parms_by_id_.end();
7369 ++i)
7370 if (diff_sptr d = *i)
7372}
7373
7374/// Compute the diff between two instances of @ref function_type.
7375///
7376/// Note that the two types must have been created in the same @ref
7377/// environment, otherwise, this function aborts.
7378///
7379/// @param first the first @ref function_type to consider for the diff.
7380///
7381/// @param second the second @ref function_type to consider for the diff.
7382///
7383/// @param ctxt the diff context to use.
7384///
7385/// @return the resulting diff between the two @ref function_type.
7388 const function_type_sptr second,
7389 diff_context_sptr ctxt)
7390{
7391 if (!first || !second)
7392 {
7393 // TODO: implement this for either first or second being NULL.
7394 return function_type_diff_sptr();
7395 }
7396
7397 function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7398
7399 diff_utils::compute_diff(first->get_first_parm(),
7400 first->get_parameters().end(),
7401 second->get_first_parm(),
7402 second->get_parameters().end(),
7403 result->priv_->parm_changes_);
7404
7405 result->ensure_lookup_tables_populated();
7406
7407 ctxt->initialize_canonical_diff(result);
7408
7409 return result;
7410}
7411// </function_type_diff stuff>
7412
7413// <function_decl_diff stuff>
7414
7415/// Build the lookup tables of the diff, if necessary.
7416void
7417function_decl_diff::ensure_lookup_tables_populated()
7418{
7419}
7420
7421/// Populate the vector of children node of the @ref diff base type
7422/// sub-object of this instance of @ref function_decl_diff.
7423///
7424/// The children node can then later be retrieved using
7425/// diff::children_node().
7426void
7428{
7429 if (diff_sptr d = type_diff())
7431}
7432
7433/// Constructor for function_decl_diff
7434///
7435/// @param first the first function considered by the diff.
7436///
7437/// @param second the second function considered by the diff.
7438///
7439/// @param ctxt the context of the diff. Note that this context
7440/// object must stay alive at least during the life time of the
7441/// current instance of @ref function_decl_diff. Otherwise memory
7442/// corruption issues occur.
7444 const function_decl_sptr second,
7445 diff_context_sptr ctxt)
7446 : decl_diff_base(first, second, ctxt),
7447 priv_(new priv)
7448{
7449}
7450
7451/// @return the first function considered by the diff.
7454{return dynamic_pointer_cast<function_decl>(first_subject());}
7455
7456/// @return the second function considered by the diff.
7459{return dynamic_pointer_cast<function_decl>(second_subject());}
7460
7462function_decl_diff::type_diff() const
7463{return priv_->type_diff_;}
7464
7465/// @return the pretty representation for the current instance of @ref
7466/// function_decl_diff.
7467const string&
7469{
7470 if (diff::priv_->pretty_representation_.empty())
7471 {
7472 std::ostringstream o;
7473 o << "function_diff["
7474 << first_subject()->get_pretty_representation()
7475 << ", "
7476 << second_subject()->get_pretty_representation()
7477 << "]";
7478 diff::priv_->pretty_representation_ = o.str();
7479 }
7480 return diff::priv_->pretty_representation_;
7481}
7482
7483/// Return true iff the current diff node carries a change.
7484///
7485/// @return true iff the current diff node carries a change.
7486bool
7489
7490/// @return the kind of local change carried by the current diff node.
7491/// The value returned is zero if the current node carries no local
7492/// change.
7493enum change_kind
7495{
7496 ir::change_kind k = ir::NO_CHANGE_KIND;
7498 return k & ir::ALL_LOCAL_CHANGES_MASK;
7499 return ir::NO_CHANGE_KIND;
7500}
7501
7502/// Serialize a report of the changes encapsulated in the current
7503/// instance of @ref function_decl_diff over to an output stream.
7504///
7505/// @param out the output stream to serialize the report to.
7506///
7507/// @param indent the string to use an an indentation prefix.
7508void
7509function_decl_diff::report(ostream& out, const string& indent) const
7510{
7511 context()->get_reporter()->report(*this, out, indent);
7512}
7513
7514/// Compute the diff between two function_decl.
7515///
7516/// Note that the two decls must have been created in the same @ref
7517/// environment, otherwise, this function aborts.
7518///
7519/// @param first the first function_decl to consider for the diff
7520///
7521/// @param second the second function_decl to consider for the diff
7522///
7523/// @param ctxt the diff context to use.
7524///
7525/// @return the computed diff
7528 const function_decl_sptr second,
7529 diff_context_sptr ctxt)
7530{
7531 if (!first || !second)
7532 {
7533 // TODO: implement this for either first or second being NULL.
7534 return function_decl_diff_sptr();
7535 }
7536
7537 function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7538 second->get_type(),
7539 ctxt);
7540
7541 function_decl_diff_sptr result(new function_decl_diff(first, second,
7542 ctxt));
7543 result->priv_->type_diff_ = type_diff;
7544
7545 result->ensure_lookup_tables_populated();
7546
7547 ctxt->initialize_canonical_diff(result);
7548
7549 return result;
7550}
7551
7552// </function_decl_diff stuff>
7553
7554// <type_decl_diff stuff>
7555
7556/// Constructor for type_decl_diff.
7557///
7558/// @param first the first subject of the diff.
7559///
7560/// @param second the second subject of the diff.
7561///
7562/// @param ctxt the context of the diff. Note that this context
7563/// object must stay alive at least during the life time of the
7564/// current instance of @ref type_decl_diff. Otherwise memory
7565/// corruption issues occur.
7566type_decl_diff::type_decl_diff(const type_decl_sptr first,
7567 const type_decl_sptr second,
7568 diff_context_sptr ctxt)
7569 : type_diff_base(first, second, ctxt)
7570{}
7571
7572/// Getter for the first subject of the type_decl_diff.
7573///
7574/// @return the first type_decl involved in the diff.
7575const type_decl_sptr
7577{return dynamic_pointer_cast<type_decl>(first_subject());}
7578
7579/// Getter for the second subject of the type_decl_diff.
7580///
7581/// @return the second type_decl involved in the diff.
7582const type_decl_sptr
7584{return dynamic_pointer_cast<type_decl>(second_subject());}
7585
7586/// @return the pretty representation for the current instance of @ref
7587/// type_decl_diff.
7588const string&
7590{
7591 if (diff::priv_->pretty_representation_.empty())
7592 {
7593 std::ostringstream o;
7594 o << "type_decl_diff["
7595 << first_subject()->get_pretty_representation()
7596 << ", "
7597 << second_subject()->get_pretty_representation()
7598 << "]";
7599 diff::priv_->pretty_representation_ = o.str();
7600 }
7601 return diff::priv_->pretty_representation_;
7602}
7603/// Return true iff the current diff node carries a change.
7604///
7605/// @return true iff the current diff node carries a change.
7606bool
7608{return first_type_decl() != second_type_decl();}
7609
7610/// @return the kind of local change carried by the current diff node.
7611/// The value returned is zero if the current node carries no local
7612/// change.
7613enum change_kind
7615{
7616 ir::change_kind k = ir::NO_CHANGE_KIND;
7617 if (!equals(*first_type_decl(), *second_type_decl(), &k))
7618 return k & ir::ALL_LOCAL_CHANGES_MASK;
7619 return ir::NO_CHANGE_KIND;
7620}
7621/// Ouputs a report of the differences between of the two type_decl
7622/// involved in the type_decl_diff.
7623///
7624/// @param out the output stream to emit the report to.
7625///
7626/// @param indent the string to use for indentatino indent.
7627void
7628type_decl_diff::report(ostream& out, const string& indent) const
7629{
7630 context()->get_reporter()->report(*this, out, indent);
7631}
7632
7633/// Compute a diff between two type_decl.
7634///
7635/// Note that the two types must have been created in the same @ref
7636/// environment, otherwise, this function aborts.
7637///
7638/// This function doesn't actually compute a diff. As a type_decl is
7639/// very simple (unlike compound constructs like function_decl or
7640/// class_decl) it's easy to just compare the components of the
7641/// type_decl to know what has changed. Thus this function just
7642/// builds and return a type_decl_diff object. The
7643/// type_decl_diff::report function will just compare the components
7644/// of the the two type_decl and display where and how they differ.
7645///
7646/// @param first a pointer to the first type_decl to
7647/// consider.
7648///
7649/// @param second a pointer to the second type_decl to consider.
7650///
7651/// @param ctxt the diff context to use.
7652///
7653/// @return a pointer to the resulting type_decl_diff.
7656 const type_decl_sptr second,
7657 diff_context_sptr ctxt)
7658{
7659 type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7660
7661 // We don't need to actually compute a diff here as a type_decl
7662 // doesn't have complicated sub-components. type_decl_diff::report
7663 // just walks the members of the type_decls and display information
7664 // about the ones that have changed. On a similar note,
7665 // type_decl_diff::length returns 0 if the two type_decls are equal,
7666 // and 1 otherwise.
7667
7668 ctxt->initialize_canonical_diff(result);
7669
7670 return result;
7671}
7672
7673// </type_decl_diff stuff>
7674
7675// <typedef_diff stuff>
7676
7677/// Populate the vector of children node of the @ref diff base type
7678/// sub-object of this instance of @ref typedef_diff.
7679///
7680/// The children node can then later be retrieved using
7681/// diff::children_node().
7682void
7685
7686/// Constructor for typedef_diff.
7687///
7688/// @param first the first subject of the diff.
7689///
7690/// @param second the second subject of the diff.
7691///
7692/// @param underlying the underlying diff of the @ref typedef_diff.
7693/// That is the diff between the underlying types of @p first and @p
7694/// second.
7695///
7696/// @param ctxt the context of the diff. Note that this context
7697/// object must stay alive at least during the life time of the
7698/// current instance of @ref typedef_diff. Otherwise memory
7699/// corruption issues occur.
7700typedef_diff::typedef_diff(const typedef_decl_sptr first,
7701 const typedef_decl_sptr second,
7702 const diff_sptr underlying,
7703 diff_context_sptr ctxt)
7704 : type_diff_base(first, second, ctxt),
7705 priv_(new priv(underlying))
7706{}
7707
7708/// Getter for the firt typedef_decl involved in the diff.
7709///
7710/// @return the first subject of the diff.
7713{return dynamic_pointer_cast<typedef_decl>(first_subject());}
7714
7715/// Getter for the second typedef_decl involved in the diff.
7716///
7717/// @return the second subject of the diff.
7720{return dynamic_pointer_cast<typedef_decl>(second_subject());}
7721
7722/// Getter for the diff between the two underlying types of the
7723/// typedefs.
7724///
7725/// @return the diff object reprensenting the difference between the
7726/// two underlying types of the typedefs.
7727const diff_sptr
7729{return priv_->underlying_type_diff_;}
7730
7731/// Setter for the diff between the two underlying types of the
7732/// typedefs.
7733///
7734/// @param d the new diff object reprensenting the difference between
7735/// the two underlying types of the typedefs.
7736void
7738{priv_->underlying_type_diff_ = d;}
7739
7740/// @return the pretty representation for the current instance of @ref
7741/// typedef_diff.
7742const string&
7744{
7745 if (diff::priv_->pretty_representation_.empty())
7746 {
7747 std::ostringstream o;
7748 o << "typedef_diff["
7749 << first_subject()->get_pretty_representation()
7750 << ", "
7751 << second_subject()->get_pretty_representation()
7752 << "]";
7753 diff::priv_->pretty_representation_ = o.str();
7754 }
7755 return diff::priv_->pretty_representation_;
7756}
7757
7758/// Return true iff the current diff node carries a change.
7759///
7760/// @return true iff the current diff node carries a change.
7761bool
7763{
7764 decl_base_sptr second = second_typedef_decl();
7765 return !(*first_typedef_decl() == *second);
7766}
7767
7768/// @return the kind of local change carried by the current diff node.
7769/// The value returned is zero if the current node carries no local
7770/// change.
7771enum change_kind
7773{
7774 ir::change_kind k = ir::NO_CHANGE_KIND;
7776 return k & ir::ALL_LOCAL_CHANGES_MASK;
7777 return ir::NO_CHANGE_KIND;
7778}
7779
7780/// Reports the difference between the two subjects of the diff in a
7781/// serialized form.
7782///
7783/// @param out the output stream to emit the report to.
7784///
7785/// @param indent the indentation string to use.
7786void
7787typedef_diff::report(ostream& out, const string& indent) const
7788{
7789 context()->get_reporter()->report(*this, out, indent);
7790}
7791
7792/// Compute a diff between two typedef_decl.
7793///
7794/// Note that the two types must have been created in the same @ref
7795/// environment, otherwise, this function aborts.
7796///
7797/// @param first a pointer to the first typedef_decl to consider.
7798///
7799/// @param second a pointer to the second typedef_decl to consider.
7800///
7801/// @param ctxt the diff context to use.
7802///
7803/// @return a pointer to the the resulting typedef_diff.
7806 const typedef_decl_sptr second,
7807 diff_context_sptr ctxt)
7808{
7809 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
7810 second->get_underlying_type(),
7811 ctxt);
7812 typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
7813
7814 ctxt->initialize_canonical_diff(result);
7815
7816 return result;
7817}
7818
7819/// Return the leaf underlying diff node of a @ref typedef_diff node.
7820///
7821/// If the underlying diff node of a @ref typedef_diff node is itself
7822/// a @ref typedef_diff node, then recursively look at the underlying
7823/// diff nodes to get the first one that is not a a @ref typedef_diff
7824/// node. This is what a leaf underlying diff node means.
7825///
7826/// Otherwise, if the underlying diff node of @ref typedef_diff is
7827/// *NOT* a @ref typedef_diff node, then just return the underlying
7828/// diff node.
7829///
7830/// And if the diff node considered is not a @ref typedef_diff node,
7831/// then just return it.
7832///
7833/// @return the leaf underlying diff node of a @p diff.
7834const diff*
7836{
7837 const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
7838 if (!d)
7839 return diff;
7840
7841 if (const typedef_diff* deef =
7842 dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
7844
7845 return d->underlying_type_diff().get();
7846}
7847
7848// </typedef_diff stuff>
7849
7850// <translation_unit_diff stuff>
7851
7852/// Constructor for translation_unit_diff.
7853///
7854/// @param first the first translation unit to consider for this diff.
7855///
7856/// @param second the second translation unit to consider for this diff.
7857///
7858/// @param ctxt the context of the diff. Note that this context
7859/// object must stay alive at least during the life time of the
7860/// current instance of @ref translation_unit_diff. Otherwise memory
7861/// corruption issues occur.
7863 translation_unit_sptr second,
7864 diff_context_sptr ctxt)
7865 : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
7866 priv_(new priv(first, second))
7867{
7868}
7869
7870/// Getter for the first translation unit of this diff.
7871///
7872/// @return the first translation unit of this diff.
7875{return priv_->first_;}
7876
7877/// Getter for the second translation unit of this diff.
7878///
7879/// @return the second translation unit of this diff.
7882{return priv_->second_;}
7883
7884/// Return true iff the current diff node carries a change.
7885///
7886/// @return true iff the current diff node carries a change.
7887bool
7889{return scope_diff::has_changes();}
7890
7891/// @return the kind of local change carried by the current diff node.
7892/// The value returned is zero if the current node carries no local
7893/// change.
7894enum change_kind
7896{return ir::NO_CHANGE_KIND;}
7897
7898/// Report the diff in a serialized form.
7899///
7900/// @param out the output stream to serialize the report to.
7901///
7902/// @param indent the prefix to use as indentation for the report.
7903void
7904translation_unit_diff::report(ostream& out, const string& indent) const
7905{scope_diff::report(out, indent);}
7906
7907/// Compute the diff between two translation_units.
7908///
7909/// Note that the two translation units must have been created in the
7910/// same @ref environment, otherwise, this function aborts.
7911///
7912/// @param first the first translation_unit to consider.
7913///
7914/// @param second the second translation_unit to consider.
7915///
7916/// @param ctxt the diff context to use. If null, this function will
7917/// create a new context and set to the diff object returned.
7918///
7919/// @return the newly created diff object.
7922 const translation_unit_sptr second,
7923 diff_context_sptr ctxt)
7924{
7925 ABG_ASSERT(first && second);
7926
7927 if (!ctxt)
7928 ctxt.reset(new diff_context);
7929
7930 // TODO: handle first or second having empty contents.
7931 translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
7932 ctxt));
7933 scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
7934
7935 compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
7936 static_pointer_cast<scope_decl>(second->get_global_scope()),
7937 sc_diff,
7938 ctxt);
7939
7940 ctxt->initialize_canonical_diff(tu_diff);
7941
7942 return tu_diff;
7943}
7944
7945// </translation_unit_diff stuff>
7946
7947// <diff_maps stuff>
7948
7949/// The private data of the @ref diff_maps type.
7950struct diff_maps::priv
7951{
7952 string_diff_ptr_map type_decl_diff_map_;
7953 string_diff_ptr_map enum_diff_map_;
7954 string_diff_ptr_map class_diff_map_;
7955 string_diff_ptr_map union_diff_map_;
7956 string_diff_ptr_map typedef_diff_map_;
7957 string_diff_ptr_map subrange_diff_map_;
7958 string_diff_ptr_map array_diff_map_;
7959 string_diff_ptr_map reference_diff_map_;
7960 string_diff_ptr_map function_type_diff_map_;
7961 string_diff_ptr_map function_decl_diff_map_;
7962 string_diff_ptr_map var_decl_diff_map_;
7963 string_diff_ptr_map distinct_diff_map_;
7964 string_diff_ptr_map fn_parm_diff_map_;
7965 diff_artifact_set_map_type impacted_artifacts_map_;
7966}; // end struct diff_maps::priv
7967
7968/// Default constructor of the @ref diff_maps type.
7970 : priv_(new diff_maps::priv())
7971{}
7972
7973diff_maps::~diff_maps() = default;
7974
7975/// Getter of the map that contains basic type diffs.
7976///
7977/// @return the map that contains basic type diffs.
7980{return priv_->type_decl_diff_map_;}
7981
7982/// Getter of the map that contains basic type diffs.
7983///
7984/// @return the map that contains basic type diffs.
7987{return priv_->type_decl_diff_map_;}
7988
7989/// Getter of the map that contains enum type diffs.
7990///
7991/// @return the map that contains enum type diffs.
7994{return priv_->enum_diff_map_;}
7995
7996/// Getter of the map that contains enum type diffs.
7997///
7998/// @return the map that contains enum type diffs.
8001{return priv_->enum_diff_map_;}
8002
8003/// Getter of the map that contains class type diffs.
8004///
8005/// @return the map that contains class type diffs.
8008{return priv_->class_diff_map_;}
8009
8010/// Getter of the map that contains class type diffs.
8011///
8012/// @return the map that contains class type diffs.
8015{return priv_->class_diff_map_;}
8016
8017/// Getter of the map that contains union type diffs.
8018///
8019/// @return the map that contains union type diffs.
8022{return priv_->union_diff_map_;}
8023
8024/// Getter of the map that contains union type diffs.
8025///
8026/// @return the map that contains union type diffs.
8029{return priv_->union_diff_map_;}
8030
8031/// Getter of the map that contains typedef type diffs.
8032///
8033/// @return the map that contains typedef type diffs.
8036{return priv_->typedef_diff_map_;}
8037
8038/// Getter of the map that contains typedef type diffs.
8039///
8040/// @return the map that contains typedef type diffs.
8043{return priv_->typedef_diff_map_;}
8044
8045/// Getter of the map that contains subrange type diffs.
8046///
8047/// @return the map that contains subrange type diffs.
8050{return priv_->subrange_diff_map_;}
8051
8052/// Getter of the map that contains subrange type diffs.
8053///
8054/// @return the map that contains subrange type diffs.
8057{return priv_->subrange_diff_map_;}
8058
8059/// Getter of the map that contains array type diffs.
8060///
8061/// @return the map that contains array type diffs.
8064{return priv_->array_diff_map_;}
8065
8066/// Getter of the map that contains array type diffs.
8067///
8068/// @return the map that contains array type diffs.
8071{return priv_->array_diff_map_;}
8072
8073/// Getter of the map that contains reference type diffs.
8074///
8075/// @return the map that contains reference type diffs.
8078{return priv_->reference_diff_map_;}
8079
8080/// Getter of the map that contains reference type diffs.
8081///
8082/// @return the map that contains reference type diffs.
8085{{return priv_->reference_diff_map_;}}
8086
8087/// Getter of the map that contains function parameter diffs.
8088///
8089/// @return the map that contains function parameter diffs.
8092{return priv_->fn_parm_diff_map_;}
8093
8094/// Getter of the map that contains function parameter diffs.
8095///
8096/// @return the map that contains function parameter diffs.
8099{return priv_->fn_parm_diff_map_;}
8100
8101/// Getter of the map that contains function type diffs.
8102///
8103/// @return the map that contains function type diffs.
8106{return priv_->function_type_diff_map_;}
8107
8108/// Getter of the map that contains function type diffs.
8109///
8110/// @return the map that contains function type diffs.
8113{return priv_->function_type_diff_map_;}
8114
8115/// Getter of the map that contains function decl diffs.
8116///
8117/// @return the map that contains function decl diffs.
8120{return priv_->function_decl_diff_map_;}
8121
8122/// Getter of the map that contains function decl diffs.
8123///
8124/// @return the map that contains function decl diffs.
8127{return priv_->function_decl_diff_map_;}
8128
8129/// Getter of the map that contains var decl diffs.
8130///
8131/// @return the map that contains var decl diffs.
8134{return priv_->var_decl_diff_map_;}
8135
8136/// Getter of the map that contains var decl diffs.
8137///
8138/// @return the map that contains var decl diffs.
8141{return priv_->var_decl_diff_map_;}
8142
8143/// Getter of the map that contains distinct diffs.
8144///
8145/// @return the map that contains distinct diffs.
8148{return priv_->distinct_diff_map_;}
8149
8150/// Getter of the map that contains distinct diffs.
8151///
8152/// @return the map that contains distinct diffs.
8155{return priv_->distinct_diff_map_;}
8156
8157/// Insert a new diff node into the current instance of @ref diff_maps.
8158///
8159/// @param dif the new diff node to insert into the @ref diff_maps.
8160///
8161/// @param impacted_iface the interface (global function or variable)
8162/// currently being analysed that led to analysing the diff node @p
8163/// dif. In other words, this is the interface impacted by the diff
8164/// node @p dif. Note that this can be nil in cases where we are
8165/// directly analysing changes to a type that is not reachable from
8166/// any global function or variable.
8167///
8168/// @return true iff the diff node could be added to the current
8169/// instance of @ref diff_maps.
8170bool
8172 const type_or_decl_base_sptr& impacted_iface)
8173{
8174 string n = get_pretty_representation(dif->first_subject(),
8175 /*internal=*/true);
8176 if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8177 get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8178 else if (const enum_diff *d = is_enum_diff(dif))
8179 get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8180 else if (const class_diff *d = is_class_diff(dif))
8181 get_class_diff_map()[n] = const_cast<class_diff*>(d);
8182 else if (const union_diff *d = is_union_diff(dif))
8183 get_union_diff_map()[n] = const_cast<union_diff*>(d);
8184 else if (const typedef_diff *d = is_typedef_diff(dif))
8185 get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8186 else if (const subrange_diff *d = is_subrange_diff(dif))
8187 get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8188 else if (const array_diff *d = is_array_diff(dif))
8189 get_array_diff_map()[n] = const_cast<array_diff*>(d);
8190 else if (const reference_diff *d = is_reference_diff(dif))
8191 get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8192 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8193 get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8194 else if (const function_type_diff *d = is_function_type_diff(dif))
8195 get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8196 else if (const var_diff *d = is_var_diff(dif))
8197 get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8198 else if (const function_decl_diff *d = is_function_decl_diff(dif))
8199 get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8200 else if (const distinct_diff *d = is_distinct_diff(dif))
8201 get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8202 else if (is_base_diff(dif))
8203 // we silently drop this case.
8204 return true;
8205 else
8207
8208 // Update the map that associates this diff node to the set of
8209 // interfaces it impacts.
8210
8211 if (impacted_iface)
8212 {
8213 diff_artifact_set_map_type::iterator i =
8214 priv_->impacted_artifacts_map_.find(dif);
8215
8216 if (i == priv_->impacted_artifacts_map_.end())
8217 {
8219 set.insert(impacted_iface);
8220 priv_->impacted_artifacts_map_[dif] = set;
8221 }
8222 else
8223 i->second.insert(impacted_iface);
8224 }
8225
8226 return true;
8227}
8228
8229/// Lookup the interfaces that are impacted by a given leaf diff node.
8230///
8231/// @param d the diff node to consider.
8232///
8233/// @return the set of artifacts impacted by @p d.
8236{
8237 diff_artifact_set_map_type::iterator i =
8238 priv_->impacted_artifacts_map_.find(d);
8239
8240 if (i == priv_->impacted_artifacts_map_.end())
8241 return 0;
8242
8243 return &i->second;
8244}
8245
8246//
8247// </diff_maps stuff>
8248
8249/// Constructor for the @ref diff_stat type.
8250///
8251/// @param ctxt the context of the corpus diff. Note that this
8252/// context object must stay alive at least during the life time of
8253/// the current instance of @ref corpus_diff::diff_stats. Otherwise
8254/// memory corruption issues occur.
8255corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8256 : priv_(new priv(ctxt))
8257{}
8258
8259/// Getter for the number of functions removed.
8260///
8261/// @return the number of functions removed.
8262size_t
8264{return priv_->num_func_removed;}
8265
8266/// Setter for the number of functions removed.
8267///
8268/// @param n the new number of functions removed.
8269void
8271{priv_->num_func_removed = n;}
8272
8273/// Getter for the number of removed functions that have been filtered
8274/// out.
8275///
8276/// @return the number of removed functions that have been filtered
8277/// out.
8278size_t
8280{
8281 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8282 return num_func_removed();
8283 return priv_->num_removed_func_filtered_out;
8284}
8285
8286/// Setter for the number of removed functions that have been filtered
8287/// out.
8288///
8289/// @param t the new value.
8290void
8292{priv_->num_removed_func_filtered_out = t;}
8293
8294/// Getter for the net number of function removed.
8295///
8296/// This is the difference between the number of functions removed and
8297/// the number of functons removed that have been filtered out.
8298///
8299/// @return the net number of function removed.
8300size_t
8302{
8303 ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8304 return num_func_removed() - num_removed_func_filtered_out();
8305}
8306
8307/// Getter for the number of functions added.
8308///
8309/// @return the number of functions added.
8310size_t
8312{return priv_->num_func_added;}
8313
8314/// Setter for the number of functions added.
8315///
8316/// @param n the new number of functions added.
8317void
8319{priv_->num_func_added = n;}
8320
8321/// Getter for the number of added function that have been filtered out.
8322///
8323/// @return the number of added function that have been filtered out.
8324size_t
8326{
8327 if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8328 return num_func_added();
8329 return priv_->num_added_func_filtered_out;
8330}
8331
8332/// Setter for the number of added function that have been filtered
8333/// out.
8334///
8335/// @param n the new value.
8336void
8338{priv_->num_added_func_filtered_out = n;}
8339
8340/// Getter for the net number of added functions.
8341///
8342/// The net number of added functions is the difference between the
8343/// number of added functions and the number of added functions that
8344/// have been filtered out.
8345///
8346/// @return the net number of added functions.
8347size_t
8349{
8350 ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8351 return num_func_added() - num_added_func_filtered_out();
8352}
8353
8354/// Getter for the number of functions that have a change in one of
8355/// their sub-types.
8356///
8357/// @return the number of functions that have a change in one of their
8358/// sub-types.
8359size_t
8361{return priv_->num_func_changed;}
8362
8363/// Setter for the number of functions that have a change in one of
8364/// their sub-types.
8365///
8366/// @@param n the new number of functions that have a change in one of
8367/// their sub-types.
8368void
8370{priv_->num_func_changed = n;}
8371
8372/// Getter for the number of functions that have a change in one of
8373/// their sub-types, and that have been filtered out.
8374///
8375/// @return the number of functions that have a change in one of their
8376/// sub-types, and that have been filtered out.
8377size_t
8379{return priv_->num_changed_func_filtered_out;}
8380
8381/// Setter for the number of functions that have a change in one of
8382/// their sub-types, and that have been filtered out.
8383///
8384/// @param n the new number of functions that have a change in one of their
8385/// sub-types, and that have been filtered out.
8386void
8388{priv_->num_changed_func_filtered_out = n;}
8389
8390/// Getter for the number of functions that carry virtual member
8391/// offset changes.
8392///
8393/// @return the number of functions that carry virtual member changes.
8394size_t
8396{return priv_->num_func_with_virt_offset_changes;}
8397
8398/// Setter for the number of functions that carry virtual member
8399/// offset changes.
8400///
8401/// @param n the new number of functions that carry virtual member
8402/// offset. changes.
8403void
8405{priv_->num_func_with_virt_offset_changes = n;}
8406
8407/// Getter for the number of functions that have a change in their
8408/// sub-types, minus the number of these functions that got filtered
8409/// out from the diff.
8410///
8411/// @return for the the number of functions that have a change in
8412/// their sub-types, minus the number of these functions that got
8413/// filtered out from the diff.
8414size_t
8416{return num_func_changed() - num_changed_func_filtered_out();}
8417
8418/// Getter for the number of variables removed.
8419///
8420/// @return the number of variables removed.
8421size_t
8423{return priv_->num_vars_removed;}
8424
8425/// Setter for the number of variables removed.
8426///
8427/// @param n the new number of variables removed.
8428void
8430{priv_->num_vars_removed = n;}
8431
8432/// Getter for the number removed variables that have been filtered
8433/// out.
8434///
8435/// @return the number removed variables that have been filtered out.
8436size_t
8438{
8439 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
8440 return num_vars_removed();
8441 return priv_->num_removed_vars_filtered_out;
8442}
8443
8444/// Setter for the number of removed variables that have been filtered
8445/// out.
8446///
8447/// @param n the new value.
8448void
8450{priv_->num_removed_vars_filtered_out = n;}
8451
8452/// Getter for the net number of removed variables.
8453///
8454/// The net number of removed variables is the difference between the
8455/// number of removed variables and the number of removed variables
8456/// that have been filtered out.
8457///
8458/// @return the net number of removed variables.
8459size_t
8461{
8462 ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
8463 return num_vars_removed() - num_removed_vars_filtered_out();
8464}
8465
8466/// Getter for the number of variables added.
8467///
8468/// @return the number of variables added.
8469size_t
8471{return priv_->num_vars_added;}
8472
8473/// Setter for the number of variables added.
8474///
8475/// @param n the new number of variables added.
8476void
8478{priv_->num_vars_added = n;}
8479
8480/// Getter for the number of added variables that have been filtered
8481/// out.
8482///
8483/// @return the number of added variables that have been filtered out.
8484size_t
8486{
8487 if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8488 return num_vars_added();
8489 return priv_->num_added_vars_filtered_out;
8490}
8491
8492/// Setter for the number of added variables that have been filtered
8493/// out.
8494///
8495/// @param n the new value.
8496void
8498{priv_->num_added_vars_filtered_out = n;}
8499
8500/// Getter for the net number of added variables.
8501///
8502/// The net number of added variables is the difference between the
8503/// number of added variables and the number of added variables that
8504/// have been filetered out.
8505///
8506/// @return the net number of added variables.
8507size_t
8509{
8510 ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8511 return num_vars_added() - num_added_vars_filtered_out();
8512}
8513
8514/// Getter for the number of variables that have a change in one of
8515/// their sub-types.
8516///
8517/// @return the number of variables that have a change in one of their
8518/// sub-types.
8519size_t
8521{return priv_->num_vars_changed;}
8522
8523/// Setter for the number of variables that have a change in one of
8524/// their sub-types.
8525///
8526/// @param n the new number of variables that have a change in one of
8527/// their sub-types.
8528void
8530{priv_->num_vars_changed = n;}
8531
8532/// Getter for the number of variables that have a change in one of
8533/// their sub-types, and that have been filtered out.
8534///
8535/// @return the number of functions that have a change in one of their
8536/// sub-types, and that have been filtered out.
8537size_t
8539{return priv_->num_changed_vars_filtered_out;}
8540
8541/// Setter for the number of variables that have a change in one of
8542/// their sub-types, and that have been filtered out.
8543///
8544/// @param n the new number of variables that have a change in one of their
8545/// sub-types, and that have been filtered out.
8546void
8548{priv_->num_changed_vars_filtered_out = n;}
8549
8550/// Getter for the number of variables that have a change in their
8551/// sub-types, minus the number of these variables that got filtered
8552/// out from the diff.
8553///
8554/// @return for the the number of variables that have a change in
8555/// their sub-types, minus the number of these variables that got
8556/// filtered out from the diff.
8557size_t
8559{return num_vars_changed() - num_changed_vars_filtered_out();}
8560
8561/// Getter for the number of function symbols (not referenced by any
8562/// debug info) that got removed.
8563///
8564/// @return the number of function symbols (not referenced by any
8565/// debug info) that got removed.
8566size_t
8568{return priv_->num_func_syms_removed;}
8569
8570/// Setter for the number of function symbols (not referenced by any
8571/// debug info) that got removed.
8572///
8573/// @param n the number of function symbols (not referenced by any
8574/// debug info) that got removed.
8575void
8577{priv_->num_func_syms_removed = n;}
8578
8579/// Getter for the number of removed function symbols, not referenced
8580/// by debug info, that have been filtered out.
8581///
8582/// @return the number of removed function symbols, not referenced by
8583/// debug info, that have been filtered out.
8584size_t
8586{
8587 if (priv_->ctxt()
8588 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8589 return num_func_syms_removed();
8590 return priv_->num_removed_func_syms_filtered_out;
8591}
8592
8593/// Setter for the number of removed function symbols, not referenced
8594/// by debug info, that have been filtered out.
8595///
8596/// @param n the new the number of removed function symbols, not
8597/// referenced by debug info, that have been filtered out.
8598void
8600{priv_->num_removed_func_syms_filtered_out = n;}
8601
8602/// Getter of the net number of removed function symbols that are not
8603/// referenced by any debug info.
8604///
8605/// This is the difference between the total number of removed
8606/// function symbols and the number of removed function symbols that
8607/// have been filteted out. Both numbers are for symbols not
8608/// referenced by debug info.
8609///
8610/// return the net number of removed function symbols that are not
8611/// referenced by any debug info.
8612size_t
8614{
8615 ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8616 return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8617}
8618
8619/// Getter for the number of function symbols (not referenced by any
8620/// debug info) that got added.
8621///
8622/// @return the number of function symbols (not referenced by any
8623/// debug info) that got added.
8624size_t
8626{return priv_->num_func_syms_added;}
8627
8628/// Setter for the number of function symbols (not referenced by any
8629/// debug info) that got added.
8630///
8631/// @param n the new number of function symbols (not referenced by any
8632/// debug info) that got added.
8633void
8635{priv_->num_func_syms_added = n;}
8636
8637/// Getter for the number of added function symbols, not referenced by
8638/// any debug info, that have been filtered out.
8639///
8640/// @return the number of added function symbols, not referenced by
8641/// any debug info, that have been filtered out.
8642size_t
8644{
8645 if (priv_->ctxt()
8646 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8647 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8648 return num_func_syms_added();
8649 return priv_->num_added_func_syms_filtered_out;
8650}
8651
8652/// Setter for the number of added function symbols, not referenced by
8653/// any debug info, that have been filtered out.
8654///
8655/// @param n the new number of added function symbols, not referenced
8656/// by any debug info, that have been filtered out.
8657void
8659{priv_->num_added_func_syms_filtered_out = n;}
8660
8661/// Getter of the net number of added function symbols that are not
8662/// referenced by any debug info.
8663///
8664/// This is the difference between the total number of added
8665/// function symbols and the number of added function symbols that
8666/// have been filteted out. Both numbers are for symbols not
8667/// referenced by debug info.
8668///
8669/// return the net number of added function symbols that are not
8670/// referenced by any debug info.
8671size_t
8673{
8674 ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8675 return num_func_syms_added()- num_added_func_syms_filtered_out();
8676}
8677
8678/// Getter for the number of variable symbols (not referenced by any
8679/// debug info) that got removed.
8680///
8681/// @return the number of variable symbols (not referenced by any
8682/// debug info) that got removed.
8683size_t
8685{return priv_->num_var_syms_removed;}
8686
8687/// Setter for the number of variable symbols (not referenced by any
8688/// debug info) that got removed.
8689///
8690/// @param n the number of variable symbols (not referenced by any
8691/// debug info) that got removed.
8692void
8694{priv_->num_var_syms_removed = n;}
8695
8696/// Getter for the number of removed variable symbols, not referenced
8697/// by any debug info, that have been filtered out.
8698///
8699/// @return the number of removed variable symbols, not referenced
8700/// by any debug info, that have been filtered out.
8701size_t
8703{
8704 if (priv_->ctxt()
8705 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8706 return num_var_syms_removed();
8707 return priv_->num_removed_var_syms_filtered_out;
8708}
8709
8710/// Setter for the number of removed variable symbols, not referenced
8711/// by any debug info, that have been filtered out.
8712///
8713/// @param n the number of removed variable symbols, not referenced by
8714/// any debug info, that have been filtered out.
8715void
8717{priv_->num_removed_var_syms_filtered_out = n;}
8718
8719/// Getter of the net number of removed variable symbols that are not
8720/// referenced by any debug info.
8721///
8722/// This is the difference between the total number of removed
8723/// variable symbols and the number of removed variable symbols that
8724/// have been filteted out. Both numbers are for symbols not
8725/// referenced by debug info.
8726///
8727/// return the net number of removed variable symbols that are not
8728/// referenced by any debug info.
8729size_t
8731{
8732 ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
8733 return num_var_syms_removed() - num_removed_var_syms_filtered_out();
8734}
8735
8736/// Getter for the number of variable symbols (not referenced by any
8737/// debug info) that got added.
8738///
8739/// @return the number of variable symbols (not referenced by any
8740/// debug info) that got added.
8741size_t
8743{return priv_->num_var_syms_added;}
8744
8745/// Setter for the number of variable symbols (not referenced by any
8746/// debug info) that got added.
8747///
8748/// @param n the new number of variable symbols (not referenced by any
8749/// debug info) that got added.
8750void
8752{priv_->num_var_syms_added = n;}
8753
8754/// Getter for the number of added variable symbols, not referenced by
8755/// any debug info, that have been filtered out.
8756///
8757/// @return the number of added variable symbols, not referenced by
8758/// any debug info, that have been filtered out.
8759size_t
8761{
8762 if (priv_->ctxt()
8763 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8764 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8765 return num_var_syms_added();
8766 return priv_->num_added_var_syms_filtered_out;
8767}
8768
8769/// Setter for the number of added variable symbols, not referenced by
8770/// any debug info, that have been filtered out.
8771///
8772/// @param n the new number of added variable symbols, not referenced
8773/// by any debug info, that have been filtered out.
8774void
8776{priv_->num_added_var_syms_filtered_out = n;}
8777
8778/// Getter of the net number of added variable symbols that are not
8779/// referenced by any debug info.
8780///
8781/// This is the difference between the total number of added
8782/// variable symbols and the number of added variable symbols that
8783/// have been filteted out. Both numbers are for symbols not
8784/// referenced by debug info.
8785///
8786/// return the net number of added variable symbols that are not
8787/// referenced by any debug info.
8788size_t
8790{
8791 ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
8792 return num_var_syms_added() - num_added_var_syms_filtered_out();
8793}
8794
8795/// Getter of the number of leaf type change diff nodes.
8796///
8797/// @return the number of leaf type change diff nodes.
8798size_t
8800{return priv_->num_leaf_changes;}
8801
8802/// Setter of the number of leaf type change diff nodes.
8803///
8804/// @param n the new number of leaf type change diff nodes.
8805void
8807{priv_->num_leaf_changes = n;}
8808
8809/// Getter of the number of leaf type change diff nodes that have been
8810/// filtered out.
8811///
8812/// @return the number of leaf type change diff nodes that have been
8813size_t
8815{return priv_->num_leaf_changes_filtered_out;}
8816
8817/// Setter of the number of leaf type change diff nodes that have been
8818/// filtered out.
8819///
8820/// @param n the new number of leaf type change diff nodes that have
8821/// been filtered out.
8822void
8824{priv_->num_leaf_changes_filtered_out = n;}
8825
8826/// Getter of the net number of leaf change diff nodes.
8827///
8828/// This is the difference between the total number of leaf change
8829/// diff nodes, and the number of the leaf change diff nodes that have
8830/// been filtered out.
8831///
8832/// A leaf change is either a type change, a function change or a
8833/// variable change.
8834size_t
8836{
8837 ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
8838 return num_leaf_changes() - num_leaf_changes_filtered_out();
8839}
8840
8841/// Getter for the number of leaf type change diff nodes.
8842///
8843/// @return the number of leaf type changes diff nodes.
8844size_t
8846{return priv_->num_leaf_type_changes;}
8847
8848/// Setter for the number of leaf type change diff nodes.
8849///
8850/// @param n the new number of leaf type change diff nodes.
8851void
8853{priv_->num_leaf_type_changes = n;}
8854
8855/// Getter for the number of filtered out leaf type change diff nodes.
8856///
8857/// @return the number of filtered out leaf type change diff nodes.
8858size_t
8860{return priv_->num_leaf_type_changes_filtered_out;}
8861
8862/// Setter for the number of filtered out leaf type change diff nodes.
8863/// @param n the new number of filtered out leaf type change diff nodes.
8864void
8866{priv_->num_leaf_type_changes_filtered_out = n;}
8867
8868/// Getter for the net number of leaf type change diff nodes.
8869///
8870/// This is the difference between the number of leaf type changes and
8871/// the number of filtered out leaf type changes.
8872///
8873/// @return the net number of leaf type change diff nodes.
8874size_t
8876{return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
8877
8878/// Getter for the number of leaf function change diff nodes.
8879///
8880/// @return the number of leaf function change diff nodes.
8881size_t
8883{return priv_->num_leaf_func_changes;}
8884
8885/// Setter for the number of leaf function change diff nodes.
8886///
8887/// @param n the new number of leaf function change diff nodes.
8888void
8890{priv_->num_leaf_func_changes = n;}
8891
8892/// Getter for the number of leaf function change diff nodes that were
8893/// filtered out.
8894///
8895/// @return the number of leaf function change diff nodes that were
8896/// filtered out.
8897size_t
8899{return priv_->num_leaf_func_changes_filtered_out;}
8900
8901/// Setter for the number of leaf function change diff nodes that were
8902/// filtered out.
8903///
8904/// @param n the new number of leaf function change diff nodes that
8905/// were filtered out.
8906void
8908{priv_->num_leaf_func_changes_filtered_out = n;}
8909
8910/// Getter for the net number of leaf function change diff nodes.
8911///
8912/// This is the difference between the number of leaf function change
8913/// diff nodes and the number of filtered out leaf function change
8914/// diff nodes.
8915///
8916/// @return the net number of leaf function change diff nodes.
8917size_t
8919{return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
8920
8921/// Getter for the number of leaf variable change diff nodes.
8922///
8923/// @return the number of leaf variable change diff nodes.
8924size_t
8926{return priv_->num_leaf_var_changes;}
8927
8928/// Setter for the number of leaf variable change diff nodes.
8929///
8930/// @param n the number of leaf variable change diff nodes.
8931void
8933{priv_->num_leaf_var_changes = n;}
8934
8935/// Getter of the number of added types that are unreachable from the
8936/// public interface of the ABI corpus.
8937///
8938/// Public interface means the set of defined and publicly exported
8939/// functions and variables of the ABI corpus.
8940///
8941/// @return the number of added types that are unreachable from the
8942/// public interface of the ABI corpus.
8943size_t
8945{return priv_->num_added_unreachable_types;}
8946
8947/// Setter of the number of added types that are unreachable from the
8948/// public interface (global functions or variables) of the ABI
8949/// corpus.
8950///
8951/// Public interface means the set of defined and publicly exported
8952/// functions and variables of the ABI corpus.
8953///
8954/// @param n the new number of added types that are unreachable from
8955/// the public interface of the ABI corpus.
8956void
8958{priv_->num_added_unreachable_types = n;}
8959
8960/// Getter of the number of added types that are unreachable from
8961/// public interfaces and that are filtered out by suppression
8962/// specifications.
8963///
8964/// @return the number of added types that are unreachable from public
8965/// interfaces and that are filtered out by suppression
8966/// specifications.
8967size_t
8969{return priv_->num_added_unreachable_types_filtered_out;}
8970
8971/// Setter of the number of added types that are unreachable from
8972/// public interfaces and that are filtered out by suppression
8973/// specifications.
8974///
8975/// @param n the new number of added types that are unreachable from
8976/// public interfaces and that are filtered out by suppression
8977/// specifications.
8978void
8980{priv_->num_added_unreachable_types_filtered_out = n;}
8981
8982/// Getter of the number of added types that are unreachable from
8983/// public interfaces and that are *NOT* filtered out by suppression
8984/// specifications.
8985///
8986/// @return the number of added types that are unreachable from public
8987/// interfaces and that are *NOT* filtered out by suppression
8988/// specifications.
8989size_t
8991{
8992 ABG_ASSERT(num_added_unreachable_types()
8993 >=
8994 num_added_unreachable_types_filtered_out());
8995
8996 return (num_added_unreachable_types()
8997 -
8998 num_added_unreachable_types_filtered_out());
8999}
9000
9001/// Getter of the number of removed types that are unreachable from
9002/// the public interface of the ABI corpus.
9003///
9004/// Public interface means the set of defined and publicly exported
9005/// functions and variables of the ABI corpus.
9006///
9007/// @return the number of removed types that are unreachable from
9008/// the public interface of the ABI corpus.
9009size_t
9011{return priv_->num_removed_unreachable_types;}
9012
9013/// Setter of the number of removed types that are unreachable from
9014/// the public interface of the ABI corpus.
9015///
9016/// Public interface means the set of defined and publicly exported
9017/// functions and variables of the ABI corpus.
9018///
9019///@param n the new number of removed types that are unreachable from
9020/// the public interface of the ABI corpus.
9021void
9023{priv_->num_removed_unreachable_types = n;}
9024
9025/// Getter of the number of removed types that are not reachable from
9026/// public interfaces and that have been filtered out by suppression
9027/// specifications.
9028///
9029/// @return the number of removed types that are not reachable from
9030/// public interfaces and that have been filtered out by suppression
9031/// specifications.
9032size_t
9034{return priv_->num_removed_unreachable_types_filtered_out;}
9035
9036/// Setter of the number of removed types that are not reachable from
9037/// public interfaces and that have been filtered out by suppression
9038/// specifications.
9039///
9040/// @param n the new number of removed types that are not reachable
9041/// from public interfaces and that have been filtered out by
9042/// suppression specifications.
9043void
9045{priv_->num_removed_unreachable_types_filtered_out = n;}
9046
9047/// Getter of the number of removed types that are not reachable from
9048/// public interfaces and that have *NOT* been filtered out by
9049/// suppression specifications.
9050///
9051/// @return the number of removed types that are not reachable from
9052/// public interfaces and that have *NOT* been filtered out by
9053/// suppression specifications.
9054size_t
9056{
9057 ABG_ASSERT(num_removed_unreachable_types()
9058 >=
9059 num_removed_unreachable_types_filtered_out());
9060
9061 return (num_removed_unreachable_types()
9062 -
9063 num_removed_unreachable_types_filtered_out());
9064}
9065
9066/// Getter of the number of changed types that are unreachable from
9067/// the public interface of the ABI corpus.
9068///
9069/// Public interface means the set of defined and publicly exported
9070/// functions and variables of the ABI corpus.
9071///
9072/// @return the number of changed types that are unreachable from the
9073/// public interface of the ABI corpus.
9074size_t
9076{return priv_->num_changed_unreachable_types;}
9077
9078/// Setter of the number of changed types that are unreachable from
9079/// the public interface of the ABI corpus.
9080///
9081/// Public interface means the set of defined and publicly exported
9082/// functions and variables of the ABI corpus.
9083///
9084///@param n the new number of changed types that are unreachable from
9085/// the public interface of the ABI corpus.
9086void
9088{priv_->num_changed_unreachable_types = n;}
9089
9090/// Getter of the number of changed types that are unreachable from
9091/// public interfaces and that have been filtered out by suppression
9092/// specifications.
9093///
9094/// @return the number of changed types that are unreachable from
9095/// public interfaces and that have been filtered out by suppression
9096/// specifications.
9097size_t
9099{return priv_->num_changed_unreachable_types_filtered_out;}
9100
9101/// Setter of the number of changed types that are unreachable from
9102/// public interfaces and that have been filtered out by suppression
9103/// specifications.
9104///
9105/// @param n the new number of changed types that are unreachable from
9106/// public interfaces and that have been filtered out by suppression
9107/// specifications.
9108void
9110{priv_->num_changed_unreachable_types_filtered_out = n;}
9111
9112/// Getter of the number of changed types that are unreachable from
9113/// public interfaces and that have *NOT* been filtered out by
9114/// suppression specifications.
9115///
9116/// @return the number of changed types that are unreachable from
9117/// public interfaces and that have *NOT* been filtered out by
9118/// suppression specifications.
9119size_t
9121{
9122 ABG_ASSERT(num_changed_unreachable_types()
9123 >=
9124 num_changed_unreachable_types_filtered_out());
9125
9126 return (num_changed_unreachable_types()
9127 -
9128 num_changed_unreachable_types_filtered_out());
9129}
9130
9131/// Getter for the number of leaf variable changes diff nodes that
9132/// have been filtered out.
9133///
9134/// @return the number of leaf variable changes diff nodes that have
9135/// been filtered out.
9136size_t
9138{return priv_->num_leaf_var_changes_filtered_out;}
9139
9140/// Setter for the number of leaf variable changes diff nodes that
9141/// have been filtered out.
9142///
9143/// @param n the number of leaf variable changes diff nodes that have
9144/// been filtered out.
9145void
9147{priv_->num_leaf_var_changes_filtered_out = n;}
9148
9149/// Getter for the net number of leaf variable change diff nodes.
9150///
9151/// This the difference between the number of leaf variable change
9152/// diff nodes and the number of filtered out leaf variable change
9153/// diff nodes.
9154///
9155/// @return the net number of leaf variable change diff nodes.
9156size_t
9158{return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9159
9160
9161// <corpus_diff stuff>
9162
9163/// Getter of the context associated with this corpus.
9164///
9165/// @return a smart pointer to the context associate with the corpus.
9168{return ctxt_.lock();}
9169
9170/// Tests if the lookup tables are empty.
9171///
9172/// @return true if the lookup tables are empty, false otherwise.
9173bool
9175{
9176 return (deleted_fns_.empty()
9177 && added_fns_.empty()
9178 && changed_fns_map_.empty()
9179 && deleted_vars_.empty()
9180 && added_vars_.empty()
9181 && changed_vars_map_.empty());
9182}
9183
9184/// Clear the lookup tables useful for reporting an enum_diff.
9185void
9187{
9188 deleted_fns_.clear();
9189 added_fns_.clear();
9190 changed_fns_map_.clear();
9191 deleted_vars_.clear();
9192 added_vars_.clear();
9193 changed_vars_map_.clear();
9194}
9195
9196/// If the lookup tables are not yet built, walk the differences and
9197/// fill the lookup tables.
9198void
9200{
9201 if (!lookup_tables_empty())
9202 return;
9203
9204 diff_context_sptr ctxt = get_context();
9205
9206 {
9207 edit_script& e = fns_edit_script_;
9208
9209 for (vector<deletion>::const_iterator it = e.deletions().begin();
9210 it != e.deletions().end();
9211 ++it)
9212 {
9213 unsigned i = it->index();
9214 ABG_ASSERT(i < first_->get_functions().size());
9215
9216 function_decl* deleted_fn = first_->get_functions()[i];
9217 string n = get_function_id_or_pretty_representation(deleted_fn);
9218 ABG_ASSERT(!n.empty());
9219 // The below is commented out because there can be several
9220 // functions with the same ID in the corpus. So several
9221 // functions with the same ID can be deleted.
9222 // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9223 deleted_fns_[n] = deleted_fn;
9224 }
9225
9226 for (vector<insertion>::const_iterator it = e.insertions().begin();
9227 it != e.insertions().end();
9228 ++it)
9229 {
9230 for (vector<unsigned>::const_iterator iit =
9231 it->inserted_indexes().begin();
9232 iit != it->inserted_indexes().end();
9233 ++iit)
9234 {
9235 unsigned i = *iit;
9236 function_decl* added_fn = second_->get_functions()[i];
9237 string n = get_function_id_or_pretty_representation(added_fn);
9238 ABG_ASSERT(!n.empty());
9239 // The below is commented out because there can be several
9240 // functions with the same ID in the corpus. So several
9241 // functions with the same ID can be added.
9242 // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9243 string_function_ptr_map::const_iterator j =
9244 deleted_fns_.find(n);
9245 if (j != deleted_fns_.end())
9246 {
9247 function_decl_sptr f(j->second, noop_deleter());
9248 function_decl_sptr s(added_fn, noop_deleter());
9249 function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9250 if (*j->second != *added_fn)
9251 changed_fns_map_[j->first] = d;
9252 deleted_fns_.erase(j);
9253 }
9254 else
9255 added_fns_[n] = added_fn;
9256 }
9257 }
9258 sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9259
9260 // Now walk the allegedly deleted functions; check if their
9261 // underlying symbols are deleted as well; otherwise, consider
9262 // that the function in question hasn't been deleted.
9263
9264 vector<string> to_delete;
9265 for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9266 i != deleted_fns_.end();
9267 ++i)
9268 if (second_->lookup_function_symbol(*i->second->get_symbol()))
9269 to_delete.push_back(i->first);
9270
9271 for (vector<string>::const_iterator i = to_delete.begin();
9272 i != to_delete.end();
9273 ++i)
9274 deleted_fns_.erase(*i);
9275
9276 // Do something similar for added functions.
9277
9278 to_delete.clear();
9279 for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9280 i != added_fns_.end();
9281 ++i)
9282 {
9283 if (first_->lookup_function_symbol(*i->second->get_symbol()))
9284 to_delete.push_back(i->first);
9285 else if (! i->second->get_symbol()->get_version().is_empty()
9286 && i->second->get_symbol()->get_version().is_default())
9287 // We are looking for a symbol that has a default version,
9288 // and which seems to be newly added. Let's see if the same
9289 // symbol with *no* version was already present in the
9290 // former corpus. If yes, then the symbol shouldn't be
9291 // considered as 'added'.
9292 {
9293 elf_symbol::version empty_version;
9294 if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
9295 empty_version))
9296 to_delete.push_back(i->first);
9297 }
9298 }
9299
9300 for (vector<string>::const_iterator i = to_delete.begin();
9301 i != to_delete.end();
9302 ++i)
9303 added_fns_.erase(*i);
9304 }
9305
9306 {
9307 edit_script& e = vars_edit_script_;
9308
9309 for (vector<deletion>::const_iterator it = e.deletions().begin();
9310 it != e.deletions().end();
9311 ++it)
9312 {
9313 unsigned i = it->index();
9314 ABG_ASSERT(i < first_->get_variables().size());
9315
9316 var_decl* deleted_var = first_->get_variables()[i];
9317 string n = deleted_var->get_id();
9318 ABG_ASSERT(!n.empty());
9319 ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
9320 deleted_vars_[n] = deleted_var;
9321 }
9322
9323 for (vector<insertion>::const_iterator it = e.insertions().begin();
9324 it != e.insertions().end();
9325 ++it)
9326 {
9327 for (vector<unsigned>::const_iterator iit =
9328 it->inserted_indexes().begin();
9329 iit != it->inserted_indexes().end();
9330 ++iit)
9331 {
9332 unsigned i = *iit;
9333 var_decl* added_var = second_->get_variables()[i];
9334 string n = added_var->get_id();
9335 ABG_ASSERT(!n.empty());
9336 {
9337 string_var_ptr_map::const_iterator k = added_vars_.find(n);
9338 if ( k != added_vars_.end())
9339 {
9340 ABG_ASSERT(is_member_decl(k->second)
9341 && get_member_is_static(k->second));
9342 continue;
9343 }
9344 }
9345 string_var_ptr_map::const_iterator j =
9346 deleted_vars_.find(n);
9347 if (j != deleted_vars_.end())
9348 {
9349 if (*j->second != *added_var)
9350 {
9351 var_decl_sptr f(j->second, noop_deleter());
9352 var_decl_sptr s(added_var, noop_deleter());
9353 changed_vars_map_[n] = compute_diff(f, s, ctxt);
9354 }
9355 deleted_vars_.erase(j);
9356 }
9357 else
9358 added_vars_[n] = added_var;
9359 }
9360 }
9361 sort_string_var_diff_sptr_map(changed_vars_map_,
9362 sorted_changed_vars_);
9363
9364 // Now walk the allegedly deleted variables; check if their
9365 // underlying symbols are deleted as well; otherwise consider
9366 // that the variable in question hasn't been deleted.
9367
9368 vector<string> to_delete;
9369 for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
9370 i != deleted_vars_.end();
9371 ++i)
9372 if (second_->lookup_variable_symbol(*i->second->get_symbol()))
9373 to_delete.push_back(i->first);
9374
9375 for (vector<string>::const_iterator i = to_delete.begin();
9376 i != to_delete.end();
9377 ++i)
9378 deleted_vars_.erase(*i);
9379
9380 // Do something similar for added variables.
9381
9382 to_delete.clear();
9383 for (string_var_ptr_map::const_iterator i = added_vars_.begin();
9384 i != added_vars_.end();
9385 ++i)
9386 if (first_->lookup_variable_symbol(*i->second->get_symbol()))
9387 to_delete.push_back(i->first);
9388 else if (! i->second->get_symbol()->get_version().is_empty()
9389 && i->second->get_symbol()->get_version().is_default())
9390 // We are looking for a symbol that has a default version,
9391 // and which seems to be newly added. Let's see if the same
9392 // symbol with *no* version was already present in the
9393 // former corpus. If yes, then the symbol shouldn't be
9394 // considered as 'added'.
9395 {
9396 elf_symbol::version empty_version;
9397 if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
9398 empty_version))
9399 to_delete.push_back(i->first);
9400 }
9401
9402 for (vector<string>::const_iterator i = to_delete.begin();
9403 i != to_delete.end();
9404 ++i)
9405 added_vars_.erase(*i);
9406 }
9407
9408 // Massage the edit script for added/removed function symbols that
9409 // were not referenced by any debug info and turn them into maps of
9410 // {symbol_name, symbol}.
9411 {
9412 edit_script& e = unrefed_fn_syms_edit_script_;
9413 for (vector<deletion>::const_iterator it = e.deletions().begin();
9414 it != e.deletions().end();
9415 ++it)
9416 {
9417 unsigned i = it->index();
9418 ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
9419 elf_symbol_sptr deleted_sym =
9420 first_->get_unreferenced_function_symbols()[i];
9421 if (!second_->lookup_function_symbol(*deleted_sym))
9422 deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
9423 }
9424
9425 for (vector<insertion>::const_iterator it = e.insertions().begin();
9426 it != e.insertions().end();
9427 ++it)
9428 {
9429 for (vector<unsigned>::const_iterator iit =
9430 it->inserted_indexes().begin();
9431 iit != it->inserted_indexes().end();
9432 ++iit)
9433 {
9434 unsigned i = *iit;
9435 ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
9436 elf_symbol_sptr added_sym =
9437 second_->get_unreferenced_function_symbols()[i];
9438 if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
9439 == deleted_unrefed_fn_syms_.end()))
9440 {
9441 if (!first_->lookup_function_symbol(*added_sym))
9442 {
9443 bool do_add = true;
9444 if (! added_sym->get_version().is_empty()
9445 && added_sym->get_version().is_default())
9446 {
9447 // So added_seem has a default version. If
9448 // the former corpus had a symbol with the
9449 // same name as added_sym but with *no*
9450 // version, then added_sym shouldn't be
9451 // considered as a newly added symbol.
9452 elf_symbol::version empty_version;
9453 if (first_->lookup_function_symbol(added_sym->get_name(),
9454 empty_version))
9455 do_add = false;
9456 }
9457
9458 if (do_add)
9459 added_unrefed_fn_syms_[added_sym->get_id_string()] =
9460 added_sym;
9461 }
9462 }
9463 else
9464 deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
9465 }
9466 }
9467 }
9468
9469 // Massage the edit script for added/removed variable symbols that
9470 // were not referenced by any debug info and turn them into maps of
9471 // {symbol_name, symbol}.
9472 {
9473 edit_script& e = unrefed_var_syms_edit_script_;
9474 for (vector<deletion>::const_iterator it = e.deletions().begin();
9475 it != e.deletions().end();
9476 ++it)
9477 {
9478 unsigned i = it->index();
9479 ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9480 elf_symbol_sptr deleted_sym =
9481 first_->get_unreferenced_variable_symbols()[i];
9482 if (!second_->lookup_variable_symbol(*deleted_sym))
9483 deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9484 }
9485
9486 for (vector<insertion>::const_iterator it = e.insertions().begin();
9487 it != e.insertions().end();
9488 ++it)
9489 {
9490 for (vector<unsigned>::const_iterator iit =
9491 it->inserted_indexes().begin();
9492 iit != it->inserted_indexes().end();
9493 ++iit)
9494 {
9495 unsigned i = *iit;
9496 ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9497 elf_symbol_sptr added_sym =
9498 second_->get_unreferenced_variable_symbols()[i];
9499 if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9500 == deleted_unrefed_var_syms_.end())
9501 {
9502 if (!first_->lookup_variable_symbol(*added_sym))
9503 {
9504 bool do_add = true;
9505 if (! added_sym->get_version().is_empty()
9506 && added_sym->get_version().is_default())
9507 {
9508 // So added_seem has a default version. If
9509 // the former corpus had a symbol with the
9510 // same name as added_sym but with *no*
9511 // version, then added_sym shouldn't be
9512 // considered as a newly added symbol.
9513 elf_symbol::version empty_version;
9514 if (first_->lookup_variable_symbol(added_sym->get_name(),
9515 empty_version))
9516 do_add = false;
9517 }
9518
9519 if (do_add)
9520 added_unrefed_var_syms_[added_sym->get_id_string()] =
9521 added_sym;
9522 }
9523 }
9524 else
9525 deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9526 }
9527 }
9528 }
9529
9530 // Handle the unreachable_types_edit_script_
9531 {
9532 edit_script& e = unreachable_types_edit_script_;
9533
9534 // Populate the map of deleted unreachable types from the
9535 // deletions of the edit script.
9536 for (vector<deletion>::const_iterator it = e.deletions().begin();
9537 it != e.deletions().end();
9538 ++it)
9539 {
9540 unsigned i = it->index();
9541 type_base_sptr t
9542 (first_->get_types_not_reachable_from_public_interfaces()[i]);
9543
9544 if (!is_user_defined_type(t))
9545 continue;
9546
9547 string repr = abigail::ir::get_pretty_representation(t, true);
9548 deleted_unreachable_types_[repr] = t;
9549 }
9550
9551 // Populate the map of added and change unreachable types from the
9552 // insertions of the edit script.
9553 for (vector<insertion>::const_iterator it = e.insertions().begin();
9554 it != e.insertions().end();
9555 ++it)
9556 {
9557 for (vector<unsigned>::const_iterator iit =
9558 it->inserted_indexes().begin();
9559 iit != it->inserted_indexes().end();
9560 ++iit)
9561 {
9562 unsigned i = *iit;
9563 type_base_sptr t
9564 (second_->get_types_not_reachable_from_public_interfaces()[i]);
9565
9566 if (!is_user_defined_type(t))
9567 continue;
9568
9569 string repr = abigail::ir::get_pretty_representation(t, true);
9570
9571 // Let's see if the inserted type we are looking at was
9572 // reported as deleted as well.
9573 //
9574 // If it's been deleted and a different version of it has
9575 // now been added, it means it's been *changed*. In that
9576 // case we'll compute the diff of that change and store it
9577 // in the map of changed unreachable types.
9578 //
9579 // Otherwise, it means the type's been added so we'll add
9580 // it to the set of added unreachable types.
9581
9582 string_type_base_sptr_map::const_iterator j =
9583 deleted_unreachable_types_.find(repr);
9584 if (j != deleted_unreachable_types_.end())
9585 {
9586 // So there was another type of the same pretty
9587 // representation which was reported as deleted.
9588 // Let's see if they are different or not ...
9589 decl_base_sptr old_type = is_decl(j->second);
9590 decl_base_sptr new_type = is_decl(t);
9591 if (old_type != new_type)
9592 {
9593 // The previously added type is different from this
9594 // one that is added. That means the initial type
9595 // was changed. Let's compute its diff and store it
9596 // as a changed type.
9597 diff_sptr d = compute_diff(old_type, new_type, ctxt);
9598 ABG_ASSERT(d->has_changes());
9599 changed_unreachable_types_[repr]= d;
9600 }
9601
9602 // In any case, the type was both deleted and added,
9603 // so we cannot have it marked as being deleted. So
9604 // let's remove it from the deleted types.
9605 deleted_unreachable_types_.erase(j);
9606 }
9607 else
9608 // The type wasn't previously reported as deleted, so
9609 // it's really added.
9610 added_unreachable_types_[repr] = t;
9611 }
9612 }
9613 }
9614}
9615
9616/// Test if a change reports about a given @ref function_decl that is
9617/// changed in a certain way is suppressed by a given suppression
9618/// specifiation
9619///
9620/// @param fn the @ref function_decl to consider.
9621///
9622/// @param suppr the suppression specification to consider.
9623///
9624/// @param k the kind of change that happened to @p fn.
9625///
9626/// @param ctxt the context of the current diff.
9627///
9628/// @return true iff the suppression specification @p suppr suppresses
9629/// change reports about function @p fn, if that function changes in
9630/// the way expressed by @p k.
9631static bool
9632function_is_suppressed(const function_decl* fn,
9633 const suppression_sptr suppr,
9635 const diff_context_sptr ctxt)
9636{
9638 if (!fn_suppr)
9639 return false;
9640 return fn_suppr->suppresses_function(fn, k, ctxt);
9641}
9642
9643/// Test if a change reports about a given @ref var_decl that is
9644/// changed in a certain way is suppressed by a given suppression
9645/// specifiation
9646///
9647/// @param fn the @ref var_decl to consider.
9648///
9649/// @param suppr the suppression specification to consider.
9650///
9651/// @param k the kind of change that happened to @p fn.
9652///
9653/// @param ctxt the context of the current diff.
9654///
9655/// @return true iff the suppression specification @p suppr suppresses
9656/// change reports about variable @p fn, if that variable changes in
9657/// the way expressed by @p k.
9658static bool
9659variable_is_suppressed(const var_decl* var,
9660 const suppression_sptr suppr,
9662 const diff_context_sptr ctxt)
9663{
9665 if (!var_suppr)
9666 return false;
9667 return var_suppr->suppresses_variable(var, k, ctxt);
9668}
9669
9670/// Apply suppression specifications for this corpus diff to the set
9671/// of added/removed functions/variables, as well as to types not
9672/// reachable from global functions/variables.
9673void
9675{
9676 diff_context_sptr ctxt = get_context();
9677
9678 const suppressions_type& suppressions = ctxt->suppressions();
9679 for (suppressions_type::const_iterator i = suppressions.begin();
9680 i != suppressions.end();
9681 ++i)
9682 {
9683 // Added/Deleted functions.
9685 {
9686 // Added functions
9687 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9688 e != added_fns_.end();
9689 ++e)
9690 if (function_is_suppressed(e->second, fn_suppr,
9692 ctxt))
9693 suppressed_added_fns_[e->first] = e->second;
9694
9695 // Deleted functions.
9696 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9697 e != deleted_fns_.end();
9698 ++e)
9699 if (function_is_suppressed(e->second, fn_suppr,
9701 ctxt))
9702 suppressed_deleted_fns_[e->first] = e->second;
9703
9704 // Added function symbols not referenced by any debug info
9705 for (string_elf_symbol_map::const_iterator e =
9706 added_unrefed_fn_syms_.begin();
9707 e != added_unrefed_fn_syms_.end();
9708 ++e)
9709 if (fn_suppr->suppresses_function_symbol(e->second,
9711 ctxt))
9712 suppressed_added_unrefed_fn_syms_[e->first] = e->second;
9713
9714 // Removed function symbols not referenced by any debug info
9715 for (string_elf_symbol_map::const_iterator e =
9716 deleted_unrefed_fn_syms_.begin();
9717 e != deleted_unrefed_fn_syms_.end();
9718 ++e)
9719 if (fn_suppr->suppresses_function_symbol(e->second,
9721 ctxt))
9722 suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
9723 }
9724 // Added/Delete virtual member functions changes that might be
9725 // suppressed by a type_suppression that matches the enclosing
9726 // class of the virtual member function.
9727 else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
9728 {
9729 // Added virtual functions
9730 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
9731 e != added_fns_.end();
9732 ++e)
9733 if (is_member_function(e->second)
9734 && get_member_function_is_virtual(e->second))
9735 {
9736 function_decl *f = e->second;
9737 class_decl_sptr c =
9738 is_class_type(is_method_type(f->get_type())->get_class_type());
9739 ABG_ASSERT(c);
9740 if (type_suppr->suppresses_type(c, ctxt))
9741 suppressed_added_fns_[e->first] = e->second;
9742 }
9743 // Deleted virtual functions
9744 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
9745 e != deleted_fns_.end();
9746 ++e)
9747 if (is_member_function(e->second)
9748 && get_member_function_is_virtual(e->second))
9749 {
9750 function_decl *f = e->second;
9751 class_decl_sptr c =
9752 is_class_type(is_method_type(f->get_type())->get_class_type());
9753 ABG_ASSERT(c);
9754 if (type_suppr->suppresses_type(c, ctxt))
9755 suppressed_deleted_fns_[e->first] = e->second;
9756 }
9757
9758 // Apply this type suppression to deleted types
9759 // non-reachable from a public interface.
9760 for (string_type_base_sptr_map::const_iterator e =
9761 deleted_unreachable_types_.begin();
9762 e != deleted_unreachable_types_.end();
9763 ++e)
9764 if (type_suppr->suppresses_type(e->second, ctxt))
9765 suppressed_deleted_unreachable_types_[e->first] = e->second;
9766
9767 // Apply this type suppression to added types
9768 // non-reachable from a public interface.
9769 for (string_type_base_sptr_map::const_iterator e =
9770 added_unreachable_types_.begin();
9771 e != added_unreachable_types_.end();
9772 ++e)
9773 if (type_suppr->suppresses_type(e->second, ctxt))
9774 suppressed_added_unreachable_types_[e->first] = e->second;
9775 }
9776 // Added/Deleted variables
9777 else if (variable_suppression_sptr var_suppr =
9779 {
9780 // Added variables
9781 for (string_var_ptr_map::const_iterator e = added_vars_.begin();
9782 e != added_vars_.end();
9783 ++e)
9784 if (variable_is_suppressed(e->second, var_suppr,
9786 ctxt))
9787 suppressed_added_vars_[e->first] = e->second;
9788
9789 //Deleted variables
9790 for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
9791 e != deleted_vars_.end();
9792 ++e)
9793 if (variable_is_suppressed(e->second, var_suppr,
9795 ctxt))
9796 suppressed_deleted_vars_[e->first] = e->second;
9797
9798 // Added variable symbols not referenced by any debug info
9799 for (string_elf_symbol_map::const_iterator e =
9800 added_unrefed_var_syms_.begin();
9801 e != added_unrefed_var_syms_.end();
9802 ++e)
9803 if (var_suppr->suppresses_variable_symbol(e->second,
9805 ctxt))
9806 suppressed_added_unrefed_var_syms_[e->first] = e->second;
9807
9808 // Removed variable symbols not referenced by any debug info
9809 for (string_elf_symbol_map::const_iterator e =
9810 deleted_unrefed_var_syms_.begin();
9811 e != deleted_unrefed_var_syms_.end();
9812 ++e)
9813 if (var_suppr->suppresses_variable_symbol(e->second,
9815 ctxt))
9816 suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
9817 }
9818 }
9819}
9820
9821/// Test if the change reports for a given deleted function have
9822/// been deleted.
9823///
9824/// @param fn the function to consider.
9825///
9826/// @return true iff the change reports for a give given deleted
9827/// function have been deleted.
9828bool
9830{
9831 if (!fn)
9832 return false;
9833
9834 string_function_ptr_map::const_iterator i =
9835 suppressed_deleted_fns_.find(fn->get_id());
9836
9837 return (i != suppressed_deleted_fns_.end());
9838}
9839
9840/// Test if an added type that is unreachable from public interface
9841/// has been suppressed by a suppression specification.
9842///
9843/// @param t the added unreachable type to be considered.
9844///
9845/// @return true iff @p t has been suppressed by a suppression
9846/// specification.
9847bool
9849{
9850 if (!t)
9851 return false;
9852
9853 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
9854 string_type_base_sptr_map::const_iterator i =
9855 suppressed_added_unreachable_types_.find(repr);
9856 if (i == suppressed_added_unreachable_types_.end())
9857 return false;
9858
9859 return true;
9860}
9861
9862/// Test if a deleted type that is unreachable from public interface
9863/// has been suppressed by a suppression specification.
9864///
9865/// @param t the deleted unreachable type to be considered.
9866///
9867/// @return true iff @p t has been suppressed by a suppression
9868/// specification.
9869bool
9871{
9872 if (!t)
9873 return false;
9874
9875 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/true);
9876 string_type_base_sptr_map::const_iterator i =
9877 suppressed_deleted_unreachable_types_.find(repr);
9878 if (i == suppressed_deleted_unreachable_types_.end())
9879 return false;
9880
9881 return true;
9882}
9883
9884/// Test if the change reports for a give given added function has
9885/// been deleted.
9886///
9887/// @param fn the function to consider.
9888///
9889/// @return true iff the change reports for a give given added
9890/// function has been deleted.
9891bool
9893{
9894 if (!fn)
9895 return false;
9896
9897 string_function_ptr_map::const_iterator i =
9898 suppressed_added_fns_.find(fn->get_id());
9899
9900 return (i != suppressed_added_fns_.end());
9901}
9902
9903/// Test if the change reports for a give given deleted variable has
9904/// been deleted.
9905///
9906/// @param var the variable to consider.
9907///
9908/// @return true iff the change reports for a give given deleted
9909/// variable has been deleted.
9910bool
9912{
9913 if (!var)
9914 return false;
9915
9916 string_var_ptr_map::const_iterator i =
9917 suppressed_deleted_vars_.find(var->get_id());
9918
9919 return (i != suppressed_deleted_vars_.end());
9920}
9921
9922/// Test if the change reports for a given added variable have been
9923/// suppressed.
9924///
9925/// @param var the variable to consider.
9926///
9927/// @return true iff the change reports for a given deleted
9928/// variable has been deleted.
9929bool
9931{
9932 if (!var)
9933 return false;
9934
9935 string_var_ptr_map::const_iterator i =
9936 suppressed_added_vars_.find(var->get_id());
9937
9938 return (i != suppressed_added_vars_.end());
9939}
9940
9941/// Test if the change reports for a given deleted function symbol
9942/// (that is not referenced by any debug info) has been suppressed.
9943///
9944/// @param var the function to consider.
9945///
9946/// @return true iff the change reports for a given deleted function
9947/// symbol has been suppressed.
9948bool
9950{
9951 if (!s)
9952 return false;
9953
9954 string_elf_symbol_map::const_iterator i =
9955 suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
9956
9957 return (i != suppressed_deleted_unrefed_fn_syms_.end());
9958}
9959
9960/// Test if the change reports for a given added function symbol
9961/// (that is not referenced by any debug info) has been suppressed.
9962///
9963/// @param var the function to consider.
9964///
9965/// @return true iff the change reports for a given added function
9966/// symbol has been suppressed.
9967bool
9969{
9970 if (!s)
9971 return false;
9972
9973 string_elf_symbol_map::const_iterator i =
9974 suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
9975
9976 return (i != suppressed_added_unrefed_fn_syms_.end());
9977}
9978
9979/// Test if the change reports for a given deleted variable symbol
9980/// (that is not referenced by any debug info) has been suppressed.
9981///
9982/// @param var the variable to consider.
9983///
9984/// @return true iff the change reports for a given deleted variable
9985/// symbol has been suppressed.
9986bool
9988{
9989 if (!s)
9990 return false;
9991
9992 string_elf_symbol_map::const_iterator i =
9993 suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
9994
9995 return (i != suppressed_deleted_unrefed_var_syms_.end());
9996}
9997
9998/// Test if the change reports for a given added variable symbol
9999/// (that is not referenced by any debug info) has been suppressed.
10000///
10001/// @param var the variable to consider.
10002///
10003/// @return true iff the change reports for a given added variable
10004/// symbol has been suppressed.
10005bool
10007{
10008 if (!s)
10009 return false;
10010
10011 string_elf_symbol_map::const_iterator i =
10012 suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10013
10014 return (i != suppressed_added_unrefed_var_syms_.end());
10015}
10016
10017#ifdef do_count_diff_map_changes
10018#undef do_count_diff_map_changes
10019#endif
10020#define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10021 { \
10022 string_diff_ptr_map::const_iterator i; \
10023 for (i = diff_map.begin(); \
10024 i != diff_map.end(); \
10025 ++i) \
10026 { \
10027 if (const var_diff* d = is_var_diff(i->second)) \
10028 if (is_data_member(d->first_var())) \
10029 continue; \
10030 \
10031 if (i->second->has_local_changes()) \
10032 ++n_changes; \
10033 if (!i->second->get_canonical_diff()->to_be_reported()) \
10034 ++n_filtered; \
10035 } \
10036 }
10037
10038/// Count the number of leaf changes as well as the number of the
10039/// changes that have been filtered out.
10040///
10041/// @param num_changes out parameter. This is set to the total number
10042/// of leaf changes.
10043///
10044/// @param num_filtered out parameter. This is set to the number of
10045/// leaf changes that have been filtered out.
10046void
10047corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10048{
10049 count_leaf_type_changes(num_changes, num_filtered);
10050
10051 // Now count the non-type changes.
10052 do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10053 num_changes, num_filtered);
10054 do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10055 num_changes, num_filtered);
10056}
10057
10058/// Count the number of leaf *type* changes as well as the number of
10059/// the leaf type changes that have been filtered out.
10060///
10061/// @param num_changes out parameter. This is set to the total number
10062/// of leaf type changes.
10063///
10064/// @param num_filtered out parameter. This is set to the number of
10065/// leaf type changes that have been filtered out.
10066void
10068 size_t &num_filtered)
10069{
10070 do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10071 num_changes, num_filtered);
10072 do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10073 num_changes, num_filtered);
10074 do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10075 num_changes, num_filtered);
10076 do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10077 num_changes, num_filtered);
10078 do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10079 num_changes, num_filtered);
10080 do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10081 num_changes, num_filtered);
10082 do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10083 num_changes, num_filtered);
10084 do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10085 num_changes, num_filtered);
10086 do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10087 num_changes, num_filtered);
10088}
10089
10090/// Count the number of types not reachable from the interface (i.e,
10091/// not reachable from global functions or variables).
10092///
10093/// @param num_added this is set to the number of added types not
10094/// reachable from the interface.
10095///
10096/// @param num_deleted this is set to the number of deleted types not
10097/// reachable from the interface.
10098///
10099/// @param num_changed this is set to the number of changed types not
10100/// reachable from the interface.
10101///
10102/// @param num_filtered_added this is set to the number of added types
10103/// not reachable from the interface and that have been filtered out
10104/// by suppression specifications.
10105///
10106/// @param num_filtered_deleted this is set to the number of deleted
10107/// types not reachable from the interface and that have been filtered
10108/// out by suppression specifications.
10109///
10110/// @param num_filtered_changed this is set to the number of changed
10111/// types not reachable from the interface and that have been filtered
10112/// out by suppression specifications.
10113void
10115 size_t &num_deleted,
10116 size_t &num_changed,
10117 size_t &num_filtered_added,
10118 size_t &num_filtered_deleted,
10119 size_t &num_filtered_changed)
10120{
10121 num_added = added_unreachable_types_.size();
10122 num_deleted = deleted_unreachable_types_.size();
10123 num_changed = changed_unreachable_types_.size();
10124 num_filtered_added = suppressed_added_unreachable_types_.size();
10125 num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10126
10127 for (vector<diff_sptr>::const_iterator i =
10130 ++i)
10131 if (!(*i)->to_be_reported())
10132 ++num_filtered_changed;
10133}
10134
10135/// Get the sorted vector of diff nodes representing changed
10136/// unreachable types.
10137///
10138/// Upon the first invocation of this method, if the vector is empty,
10139/// this function gets the diff nodes representing changed
10140/// unreachable, sort them, and return the sorted vector.
10141///
10142/// @return the sorted vector of diff nodes representing changed
10143/// unreachable types.
10144const vector<diff_sptr>&
10146{
10147if (changed_unreachable_types_sorted_.empty())
10148 if (!changed_unreachable_types_.empty())
10149 sort_string_diff_sptr_map(changed_unreachable_types_,
10150 changed_unreachable_types_sorted_);
10151
10152 return changed_unreachable_types_sorted_;
10153}
10154
10155/// Compute the diff stats.
10156///
10157/// To know the number of functions that got filtered out, this
10158/// function applies the categorizing filters to the diff sub-trees of
10159/// each function changes diff, prior to calculating the stats.
10160///
10161/// @param num_removed the number of removed functions.
10162///
10163/// @param num_added the number of added functions.
10164///
10165/// @param num_changed the number of changed functions.
10166///
10167/// @param num_filtered_out the number of changed functions that are
10168/// got filtered out from the report
10169void
10171{
10172 stat.num_func_removed(deleted_fns_.size());
10173 stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
10174 stat.num_func_added(added_fns_.size());
10175 stat.num_added_func_filtered_out(suppressed_added_fns_.size());
10176 stat.num_func_changed(changed_fns_map_.size());
10177
10178 stat.num_vars_removed(deleted_vars_.size());
10179 stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
10180 stat.num_vars_added(added_vars_.size());
10181 stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
10182 stat.num_vars_changed(changed_vars_map_.size());
10183
10184 diff_context_sptr ctxt = get_context();
10185
10187 if (ctxt->perform_change_categorization())
10188 {
10189 if (get_context()->do_log())
10190 {
10191 std::cerr << "in apply_filters_and_compute_diff_stats:"
10192 << "applying filters to "
10193 << changed_fns_.size()
10194 << " changed fns ...\n";
10195 t.start();
10196 }
10197 // Walk the changed function diff nodes to apply the categorization
10198 // filters.
10200 for (function_decl_diff_sptrs_type::const_iterator i =
10201 changed_fns_.begin();
10202 i != changed_fns_.end();
10203 ++i)
10204 {
10205 diff_sptr diff = *i;
10206 ctxt->maybe_apply_filters(diff);
10207 }
10208
10209 if (get_context()->do_log())
10210 {
10211 t.stop();
10212 std::cerr << "in apply_filters_and_compute_diff_stats:"
10213 << "filters to changed fn applied!:" << t << "\n";
10214
10215 std::cerr << "in apply_filters_and_compute_diff_stats:"
10216 << "applying filters to "
10217 << sorted_changed_vars_.size()
10218 << " changed vars ...\n";
10219 t.start();
10220 }
10221
10222 // Walk the changed variable diff nodes to apply the categorization
10223 // filters.
10224 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10225 i != sorted_changed_vars_.end();
10226 ++i)
10227 {
10228 diff_sptr diff = *i;
10229 ctxt->maybe_apply_filters(diff);
10230 }
10231
10232 if (get_context()->do_log())
10233 {
10234 t.stop();
10235 std::cerr << "in apply_filters_and_compute_diff_stats:"
10236 << "filters to changed vars applied!:" << t << "\n";
10237
10238 std::cerr << "in apply_filters_and_compute_diff_stats:"
10239 << "applying filters to unreachable types ...\n";
10240 t.start();
10241 }
10242
10243 // walk the changed unreachable types to apply categorization
10244 // filters
10245 for (diff_sptrs_type::const_iterator i =
10248 ++i)
10249 {
10250 diff_sptr diff = *i;
10251 ctxt->maybe_apply_filters(diff);
10252 }
10253
10254 if (get_context()->do_log())
10255 {
10256 t.stop();
10257 std::cerr << "in apply_filters_and_compute_diff_stats:"
10258 << "filters to unreachable types applied!:" << t << "\n";
10259
10260 std::cerr << "in apply_filters_and_compute_diff_stats:"
10261 << "categorizing redundant changed sub nodes ...\n";
10262 t.start();
10263 }
10264
10265 categorize_redundant_changed_sub_nodes();
10266
10267 if (get_context()->do_log())
10268 {
10269 t.stop();
10270 std::cerr << "in apply_filters_and_compute_diff_stats:"
10271 << "redundant changed sub nodes categorized!:" << t << "\n";
10272
10273 std::cerr << "in apply_filters_and_compute_diff_stats:"
10274 << "count changed fns ...\n";
10275 t.start();
10276 }
10277 }
10278
10279 // Walk the changed function diff nodes to count the number of
10280 // filtered-out functions and the number of functions with virtual
10281 // offset changes.
10282 for (function_decl_diff_sptrs_type::const_iterator i =
10283 changed_fns_.begin();
10284 i != changed_fns_.end();
10285 ++i)
10286 {
10287 if ((*i)->is_filtered_out())
10288 {
10290 (stat.num_changed_func_filtered_out() + 1);
10291
10292 if ((*i)->has_local_changes())
10295 }
10296 else
10297 {
10298 if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
10301 }
10302
10303 if ((*i)->has_local_changes())
10305 (stat.num_leaf_func_changes() + 1);
10306 }
10307
10308 if (get_context()->do_log())
10309 {
10310 t.stop();
10311 std::cerr << "in apply_filters_and_compute_diff_stats:"
10312 << "changed fn counted!:" << t << "\n";
10313
10314 std::cerr << "in apply_filters_and_compute_diff_stats:"
10315 << "count changed vars ...\n";
10316 t.start();
10317 }
10318
10319 // Walk the changed variables diff nodes to count the number of
10320 // filtered-out variables.
10321 for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
10322 i != sorted_changed_vars_.end();
10323 ++i)
10324 {
10325 if ((*i)->is_filtered_out())
10326 {
10328 (stat.num_changed_vars_filtered_out() + 1);
10329
10330 if ((*i)->has_local_changes())
10333 }
10334 if ((*i)->has_local_changes())
10336 (stat.num_leaf_var_changes() + 1);
10337 }
10338
10339 if (get_context()->do_log())
10340 {
10341 t.stop();
10342 std::cerr << "in apply_filters_and_compute_diff_stats:"
10343 << "changed vars counted!:" << t << "\n";
10344
10345 std::cerr << "in apply_filters_and_compute_diff_stats:"
10346 << "count leaf changed types ...\n";
10347 t.start();
10348 }
10349
10350 stat.num_func_syms_added(added_unrefed_fn_syms_.size());
10351 stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
10352 stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
10353 stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
10354 stat.num_var_syms_added(added_unrefed_var_syms_.size());
10355 stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
10356 stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
10357 stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
10358
10359 // Walk the general leaf type diff nodes to count them
10360 {
10361 size_t num_type_changes = 0, num_type_filtered = 0;
10362 count_leaf_type_changes(num_type_changes, num_type_filtered);
10363
10364 stat.num_leaf_type_changes(num_type_changes);
10365 stat.num_leaf_type_changes_filtered_out(num_type_filtered);
10366 }
10367
10368 if (get_context()->do_log())
10369 {
10370 t.stop();
10371 std::cerr << "in apply_filters_and_compute_diff_stats:"
10372 << "changed leaf types counted!:" << t << "\n";
10373
10374 std::cerr << "in apply_filters_and_compute_diff_stats:"
10375 << "count leaf changed artefacts ...\n";
10376 t.start();
10377 }
10378
10379 // Walk the general leaf artefacts diff nodes to count them
10380 {
10381 size_t num_changes = 0, num_filtered = 0;
10382 count_leaf_changes(num_changes, num_filtered);
10383
10384 stat.num_leaf_changes(num_changes);
10385 stat.num_leaf_changes_filtered_out(num_filtered);
10386 }
10387
10388 if (get_context()->do_log())
10389 {
10390 t.stop();
10391 std::cerr << "in apply_filters_and_compute_diff_stats:"
10392 << "changed leaf artefacts counted!:" << t << "\n";
10393
10394 std::cerr << "in apply_filters_and_compute_diff_stats:"
10395 << "count unreachable types ...\n";
10396 t.start();
10397 }
10398
10399 // Walk the unreachable types to count them
10400 {
10401 size_t num_added_unreachable_types = 0,
10402 num_changed_unreachable_types = 0,
10403 num_deleted_unreachable_types = 0,
10404 num_added_unreachable_types_filtered = 0,
10405 num_changed_unreachable_types_filtered = 0,
10406 num_deleted_unreachable_types_filtered = 0;
10407
10408 count_unreachable_types(num_added_unreachable_types,
10409 num_deleted_unreachable_types,
10410 num_changed_unreachable_types,
10411 num_added_unreachable_types_filtered,
10412 num_deleted_unreachable_types_filtered,
10413 num_changed_unreachable_types_filtered);
10414
10415 if (get_context()->do_log())
10416 {
10417 t.stop();
10418 std::cerr << "in apply_filters_and_compute_diff_stats:"
10419 << "unreachable types counted!:" << t << "\n";
10420 }
10421
10422 stat.num_added_unreachable_types(num_added_unreachable_types);
10423 stat.num_removed_unreachable_types(num_deleted_unreachable_types);
10424 stat.num_changed_unreachable_types(num_changed_unreachable_types);
10426 (num_added_unreachable_types_filtered);
10428 (num_deleted_unreachable_types_filtered);
10430 (num_changed_unreachable_types_filtered);
10431 }
10432}
10433
10434/// Emit the summary of the functions & variables that got
10435/// removed/changed/added.
10436///
10437/// TODO: This should be handled by the reporters, just like what is
10438/// done for reporter_base::diff_to_be_reported.
10439///
10440/// @param out the output stream to emit the stats to.
10441///
10442/// @param indent the indentation string to use in the summary.
10443void
10445 ostream& out,
10446 const string& indent)
10447{
10448 /// Report added/removed/changed functions.
10449 size_t net_num_leaf_changes =
10451 s.net_num_func_added() +
10454 s.net_num_vars_added() +
10461
10462 if (!sonames_equal_)
10463 out << indent << "ELF SONAME changed\n";
10464
10465 if (!architectures_equal_)
10466 out << indent << "ELF architecture changed\n";
10467
10468 diff_context_sptr ctxt = get_context();
10469
10470 if (ctxt->show_leaf_changes_only())
10471 {
10472 out << "Leaf changes summary: ";
10473 out << net_num_leaf_changes << " artifact";
10474 if (net_num_leaf_changes > 1)
10475 out << "s";
10476 out << " changed";
10477
10478 if (size_t num_filtered = s.num_leaf_changes_filtered_out())
10479 out << " (" << num_filtered << " filtered out)";
10480 out << "\n";
10481
10482 out << indent << "Changed leaf types summary: "
10485 out << " (" << s.num_leaf_type_changes_filtered_out()
10486 << " filtered out)";
10487 out << " leaf type";
10488 if (s.num_leaf_type_changes() > 1)
10489 out << "s";
10490 out << " changed\n";
10491
10492 // function changes summary
10493 out << indent << "Removed/Changed/Added functions summary: ";
10494 out << s.net_num_func_removed() << " Removed";
10496 out << " ("
10498 << " filtered out)";
10499 out << ", ";
10500
10501 out << s.net_num_leaf_func_changes() << " Changed";
10503 out << " ("
10505 << " filtered out)";
10506 out << ", ";
10507
10508 out << s.net_num_func_added()<< " Added ";
10509 if (s.net_num_func_added() <= 1)
10510 out << "function";
10511 else
10512 out << "functions";
10514 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10515 out << "\n";
10516
10517 // variables changes summary
10518 out << indent << "Removed/Changed/Added variables summary: ";
10519 out << s.net_num_vars_removed() << " Removed";
10521 out << " (" << s.num_removed_vars_filtered_out()
10522 << " filtered out)";
10523 out << ", ";
10524
10525 out << s.net_num_leaf_var_changes() << " Changed";
10527 out << " ("
10529 << " filtered out)";
10530 out << ", ";
10531
10532 out << s.net_num_vars_added() << " Added ";
10533 if (s.net_num_vars_added() <= 1)
10534 out << "variable";
10535 else
10536 out << "variables";
10538 out << " (" << s.num_added_vars_filtered_out()
10539 << " filtered out)";
10540 out << "\n";
10541 }
10542 else // if (ctxt->show_leaf_changes_only())
10543 {
10544 size_t total_nb_function_changes = s.num_func_removed()
10545 + s.num_func_changed() + s.num_func_added();
10546
10547 // function changes summary
10548 out << indent << "Functions changes summary: ";
10549 out << s.net_num_func_removed() << " Removed";
10551 out << " ("
10553 << " filtered out)";
10554 out << ", ";
10555
10556 out << s.net_num_func_changed() << " Changed";
10558 out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
10559 out << ", ";
10560
10561 out << s.net_num_func_added() << " Added";
10563 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10564 if (total_nb_function_changes <= 1)
10565 out << " function";
10566 else
10567 out << " functions";
10568 out << "\n";
10569
10570 // variables changes summary
10571 size_t total_nb_variable_changes = s.num_vars_removed()
10572 + s.num_vars_changed() + s.num_vars_added();
10573
10574 out << indent << "Variables changes summary: ";
10575 out << s.net_num_vars_removed() << " Removed";
10577 out << " (" << s.num_removed_vars_filtered_out()
10578 << " filtered out)";
10579 out << ", ";
10580
10581 out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
10583 out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
10584 out << ", ";
10585
10586 out << s.net_num_vars_added() << " Added";
10588 out << " (" << s.num_added_vars_filtered_out()
10589 << " filtered out)";
10590 if (total_nb_variable_changes <= 1)
10591 out << " variable";
10592 else
10593 out << " variables";
10594 out << "\n";
10595 }
10596
10597 // Show statistics about types not reachable from global
10598 // functions/variables.
10599 if (ctxt->show_unreachable_types())
10600 {
10601 size_t total_nb_unreachable_type_changes =
10605
10606 // Show summary of unreachable types
10607 out << indent << "Unreachable types summary: "
10609 << " removed";
10612 << " filtered out)";
10613 out << ", ";
10614
10616 << " changed";
10619 << " filtered out)";
10620 out << ", ";
10621
10623 << " added";
10626 << " filtered out)";
10627 if (total_nb_unreachable_type_changes <= 1)
10628 out << " type";
10629 else
10630 out << " types";
10631 out << "\n";
10632 }
10633
10634 if (ctxt->show_symbols_unreferenced_by_debug_info()
10635 && (s.num_func_syms_removed()
10636 || s.num_func_syms_added()
10638 || s.num_var_syms_added()))
10639 {
10640 // function symbols changes summary.
10641
10642 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10643 && s.num_func_syms_removed() == 0
10644 && s.num_func_syms_added() != 0)
10645 // If the only unreferenced function symbol change is function
10646 // syms that got added, but we were forbidden to show function
10647 // syms being added, do nothing.
10648 ;
10649 else
10650 {
10651 out << indent
10652 << "Function symbols changes summary: "
10653 << s.net_num_removed_func_syms() << " Removed";
10655 out << " (" << s.num_removed_func_syms_filtered_out()
10656 << " filtered out)";
10657 out << ", ";
10658 out << s.net_num_added_func_syms() << " Added";
10660 out << " (" << s.num_added_func_syms_filtered_out()
10661 << " filtered out)";
10662 out << " function symbol";
10664 out << "s";
10665 out << " not referenced by debug info\n";
10666 }
10667
10668 // variable symbol changes summary.
10669
10670 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10671 && s.num_var_syms_removed() == 0
10672 && s.num_var_syms_added() != 0)
10673 // If the only unreferenced variable symbol change is variable
10674 // syms that got added, but we were forbidden to show variable
10675 // syms being added, do nothing.
10676 ;
10677 else
10678 {
10679 out << indent
10680 << "Variable symbols changes summary: "
10681 << s.net_num_removed_var_syms() << " Removed";
10683 out << " (" << s.num_removed_var_syms_filtered_out()
10684 << " filtered out)";
10685 out << ", ";
10686 out << s.net_num_added_var_syms() << " Added";
10688 out << " (" << s.num_added_var_syms_filtered_out()
10689 << " filtered out)";
10690 out << " variable symbol";
10691 if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
10692 out << "s";
10693 out << " not referenced by debug info\n";
10694 }
10695 }
10696}
10697
10698/// Walk the changed functions and variables diff nodes to categorize
10699/// redundant nodes.
10700void
10702{
10704
10705 diff_context_sptr ctxt = get_context();
10706
10707 ctxt->forget_visited_diffs();
10708 for (function_decl_diff_sptrs_type::const_iterator i =
10709 changed_fns_.begin();
10710 i!= changed_fns_.end();
10711 ++i)
10712 {
10713 diff = *i;
10715 }
10716
10717 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10718 i!= sorted_changed_vars_.end();
10719 ++i)
10720 {
10721 diff_sptr diff = *i;
10723 }
10724
10725 for (diff_sptrs_type::const_iterator i =
10728 ++i)
10729 {
10730 diff_sptr diff = *i;
10732 }
10733}
10734
10735/// Walk the changed functions and variables diff nodes and clear the
10736/// redundancy categorization they might carry.
10737void
10739{
10741 for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
10742 i!= changed_fns_.end();
10743 ++i)
10744 {
10745 diff = *i;
10747 }
10748
10749 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10750 i!= sorted_changed_vars_.end();
10751 ++i)
10752 {
10753 diff = *i;
10755 }
10756}
10757
10758/// If the user asked to dump the diff tree node (for changed
10759/// variables and functions) on the error output stream, then just do
10760/// that.
10761///
10762/// This function is used for debugging purposes.
10763void
10765{
10766 diff_context_sptr ctxt = get_context();
10767
10768 if (!ctxt->dump_diff_tree()
10769 || ctxt->error_output_stream() == 0)
10770 return;
10771
10772 if (!changed_fns_.empty())
10773 {
10774 *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
10775 for (function_decl_diff_sptrs_type::const_iterator i =
10776 changed_fns_.begin();
10777 i != changed_fns_.end();
10778 ++i)
10779 {
10780 diff_sptr d = *i;
10781 print_diff_tree(d, *ctxt->error_output_stream());
10782 }
10783 }
10784
10785 if (!sorted_changed_vars_.empty())
10786 {
10787 *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
10788 for (var_diff_sptrs_type::const_iterator i =
10789 sorted_changed_vars_.begin();
10790 i != sorted_changed_vars_.end();
10791 ++i)
10792 {
10793 diff_sptr d = *i;
10794 print_diff_tree(d, *ctxt->error_output_stream());
10795 }
10796 }
10797
10798 if (!changed_unreachable_types_sorted().empty())
10799 {
10800 *ctxt->error_output_stream() << "\nchanged unreachable "
10801 "types diff tree: \n\n";
10802 for (vector<diff_sptr>::const_iterator i =
10805 ++i)
10806 {
10807 diff_sptr d = *i;
10808 print_diff_tree(d, *ctxt->error_output_stream());
10809 }
10810 }
10811}
10812
10813/// Populate the vector of children node of the @ref corpus_diff type.
10814///
10815/// The children node can then later be retrieved using
10816/// corpus_diff::children_node().
10817void
10819{
10820 for (function_decl_diff_sptrs_type::const_iterator i =
10821 changed_functions_sorted().begin();
10822 i != changed_functions_sorted().end();
10823 ++i)
10824 if (diff_sptr d = *i)
10826}
10827
10828/// Constructor for @ref corpus_diff.
10829///
10830/// @param first the first corpus of the diff.
10831///
10832/// @param second the second corpus of the diff.
10833///
10834/// @param ctxt the diff context to use. Note that this context
10835/// object must stay alive at least during the life time of the
10836/// current instance of @ref corpus_diff. Otherwise memory corruption
10837/// issues occur.
10839 corpus_sptr second,
10840 diff_context_sptr ctxt)
10841 : priv_(new priv(first, second, ctxt))
10842{}
10843
10844corpus_diff::~corpus_diff() = default;
10845
10846/// Finish building the current instance of @ref corpus_diff.
10847void
10849{
10850 if (priv_->finished_)
10851 return;
10853 priv_->finished_ = true;
10854}
10855
10856/// Test if logging was requested.
10857///
10858/// @return true iff logging was requested.
10859bool
10861{return context()->do_log();}
10862
10863/// Request logging, or not.
10864///
10865/// @param f true iff logging is requested.
10866void
10868{context()->do_log(f);}
10869
10870/// @return the first corpus of the diff.
10871corpus_sptr
10873{return priv_->first_;}
10874
10875/// @return the second corpus of the diff.
10876corpus_sptr
10878{return priv_->second_;}
10879
10880/// @return the children nodes of the current instance of corpus_diff.
10881const vector<diff*>&
10883{return priv_->children_;}
10884
10885/// Append a new child node to the vector of children nodes for the
10886/// current instance of @ref corpus_diff node.
10887///
10888/// Note that the vector of children nodes for the current instance of
10889/// @ref corpus_diff node must remain sorted, using
10890/// diff_less_than_functor.
10891///
10892/// @param d the new child node. Note that the life time of the
10893/// object held by @p d will thus equal the life time of the current
10894/// instance of @ref corpus_diff.
10895void
10897{
10898 ABG_ASSERT(d);
10899
10900 diff_less_than_functor is_less_than;
10901 bool inserted = false;
10902 for (vector<diff*>::iterator i = priv_->children_.begin();
10903 i != priv_->children_.end();
10904 ++i)
10905 // Look for the point where to insert the diff child node.
10906 if (!is_less_than(d.get(), *i))
10907 {
10908 context()->keep_diff_alive(d);
10909 priv_->children_.insert(i, d.get());
10910 // As we have just inserted 'd' into the vector, the iterator
10911 // 'i' is invalidated. We must *NOT* use it anymore.
10912 inserted = true;
10913 break;
10914 }
10915
10916 if (!inserted)
10917 {
10918 context()->keep_diff_alive(d);
10919 // We didn't insert anything to the vector, presumably b/c it was
10920 // empty or had one element that was "less than" 'd'. We can thus
10921 // just append 'd' to the end of the vector.
10922 priv_->children_.push_back(d.get());
10923 }
10924}
10925
10926/// @return the bare edit script of the functions changed as recorded
10927/// by the diff.
10930{return priv_->fns_edit_script_;}
10931
10932/// @return the bare edit script of the variables changed as recorded
10933/// by the diff.
10936{return priv_->vars_edit_script_;}
10937
10938/// Test if the soname of the underlying corpus has changed.
10939///
10940/// @return true iff the soname has changed.
10941bool
10943{return !priv_->sonames_equal_;}
10944
10945/// Test if the architecture of the underlying corpus has changed.
10946///
10947/// @return true iff the architecture has changed.
10948bool
10950{return !priv_->architectures_equal_;}
10951
10952/// Getter for the deleted functions of the diff.
10953///
10954/// @return the the deleted functions of the diff.
10957{return priv_->deleted_fns_;}
10958
10959/// Getter for the added functions of the diff.
10960///
10961/// @return the added functions of the diff.
10964{return priv_->added_fns_;}
10965
10966/// Getter for the functions which signature didn't change, but which
10967/// do have some indirect changes in their parms.
10968///
10969/// @return a non-sorted map of functions which signature didn't
10970/// change, but which do have some indirect changes in their parms.
10971/// The key of the map is a unique identifier for the function; it's
10972/// usually made of the name and version of the underlying ELF symbol
10973/// of the function for corpora that were built from ELF files.
10976{return priv_->changed_fns_map_;}
10977
10978/// Getter for a sorted vector of functions which signature didn't
10979/// change, but which do have some indirect changes in their parms.
10980///
10981/// @return a sorted vector of functions which signature didn't
10982/// change, but which do have some indirect changes in their parms.
10985{return priv_->changed_fns_;}
10986
10987/// Getter for the variables that got deleted from the first subject
10988/// of the diff.
10989///
10990/// @return the map of deleted variable.
10991const string_var_ptr_map&
10993{return priv_->deleted_vars_;}
10994
10995/// Getter for the added variables of the diff.
10996///
10997/// @return the map of added variable.
10998const string_var_ptr_map&
11000{return priv_->added_vars_;}
11001
11002/// Getter for the non-sorted map of variables which signature didn't
11003/// change but which do have some indirect changes in some sub-types.
11004///
11005/// @return the non-sorted map of changed variables.
11008{return priv_->changed_vars_map_;}
11009
11010/// Getter for the sorted vector of variables which signature didn't
11011/// change but which do have some indirect changes in some sub-types.
11012///
11013/// @return a sorted vector of changed variables.
11016{return priv_->sorted_changed_vars_;}
11017
11018/// Getter for function symbols not referenced by any debug info and
11019/// that got deleted.
11020///
11021/// @return a map of elf function symbols not referenced by any debug
11022/// info and that got deleted.
11025{return priv_->deleted_unrefed_fn_syms_;}
11026
11027/// Getter for function symbols not referenced by any debug info and
11028/// that got added.
11029///
11030/// @return a map of elf function symbols not referenced by any debug
11031/// info and that got added.
11034{return priv_->added_unrefed_fn_syms_;}
11035
11036/// Getter for variable symbols not referenced by any debug info and
11037/// that got deleted.
11038///
11039/// @return a map of elf variable symbols not referenced by any debug
11040/// info and that got deleted.
11043{return priv_->deleted_unrefed_var_syms_;}
11044
11045/// Getter for variable symbols not referenced by any debug info and
11046/// that got added.
11047///
11048/// @return a map of elf variable symbols not referenced by any debug
11049/// info and that got added.
11052{return priv_->added_unrefed_var_syms_;}
11053
11054/// Getter for a map of deleted types that are not reachable from
11055/// global functions/variables.
11056///
11057/// @return a map that associates pretty representation of deleted
11058/// unreachable types and said types.
11061{return priv_->deleted_unreachable_types_;}
11062
11063/// Getter of a sorted vector of deleted types that are not reachable
11064/// from global functions/variables.
11065///
11066/// @return a sorted vector of deleted types that are not reachable
11067/// from global functions/variables. The types are lexicographically
11068/// sorted by considering their pretty representation.
11069const vector<type_base_sptr>&
11071{
11072 if (priv_->deleted_unreachable_types_sorted_.empty())
11073 if (!priv_->deleted_unreachable_types_.empty())
11074 sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
11075 priv_->deleted_unreachable_types_sorted_);
11076
11077 return priv_->deleted_unreachable_types_sorted_;
11078}
11079
11080/// Getter for a map of added types that are not reachable from global
11081/// functions/variables.
11082///
11083/// @return a map that associates pretty representation of added
11084/// unreachable types and said types.
11087{return priv_->added_unreachable_types_;}
11088
11089/// Getter of a sorted vector of added types that are not reachable
11090/// from global functions/variables.
11091///
11092/// @return a sorted vector of added types that are not reachable from
11093/// global functions/variables. The types are lexicographically
11094/// sorted by considering their pretty representation.
11095const vector<type_base_sptr>&
11097{
11098 if (priv_->added_unreachable_types_sorted_.empty())
11099 if (!priv_->added_unreachable_types_.empty())
11100 sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
11101 priv_->added_unreachable_types_sorted_);
11102
11103 return priv_->added_unreachable_types_sorted_;
11104}
11105
11106/// Getter for a map of changed types that are not reachable from
11107/// global functions/variables.
11108///
11109/// @return a map that associates pretty representation of changed
11110/// unreachable types and said types.
11113{return priv_->changed_unreachable_types_;}
11114
11115/// Getter of a sorted vector of changed types that are not reachable
11116/// from global functions/variables.
11117///
11118/// @return a sorted vector of changed types that are not reachable
11119/// from global functions/variables. The diffs are lexicographically
11120/// sorted by considering their pretty representation.
11121const vector<diff_sptr>&
11123{return priv_->changed_unreachable_types_sorted();}
11124
11125/// Getter of the diff context of this diff
11126///
11127/// @return the diff context for this diff.
11130{return priv_->get_context();}
11131
11132/// @return the pretty representation for the current instance of @ref
11133/// corpus_diff
11134const string&
11136{
11137 if (priv_->pretty_representation_.empty())
11138 {
11139 std::ostringstream o;
11140 o << "corpus_diff["
11141 << first_corpus()->get_path()
11142 << ", "
11143 << second_corpus()->get_path()
11144 << "]";
11145 priv_->pretty_representation_ = o.str();
11146 }
11147 return priv_->pretty_representation_;
11148}
11149/// Return true iff the current @ref corpus_diff node carries a
11150/// change.
11151///
11152/// @return true iff the current diff node carries a change.
11153bool
11155{
11156 return (soname_changed()
11158 || !(priv_->deleted_fns_.empty()
11159 && priv_->added_fns_.empty()
11160 && priv_->changed_fns_map_.empty()
11161 && priv_->deleted_vars_.empty()
11162 && priv_->added_vars_.empty()
11163 && priv_->changed_vars_map_.empty()
11164 && priv_->added_unrefed_fn_syms_.empty()
11165 && priv_->deleted_unrefed_fn_syms_.empty()
11166 && priv_->added_unrefed_var_syms_.empty()
11167 && priv_->deleted_unrefed_var_syms_.empty()
11168 && priv_->deleted_unreachable_types_.empty()
11169 && priv_->added_unreachable_types_.empty()
11170 && priv_->changed_unreachable_types_.empty()));
11171}
11172
11173/// Test if the current instance of @ref corpus_diff carries changes
11174/// that we are sure are incompatible. By incompatible change we mean
11175/// a change that "breaks" the ABI of the corpus we are looking at.
11176///
11177/// In concrete terms, this function considers the following changes
11178/// as being ABI incompatible for sure:
11179///
11180/// - a soname change
11181/// - if exported functions or variables got removed
11182///
11183/// Note that subtype changes *can* represent changes that break ABI
11184/// too. But they also can be changes that are OK, ABI-wise.
11185///
11186/// It's up to the user to provide suppression specifications to say
11187/// explicitely which subtype change is OK. The remaining sub-type
11188/// changes are then considered to be ABI incompatible. But to test
11189/// if such ABI incompatible subtype changes are present you need to
11190/// use the function @ref corpus_diff::has_net_subtype_changes()
11191///
11192/// @return true iff the current instance of @ref corpus_diff carries
11193/// changes that we are sure are ABI incompatible.
11194bool
11196{
11197 const diff_stats& stats = const_cast<corpus_diff*>(this)->
11199
11201 || stats.net_num_func_removed() != 0
11203 // If all reports about functions with sub-type changes
11204 // have been suppressed, then even those about functions
11205 // that are virtual don't matter anymore because the
11206 // user willingly requested to shut them down
11207 && stats.net_num_func_changed() != 0)
11208 || stats.net_num_vars_removed() != 0
11209 || stats.net_num_removed_func_syms() != 0
11210 || stats.net_num_removed_var_syms() != 0
11211 || stats.net_num_removed_unreachable_types() != 0
11212 || stats.net_num_changed_unreachable_types() != 0);
11213}
11214
11215/// Test if the current instance of @ref corpus_diff carries subtype
11216/// changes whose reports are not suppressed by any suppression
11217/// specification. In effect, these are deemed incompatible ABI
11218/// changes.
11219///
11220/// @return true iff the the current instance of @ref corpus_diff
11221/// carries subtype changes that are deemed incompatible ABI changes.
11222bool
11224{
11225 const diff_stats& stats = const_cast<corpus_diff*>(this)->
11227
11228 return (stats.net_num_func_changed() != 0
11229 || stats.net_num_vars_changed() != 0
11230 || stats.net_num_removed_unreachable_types() != 0
11231 || stats.net_num_changed_unreachable_types() != 0);
11232}
11233
11234/// Test if the current instance of @ref corpus_diff carries changes
11235/// whose reports are not suppressed by any suppression specification.
11236/// In effect, these are deemed incompatible ABI changes.
11237///
11238/// @return true iff the the current instance of @ref corpus_diff
11239/// carries subtype changes that are deemed incompatible ABI changes.
11240bool
11242{return context()->get_reporter()->diff_has_net_changes(this);}
11243
11244/// Apply the different filters that are registered to be applied to
11245/// the diff tree; that includes the categorization filters. Also,
11246/// apply the suppression interpretation filters.
11247///
11248/// After the filters are applied, this function calculates some
11249/// statistics about the changes carried by the current instance of
11250/// @ref corpus_diff. These statistics are represented by an instance
11251/// of @ref corpus_diff::diff_stats.
11252///
11253/// This member function is called by the reporting function
11254/// corpus_diff::report().
11255///
11256/// Note that for a given instance of corpus_diff, this function
11257/// applies the filters and suppressions only the first time it is
11258/// invoked. Subsequent invocations just return the instance of
11259/// corpus_diff::diff_stats that was cached after the first
11260/// invocation.
11261///
11262/// @return a reference to the statistics about the changes carried by
11263/// the current instance of @ref corpus_diff.
11266{
11267 if (priv_->diff_stats_)
11268 return *priv_->diff_stats_;
11269
11271 if (do_log())
11272 {
11273 std::cerr << "Applying suppressions ...\n";
11274 t.start();
11275 }
11276
11277 apply_suppressions(this);
11278
11279 if (do_log())
11280 {
11281 t.stop();
11282 std::cerr << "suppressions applied!:" << t << "\n";
11283 }
11284
11285 priv_->diff_stats_.reset(new diff_stats(context()));
11286
11287 if (do_log())
11288 {
11289 std::cerr << "Marking leaf nodes ...\n";
11290 t.start();
11291 }
11292
11294
11295 if (do_log())
11296 {
11297 t.stop();
11298 std::cerr << "leaf nodes marked!:" << t << "\n";
11299 std::cerr << "Applying filters and computing diff stats ...\n";
11300 t.start();
11301 }
11302
11303 priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
11304
11305 if (do_log())
11306 {
11307 t.stop();
11308 std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
11309 }
11310
11311 return *priv_->diff_stats_;
11312}
11313
11314/// A visitor that marks leaf diff nodes by storing them in the
11315/// instance of @ref diff_maps returned by
11316/// corpus_diff::get_leaf_diffs() invoked on the current instance of
11317/// corpus_diff.
11318struct leaf_diff_node_marker_visitor : public diff_node_visitor
11319{
11320 /// This is called when the visitor visits a diff node.
11321 ///
11322 /// It basically tests if the diff node being visited is a leaf diff
11323 /// node - that is, it contains local changes. If it does, then the
11324 /// node is added to the set of maps that hold leaf diffs in the
11325 /// current corpus_diff.
11326 ///
11327 /// Note that only leaf nodes that are reachable from public
11328 /// interfaces (global functions or variables) are collected by this
11329 /// visitor.
11330 ///
11331 /// @param d the diff node being visited.
11332 virtual void
11333 visit_begin(diff *d)
11334 {
11335 if (d->has_local_changes()
11336 // A leaf basic (or class/union) type name change makes no
11337 // sense when showing just leaf changes. It only makes sense
11338 // when it can explain the details about a non-leaf change.
11339 // In other words, it doesn't make sense to say that an "int"
11340 // became "unsigned int". But it does make sense to say that
11341 // a typedef changed because its underlying type was 'int' and
11342 // is now an "unsigned int".
11344 // Similarly, a *local* change describing a type that changed
11345 // its nature doesn't make sense.
11346 && !is_distinct_diff(d)
11347 // Similarly, a pointer (or reference or array), a typedef or
11348 // qualified type change in itself doesn't make sense. It
11349 // would rather make sense to show that pointer change as part
11350 // of the variable change whose pointer type changed, for
11351 // instance.
11352 && !is_pointer_diff(d)
11353 && !is_reference_diff(d)
11355 && !is_typedef_diff(d)
11356 && !is_array_diff(d)
11357 // Similarly a parameter change in itself doesn't make sense.
11358 // It should have already been reported as part of the change
11359 // of the function it belongs to.
11360 && !is_fn_parm_diff(d)
11361 // An anonymous class or union diff doesn't make sense on its
11362 // own. It must have been described already by the diff of
11363 // the enclosing struct or union if 'd' is from an anonymous
11364 // data member, or from a typedef change if 'd' is from a
11365 // typedef change which underlying type is an anonymous
11366 // struct/union.
11368 // Don't show decl-only-ness changes either.
11370 // Sometime, we can encounter artifacts of bogus DWARF that
11371 // yield a diff node for a decl-only class (and empty class
11372 // with the is_declaration flag set) that carries a non-zero
11373 // size! And of course at some point that non-zero size
11374 // changes. We need to be able to detect that.
11376 {
11377 diff_context_sptr ctxt = d->context();
11378 const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
11379 ABG_ASSERT(corpus_diff_node);
11380
11381 if (diff *iface_diff = get_current_topmost_iface_diff())
11382 {
11383 type_or_decl_base_sptr iface = iface_diff->first_subject();
11384 // So, this diff node that is reachable from a global
11385 // function or variable carries a leaf change. Let's add
11386 // it to the set of of leaf diffs of corpus_diff_node.
11387 const_cast<corpus_diff*>(corpus_diff_node)->
11388 get_leaf_diffs().insert_diff_node(d, iface);
11389 }
11390 }
11391 }
11392}; // end struct leaf_diff_node_marker_visitor
11393
11394/// Walks the diff nodes associated to the current corpus diff and
11395/// mark those that carry local changes. They are said to be leaf
11396/// diff nodes.
11397///
11398/// The marked nodes are available from the
11399/// corpus_diff::get_leaf_diffs() function.
11400void
11402{
11403 if (!has_changes())
11404 return;
11405
11406 if (!context()->show_leaf_changes_only())
11407 return;
11408
11409 leaf_diff_node_marker_visitor v;
11410 context()->forget_visited_diffs();
11411 bool s = context()->visiting_a_node_twice_is_forbidden();
11412 context()->forbid_visiting_a_node_twice(true);
11413 if (context()->show_impacted_interfaces())
11414 context()->forbid_visiting_a_node_twice_per_interface(true);
11415 traverse(v);
11416 context()->forbid_visiting_a_node_twice(s);
11417 context()->forbid_visiting_a_node_twice_per_interface(false);
11418}
11419
11420/// Get the set of maps that contain leaf nodes. A leaf node being a
11421/// node with a local change.
11422///
11423/// @return the set of maps that contain leaf nodes. A leaf node
11424/// being a node with a local change.
11425diff_maps&
11427{return priv_->leaf_diffs_;}
11428
11429/// Get the set of maps that contain leaf nodes. A leaf node being a
11430/// node with a local change.
11431///
11432/// @return the set of maps that contain leaf nodes. A leaf node
11433/// being a node with a local change.
11434const diff_maps&
11436{return priv_->leaf_diffs_;}
11437
11438/// Report the diff in a serialized form.
11439///
11440/// @param out the stream to serialize the diff to.
11441///
11442/// @param indent the prefix to use for the indentation of this
11443/// serialization.
11444void
11445corpus_diff::report(ostream& out, const string& indent) const
11446{
11447 context()->get_reporter()->report(*this, out, indent);
11448}
11449
11450/// Traverse the diff sub-tree under the current instance corpus_diff.
11451///
11452/// @param v the visitor to invoke on each diff node of the sub-tree.
11453///
11454/// @return true if the traversing has to keep going on, false otherwise.
11455bool
11457{
11459
11460 v.visit_begin(this);
11461
11462 if (!v.visit(this, true))
11463 {
11464 v.visit_end(this);
11465 return false;
11466 }
11467
11468 for (function_decl_diff_sptrs_type::const_iterator i =
11469 changed_functions_sorted().begin();
11470 i != changed_functions_sorted().end();
11471 ++i)
11472 {
11473 if (diff_sptr d = *i)
11474 {
11475 const diff_context_sptr &ctxt = context();
11476 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11477 ctxt->forget_visited_diffs();
11478
11480
11481 if (!d->traverse(v))
11482 {
11483 v.visit_end(this);
11485 return false;
11486 }
11487 }
11488 }
11489
11490 for (var_diff_sptrs_type::const_iterator i =
11491 changed_variables_sorted().begin();
11492 i != changed_variables_sorted().end();
11493 ++i)
11494 {
11495 if (diff_sptr d = *i)
11496 {
11497 const diff_context_sptr &ctxt = context();
11498 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11499 ctxt->forget_visited_diffs();
11500
11502
11503 if (!d->traverse(v))
11504 {
11505 v.visit_end(this);
11507 return false;
11508 }
11509 }
11510 }
11511
11513
11514 // Traverse the changed unreachable type diffs. These diffs are on
11515 // types that are not reachable from global functions or variables.
11516 for (vector<diff_sptr>::const_iterator i =
11519 ++i)
11520 {
11521 if (diff_sptr d = *i)
11522 {
11523 const diff_context_sptr &ctxt = context();
11524 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11525 ctxt->forget_visited_diffs();
11526
11527 if (!d->traverse(v))
11528 {
11529 v.visit_end(this);
11530 return false;
11531 }
11532 }
11533 }
11534
11535 v.visit_end(this);
11536 return true;
11537}
11538
11539/// Compute the diff between two instances of @ref corpus.
11540///
11541/// Note that the two corpora must have been created in the same @ref
11542/// environment, otherwise, this function aborts.
11543///
11544/// @param f the first @ref corpus to consider for the diff.
11545///
11546/// @param s the second @ref corpus to consider for the diff.
11547///
11548/// @param ctxt the diff context to use.
11549///
11550/// @return the resulting diff between the two @ref corpus.
11552compute_diff(const corpus_sptr f,
11553 const corpus_sptr s,
11554 diff_context_sptr ctxt)
11555{
11556 typedef corpus::functions::const_iterator fns_it_type;
11557 typedef corpus::variables::const_iterator vars_it_type;
11558 typedef elf_symbols::const_iterator symbols_it_type;
11559 typedef diff_utils::deep_ptr_eq_functor eq_type;
11560 typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
11561
11562 ABG_ASSERT(f && s);
11563
11564 if (!ctxt)
11565 ctxt.reset(new diff_context);
11566
11567 corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
11568
11569 ctxt->set_corpus_diff(r);
11570
11571 if(ctxt->show_soname_change())
11572 r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
11573 else
11574 r->priv_->sonames_equal_ = true;
11575
11576 r->priv_->architectures_equal_ =
11577 f->get_architecture_name() == s->get_architecture_name();
11578
11579 // Compute the diff of publicly defined and exported functions
11580 diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
11581 f->get_functions().end(),
11582 s->get_functions().begin(),
11583 s->get_functions().end(),
11584 r->priv_->fns_edit_script_);
11585
11586 // Compute the diff of publicly defined and exported variables.
11587 diff_utils::compute_diff<vars_it_type, eq_type>
11588 (f->get_variables().begin(), f->get_variables().end(),
11589 s->get_variables().begin(), s->get_variables().end(),
11590 r->priv_->vars_edit_script_);
11591
11592 // Compute the diff of function elf symbols not referenced by debug
11593 // info.
11594 diff_utils::compute_diff<symbols_it_type, eq_type>
11595 (f->get_unreferenced_function_symbols().begin(),
11596 f->get_unreferenced_function_symbols().end(),
11597 s->get_unreferenced_function_symbols().begin(),
11598 s->get_unreferenced_function_symbols().end(),
11599 r->priv_->unrefed_fn_syms_edit_script_);
11600
11601 // Compute the diff of variable elf symbols not referenced by debug
11602 // info.
11603 diff_utils::compute_diff<symbols_it_type, eq_type>
11604 (f->get_unreferenced_variable_symbols().begin(),
11605 f->get_unreferenced_variable_symbols().end(),
11606 s->get_unreferenced_variable_symbols().begin(),
11607 s->get_unreferenced_variable_symbols().end(),
11608 r->priv_->unrefed_var_syms_edit_script_);
11609
11610 if (ctxt->show_unreachable_types())
11611 // Compute the diff of types not reachable from public functions
11612 // or global variables that are exported.
11613 diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
11614 (f->get_types_not_reachable_from_public_interfaces().begin(),
11615 f->get_types_not_reachable_from_public_interfaces().end(),
11616 s->get_types_not_reachable_from_public_interfaces().begin(),
11617 s->get_types_not_reachable_from_public_interfaces().end(),
11618 r->priv_->unreachable_types_edit_script_);
11619
11620 r->priv_->ensure_lookup_tables_populated();
11621
11622 return r;
11623}
11624
11625// </corpus stuff>
11626
11627/// Compute the diff between two instances of @ref corpus_group.
11628///
11629/// Note that the two corpus_diff must have been created in the same
11630/// @ref environment, otherwise, this function aborts.
11631///
11632/// @param f the first @ref corpus_group to consider for the diff.
11633///
11634/// @param s the second @ref corpus_group to consider for the diff.
11635///
11636/// @param ctxt the diff context to use.
11637///
11638/// @return the resulting diff between the two @ref corpus_group.
11640compute_diff(const corpus_group_sptr& f,
11641 const corpus_group_sptr& s,
11642 diff_context_sptr ctxt)
11643{
11644
11645 corpus_sptr c1 = f;
11646 corpus_sptr c2 = s;
11647
11648 return compute_diff(c1, c2, ctxt);
11649}
11650
11651// <corpus_group stuff>
11652
11653// </corpus_group stuff>
11654// <diff_node_visitor stuff>
11655
11656/// The private data of the @diff_node_visitor type.
11657struct diff_node_visitor::priv
11658{
11659 diff* topmost_interface_diff;
11660 visiting_kind kind;
11661
11662 priv()
11663 : topmost_interface_diff(),
11664 kind()
11665 {}
11666
11667 priv(visiting_kind k)
11668 : topmost_interface_diff(),
11669 kind(k)
11670 {}
11671}; // end struct diff_node_visitor
11672
11673/// Default constructor of the @ref diff_node_visitor type.
11675 : priv_(new priv)
11676{}
11677
11678diff_node_visitor::~diff_node_visitor() = default;
11679
11680/// Constructor of the @ref diff_node_visitor type.
11681///
11682/// @param k how the visiting has to be performed.
11684 : priv_(new priv(k))
11685{}
11686
11687/// Getter for the visiting policy of the traversing code while
11688/// invoking this visitor.
11689///
11690/// @return the visiting policy used by the traversing code when
11691/// invoking this visitor.
11694{return priv_->kind;}
11695
11696/// Setter for the visiting policy of the traversing code while
11697/// invoking this visitor.
11698///
11699/// @param v a bit map representing the new visiting policy used by
11700/// the traversing code when invoking this visitor.
11701void
11703{priv_->kind = v;}
11704
11705/// Setter for the visiting policy of the traversing code while
11706/// invoking this visitor. This one makes a logical or between the
11707/// current policy and the bitmap given in argument and assigns the
11708/// current policy to the result.
11709///
11710/// @param v a bitmap representing the visiting policy to or with
11711/// the current policy.
11712void
11714{priv_->kind = priv_->kind | v;}
11715
11716/// Setter of the diff current topmost interface which is impacted by
11717/// the current diff node being visited.
11718///
11719/// @param d the current topmost interface diff impacted.
11720void
11722{priv_->topmost_interface_diff = d;}
11723
11724/// Getter of the diff current topmost interface which is impacted by
11725/// the current diff node being visited.
11726///
11727/// @return the current topmost interface diff impacted.
11728diff*
11730{return priv_->topmost_interface_diff;}
11731
11732/// This is called by the traversing code on a @ref diff node just
11733/// before visiting it. That is, before visiting it and its children
11734/// node.
11735///
11736/// @param d the diff node to visit.
11737void
11739{}
11740
11741/// This is called by the traversing code on a @ref diff node just
11742/// after visiting it. That is after visiting it and its children
11743/// nodes.
11744///
11745/// @param d the diff node that got visited.
11746void
11748{}
11749
11750/// This is called by the traversing code on a @ref corpus_diff node
11751/// just before visiting it. That is, before visiting it and its
11752/// children node.
11753///
11754/// @param p the corpus_diff node to visit.
11755///
11756void
11758{}
11759
11760/// This is called by the traversing code on a @ref corpus_diff node
11761/// just after visiting it. That is after visiting it and its children
11762/// nodes.
11763///
11764/// @param d the diff node that got visited.
11765void
11767{}
11768
11769/// Default visitor implementation
11770///
11771/// @return true
11772bool
11774{return true;}
11775
11776/// Default visitor implementation.
11777///
11778/// @return true
11779bool
11781{
11782 diff* d = dif;
11783 visit(d, pre);
11784
11785 return true;
11786}
11787
11788/// Default visitor implementation.
11789///
11790/// @return true
11791bool
11793{
11794 diff* d = dif;
11795 visit(d, pre);
11796
11797 return true;
11798}
11799
11800/// Default visitor implementation.
11801///
11802/// @return true
11803bool
11805{
11806 diff* d = dif;
11807 visit(d, pre);
11808
11809 return true;
11810}
11811
11812/// Default visitor implementation.
11813///
11814/// @return true
11815bool
11817{
11818 diff* d = dif;
11819 visit(d, pre);
11820
11821 return true;
11822}
11823
11824/// Default visitor implementation.
11825///
11826/// @return true
11827bool
11829{
11830 diff* d = dif;
11831 visit(d, pre);
11832
11833 return true;
11834}
11835
11836/// Default visitor implementation.
11837///
11838/// @return true
11839bool
11841{
11842 diff* d = dif;
11843 visit(d, pre);
11844
11845 return true;
11846}
11847
11848/// Default visitor implementation.
11849///
11850/// @return true
11851bool
11853{
11854 diff* d = dif;
11855 visit(d, pre);
11856
11857 return true;
11858}
11859
11860/// Default visitor implementation.
11861///
11862/// @return true
11863bool
11865{
11866 diff* d = dif;
11867 visit(d, pre);
11868
11869 return true;
11870}
11871
11872/// Default visitor implementation.
11873///
11874/// @return true
11875bool
11877{
11878 diff* d = dif;
11879 visit(d, pre);
11880
11881 return true;
11882}
11883
11884/// Default visitor implementation.
11885///
11886/// @return true
11887bool
11889{
11890 diff* d = dif;
11891 visit(d, pre);
11892
11893 return true;
11894}
11895
11896/// Default visitor implementation.
11897///
11898/// @return true
11899bool
11901{
11902 diff* d = dif;
11903 visit(d, pre);
11904
11905 return true;
11906}
11907
11908/// Default visitor implementation.
11909///
11910/// @return true
11911bool
11913{
11914 diff* d = dif;
11915 visit(d, pre);
11916
11917 return true;
11918}
11919
11920/// Default visitor implementation.
11921///
11922/// @return true
11923bool
11925{
11926 diff* d = dif;
11927 visit(d, pre);
11928
11929 return true;
11930}
11931
11932/// Default visitor implementation.
11933///
11934/// @return true
11935bool
11937{return true;}
11938
11939// </diff_node_visitor stuff>
11940
11941// <redundant diff node marking>
11942
11943// </redundant diff node marking>
11944
11945// <diff tree category propagation>
11946
11947/// A visitor to propagate the category of a node up to its parent
11948/// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
11949/// SUPPRESSED_CATEGORY because those are propagated using other
11950/// specific visitors.
11951struct category_propagation_visitor : public diff_node_visitor
11952{
11953 virtual void
11954 visit_end(diff* d)
11955 {
11956 // Has this diff node 'd' been already visited ?
11957 bool already_visited = d->context()->diff_has_been_visited(d);
11958
11959 // The canonical diff node of the class of equivalence of the diff
11960 // node 'd'.
11961 diff* canonical = d->get_canonical_diff();
11962
11963 // If this class of equivalence of diff node is being visited for
11964 // the first time, then update its canonical node's category too.
11965 bool update_canonical = !already_visited && canonical;
11966
11967 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
11968 i != d->children_nodes().end();
11969 ++i)
11970 {
11971 // If we are visiting the class of equivalence of 'd' for the
11972 // first time, then let's look at the children of 'd' and
11973 // propagate their categories to 'd'.
11974 //
11975 // If the class of equivalence of 'd' has already been
11976 // visited, then let's look at the canonical diff nodes of the
11977 // children of 'd' and propagate their categories to 'd'.
11978 diff* diff = already_visited
11979 ? (*i)->get_canonical_diff()
11980 : *i;
11981
11983
11985 // Do not propagate redundant and suppressed categories. Those
11986 // are propagated in a specific pass elsewhere.
11987 c &= ~(REDUNDANT_CATEGORY
11993 // Also, if a (class) type has got a harmful name change, do not
11994 // propagate harmless name changes coming from its sub-types
11995 // (i.e, data members) to the class itself.
11998
11999 d->add_to_category(c);
12000 if (!already_visited && canonical)
12001 if (update_canonical)
12002 canonical->add_to_category(c);
12003 }
12004 }
12005};// end struct category_propagation_visitor
12006
12007/// Visit all the nodes of a given sub-tree. For each node that has a
12008/// particular category set, propagate that category set up to its
12009/// parent nodes.
12010///
12011/// @param diff_tree the diff sub-tree to walk for categorization
12012/// purpose;
12013void
12015{
12016 category_propagation_visitor v;
12017 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12018 diff_tree->context()->forbid_visiting_a_node_twice(true);
12019 diff_tree->context()->forget_visited_diffs();
12020 diff_tree->traverse(v);
12021 diff_tree->context()->forbid_visiting_a_node_twice(s);
12022}
12023
12024/// Visit all the nodes of a given sub-tree. For each node that has a
12025/// particular category set, propagate that category set up to its
12026/// parent nodes.
12027///
12028/// @param diff_tree the diff sub-tree to walk for categorization
12029/// purpose;
12030void
12032{propagate_categories(diff_tree.get());}
12033
12034/// Visit all the nodes of a given corpus tree. For each node that
12035/// has a particular category set, propagate that category set up to
12036/// its parent nodes.
12037///
12038/// @param diff_tree the corpus_diff tree to walk for categorization
12039/// purpose;
12040void
12042{
12043 category_propagation_visitor v;
12044 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12045 diff_tree->context()->forbid_visiting_a_node_twice(false);
12046 diff_tree->traverse(v);
12047 diff_tree->context()->forbid_visiting_a_node_twice(s);
12048}
12049
12050/// Visit all the nodes of a given corpus tree. For each node that
12051/// has a particular category set, propagate that category set up to
12052/// its parent nodes.
12053///
12054/// @param diff_tree the corpus_diff tree to walk for categorization
12055/// purpose;
12056void
12058{propagate_categories(diff_tree.get());}
12059
12060/// A tree node visitor that knows how to categorizes a given diff
12061/// node in the SUPPRESSED_CATEGORY category and how to propagate that
12062/// categorization.
12063struct suppression_categorization_visitor : public diff_node_visitor
12064{
12065
12066 /// Before visiting the children of the diff node, check if the node
12067 /// is suppressed by a suppression specification. If it is, mark
12068 /// the node as belonging to the SUPPRESSED_CATEGORY category.
12069 ///
12070 /// @param p the diff node to visit.
12071 virtual void
12072 visit_begin(diff* d)
12073 {
12074 bool is_private_type = false;
12075 if (d->is_suppressed(is_private_type))
12076 {
12077 diff_category c = is_private_type
12081
12082 // If a node was suppressed, all the other nodes of its class
12083 // of equivalence are suppressed too.
12084 diff *canonical_diff = d->get_canonical_diff();
12085 if (canonical_diff != d)
12086 canonical_diff->add_to_category(c);
12087 }
12089 {
12090 // This diff node is specifically allowed by a
12091 // negated_suppression, then mark it as being in the
12092 // HAS_ALLOWED_CHANGE_CATEGORY.
12095 diff *canonical_diff = d->get_canonical_diff();
12096 canonical_diff->add_to_category(c);
12097
12098 // Note that some complementary code later down below does
12099 // categorize the descendants and parents nodes of this node
12100 // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
12101 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
12102 }
12103
12104 // If a parent node has been allowed by a negated suppression
12105 // specification, then categorize the current node as
12106 // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
12107 if (d->parent_node())
12108 {
12113 else
12114 {
12115 c = d->parent_node()->get_category();
12119 }
12120 }
12121
12122 }
12123
12124 /// After visiting the children nodes of a given diff node,
12125 /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
12126 /// diff node, if need be.
12127 ///
12128 /// That is, if all children nodes carry a suppressed change the
12129 /// current node should be marked as suppressed as well.
12130 ///
12131 /// In practice, this might be too strong of a condition. If the
12132 /// current node carries a local change (i.e, a change not carried
12133 /// by any of its children node) and if that change is not
12134 /// suppressed, then the current node should *NOT* be suppressed.
12135 ///
12136 /// But right now, the IR doesn't let us know about local vs
12137 /// children-carried changes. So we cannot be that precise yet.
12138 virtual void
12139 visit_end(diff* d)
12140 {
12141 bool has_non_suppressed_child = false;
12142 bool has_non_empty_child = false;
12143 bool has_suppressed_child = false;
12144 bool has_non_private_child = false;
12145 bool has_private_child = false;
12146 bool has_descendant_with_allowed_change = false;
12147
12148 if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
12149 // (or the PRIVATE_TYPE_CATEGORY for the same matter)
12150 // category from its children is a node which:
12151 //
12152 // 1/ hasn't been suppressed already
12153 //
12154 // 2/ and has no local change (unless it's a pointer,
12155 // reference or qualified diff node).
12156 //
12157 // Note that qualified type and typedef diff nodes are a bit
12158 // special. The local changes of the underlying type are
12159 // considered local for the qualified/typedef type, just like
12160 // for pointer/reference types. But then the qualified or
12161 // typedef type itself can have local changes of its own, and
12162 // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
12163 // So a qualified type which have local changes that are
12164 // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
12165 // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
12166 // or SUPPRESSED_CATEGORY can see these categories be
12167 // propagated.
12168 //
12169 // Note that all pointer/reference diff node changes are
12170 // potentially considered local, i.e, local changes of the
12171 // pointed-to-type are considered local to the pointer itself.
12172 //
12173 // Similarly, changes local to the type of function parameters,
12174 // variables (and data members) and classes (that are not of
12175 // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
12176 // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
12177 // those kinds of diff node.
12178 !(d->get_category() & SUPPRESSED_CATEGORY)
12179 && (!d->has_local_changes()
12180 || is_pointer_diff(d)
12181 || is_reference_diff(d)
12183 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12184 || (is_typedef_diff(d)
12185 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12187 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12188 || (is_fn_parm_diff(d)
12189 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12191 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12192 || (is_var_diff(d)
12193 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12194 || (is_class_diff(d)
12195 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
12196 {
12197 // Note that we handle private diff nodes differently from
12198 // generally suppressed diff nodes. E.g, it's not because a
12199 // type is private (and suppressed because of that; i.e, in
12200 // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
12201 // type should also be private and so suppressed. Private
12202 // diff nodes thus have different propagation rules than
12203 // generally suppressed rules.
12204 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12205 i != d->children_nodes().end();
12206 ++i)
12207 {
12208 diff* child = *i;
12209 if (child->has_changes())
12210 {
12211 has_non_empty_child = true;
12212 if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
12213 has_suppressed_child = true;
12214 else if (child->get_class_of_equiv_category()
12216 // Propagation of the PRIVATE_TYPE_CATEGORY is going
12217 // to be handled later below.
12218 ;
12219 else
12220 has_non_suppressed_child = true;
12221
12222 if (child->get_class_of_equiv_category()
12224 has_private_child = true;
12225 else if (child->get_class_of_equiv_category()
12227 // Propagation of the SUPPRESSED_CATEGORY has been
12228 // handled above already.
12229 ;
12230 else
12231 has_non_private_child = true;
12232 }
12233 }
12234
12235 if (has_non_empty_child
12236 && has_suppressed_child
12237 && !has_non_suppressed_child)
12238 {
12240 // If a node was suppressed, all the other nodes of its class
12241 // of equivalence are suppressed too.
12242 diff *canonical_diff = d->get_canonical_diff();
12243 if (canonical_diff != d)
12244 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12245 }
12246
12247 // Note that the private-ness of a an underlying type won't be
12248 // propagated to its parent typedef, by virtue of the big "if"
12249 // clause at the beginning of this function. So we don't have
12250 // to handle that case here. So the idiom of defining
12251 // typedefs of private (opaque) types will be respected;
12252 // meaning that changes to opaque underlying type will be
12253 // flagged as private and the typedef will be flagged private
12254 // as well, unless the typedef itself has local non-type
12255 // changes. In the later case, changes to the typedef will be
12256 // emitted because the typedef won't inherit the privateness
12257 // of its underlying type. So in practise, the typedef
12258 // remains public for the purpose of change reporting.
12259 if (has_non_empty_child
12260 && has_private_child
12261 && !has_non_private_child)
12262 {
12263 d->add_to_category(PRIVATE_TYPE_CATEGORY);
12264 // If a node was suppressed, all the other nodes of its class
12265 // of equivalence are suppressed too.
12266 diff *canonical_diff = d->get_canonical_diff();
12267 if (canonical_diff != d)
12268 canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
12269 }
12270
12271 // If the underlying type of a typedef is private and carries
12272 // changes (that are implicitely suppressed because it's
12273 // private) then the typedef must be suppressed too, so that
12274 // those changes to the underlying type are not seen.
12275 if (is_typedef_diff(d)
12276 && !d->has_local_changes()
12277 && has_private_child
12278 && has_non_empty_child)
12279 {
12280 d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
12281 // If a node was suppressed, all the other nodes of its class
12282 // of equivalence are suppressed too.
12283 diff *canonical_diff = d->get_canonical_diff();
12284 if (canonical_diff != d)
12285 canonical_diff->add_to_category
12287 }
12288
12289 if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
12290 if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
12291 {
12292 // d is a function diff that carries a local *type*
12293 // change (that means it's a change to the function
12294 // type). Let's see if the child function type diff
12295 // node is suppressed. That would mean that we are
12296 // instructed to show details of a diff that is deemed
12297 // suppressed; this means the suppression conflicts with
12298 // a local type change. In that case, let's follow what
12299 // the user asked and suppress the function altogether,
12300 if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
12301 if (fn_type_diff->is_suppressed())
12302 {
12303 d->add_to_category(SUPPRESSED_CATEGORY);
12304 // If a node was suppressed, all the other nodes
12305 // of its class of equivalence are suppressed too.
12306 diff *canonical_diff = d->get_canonical_diff();
12307 if (canonical_diff != d)
12308 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12309 }
12310 }
12311 }
12312
12313 // If any descendant node was selected by a negated suppression
12314 // specification then categorize the current one as
12315 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
12316 for (auto child_node : d->children_nodes())
12317 {
12318 diff *canonical_diff = child_node->get_canonical_diff();
12319 diff_category c = canonical_diff->get_category();
12322 has_descendant_with_allowed_change = true;
12323 }
12324 if (has_descendant_with_allowed_change)
12325 {
12327 d->add_to_category(c);
12328 d->get_canonical_diff()->add_to_category(c);
12329 }
12330 }
12331}; //end struct suppression_categorization_visitor
12332
12333/// Walk a given diff-sub tree and appply the suppressions carried by
12334/// the context. If the suppression applies to a given node than
12335/// categorize the node into the SUPPRESSED_CATEGORY category and
12336/// propagate that categorization.
12337///
12338/// @param diff_tree the diff-sub tree to apply the suppressions to.
12339void
12341{
12342 if (diff_tree && !diff_tree->context()->suppressions().empty())
12343 {
12344 // Apply suppressions to functions and variables that have
12345 // changed sub-types.
12346 suppression_categorization_visitor v;
12347 diff_tree->context()->forget_visited_diffs();
12348 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12349 diff_tree->context()->forbid_visiting_a_node_twice(true);
12350 diff_tree->traverse(v);
12351 diff_tree->context()->forbid_visiting_a_node_twice(s);
12352 }
12353}
12354
12355/// Walk a given diff-sub tree and appply the suppressions carried by
12356/// the context. If the suppression applies to a given node than
12357/// categorize the node into the SUPPRESSED_CATEGORY category and
12358/// propagate that categorization.
12359///
12360/// @param diff_tree the diff-sub tree to apply the suppressions to.
12361void
12363{apply_suppressions(diff_tree.get());}
12364
12365/// Walk a @ref corpus_diff tree and appply the suppressions carried
12366/// by the context. If the suppression applies to a given node then
12367/// categorize the node into the SUPPRESSED_CATEGORY category and
12368/// propagate that categorization.
12369///
12370/// @param diff_tree the diff tree to apply the suppressions to.
12371void
12373{
12374 if (diff_tree && !diff_tree->context()->suppressions().empty())
12375 {
12376 // First, visit the children trees of changed constructs:
12377 // changed functions, variables, as well as sub-types of these,
12378 // and apply suppression specifications to these ...
12379 suppression_categorization_visitor v;
12380 diff_tree->context()->forget_visited_diffs();
12381 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12382 diff_tree->context()->forbid_visiting_a_node_twice(true);
12383 const_cast<corpus_diff*>(diff_tree)->traverse(v);
12384 diff_tree->context()->forbid_visiting_a_node_twice(s);
12385
12386 // ... then also visit the set of added and removed functions,
12387 // variables, symbols, and types not reachable from global
12388 // functions and variables.
12389 diff_tree->priv_->
12390 apply_supprs_to_added_removed_fns_vars_unreachable_types();
12391 }
12392}
12393
12394/// Walk a diff tree and appply the suppressions carried by the
12395/// context. If the suppression applies to a given node than
12396/// categorize the node into the SUPPRESSED_CATEGORY category and
12397/// propagate that categorization.
12398///
12399/// @param diff_tree the diff tree to apply the suppressions to.
12400void
12402{apply_suppressions(diff_tree.get());}
12403
12404// </diff tree category propagation>
12405
12406// <diff tree printing stuff>
12407
12408/// A visitor to print (to an output stream) a pretty representation
12409/// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
12410struct diff_node_printer : public diff_node_visitor
12411{
12412 ostream& out_;
12413 unsigned level_;
12414
12415 /// Emit a certain number of spaces to the output stream associated
12416 /// to this diff_node_printer.
12417 ///
12418 /// @param level half of the numver of spaces to emit.
12419 void
12420 do_indent(unsigned level)
12421 {
12422 for (unsigned i = 0; i < level; ++i)
12423 out_ << " ";
12424 }
12425
12426 diff_node_printer(ostream& out)
12427 : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
12428 out_(out),
12429 level_(0)
12430 {}
12431
12432 virtual void
12433 visit_begin(diff*)
12434 {
12435 ++level_;
12436 }
12437
12438 virtual void
12439 visit_end(diff*)
12440 {
12441 --level_;
12442 }
12443
12444 virtual void
12445 visit_begin(corpus_diff*)
12446 {
12447 ++level_;
12448 }
12449
12450 virtual void
12451 visit_end(corpus_diff*)
12452 {
12453 --level_;
12454 }
12455
12456 virtual bool
12457 visit(diff* d, bool pre)
12458 {
12459 if (!pre)
12460 // We are post-visiting the diff node D. Which means, we have
12461 // printed a pretty representation for it already. So do
12462 // nothing now.
12463 return true;
12464
12465 do_indent(level_);
12466 out_ << d->get_pretty_representation();
12467 out_ << "\n";
12468 do_indent(level_);
12469 out_ << "{\n";
12470 do_indent(level_ + 1);
12471 out_ << "category: "<< d->get_category() << "\n";
12472 do_indent(level_ + 1);
12473 out_ << "@: " << std::hex << d << std::dec << "\n";
12474 do_indent(level_ + 1);
12475 out_ << "@-canonical: " << std::hex
12476 << d->get_canonical_diff()
12477 << std::dec << "\n";
12478 do_indent(level_);
12479 out_ << "}\n";
12480
12481 return true;
12482 }
12483
12484 virtual bool
12485 visit(corpus_diff* d, bool pre)
12486 {
12487 if (!pre)
12488 // We are post-visiting the diff node D. Which means, we have
12489 // printed a pretty representation for it already. So do
12490 // nothing now.
12491 return true;
12492
12493 // indent
12494 for (unsigned i = 0; i < level_; ++i)
12495 out_ << ' ';
12496 out_ << d->get_pretty_representation();
12497 out_ << '\n';
12498 return true;
12499 }
12500}; // end struct diff_printer_visitor
12501
12502// </ diff tree printing stuff>
12503
12504/// Emit a textual representation of a @ref diff sub-tree to an
12505/// output stream.
12506///
12507/// @param diff_tree the sub-tree to emit the textual representation
12508/// for.
12509///
12510/// @param out the output stream to emit the textual representation
12511/// for @p diff_tree to.
12512void
12513print_diff_tree(diff* diff_tree, ostream& out)
12514{
12515 diff_node_printer p(out);
12516 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12517 diff_tree->context()->forbid_visiting_a_node_twice(false);
12518 diff_tree->traverse(p);
12519 diff_tree->context()->forbid_visiting_a_node_twice(s);
12520}
12521
12522/// Emit a textual representation of a @ref corpus_diff tree to an
12523/// output stream.
12524///
12525/// @param diff_tree the @ref corpus_diff tree to emit the textual
12526/// representation for.
12527///
12528/// @param out the output stream to emit the textual representation
12529/// for @p diff_tree to.
12530void
12531print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
12532{
12533 diff_node_printer p(out);
12534 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12535 diff_tree->context()->forbid_visiting_a_node_twice(false);
12536 diff_tree->traverse(p);
12537 diff_tree->context()->forbid_visiting_a_node_twice(s);
12538}
12539
12540/// Emit a textual representation of a @ref diff sub-tree to an
12541/// output stream.
12542///
12543/// @param diff_tree the sub-tree to emit the textual representation
12544/// for.
12545///
12546/// @param out the output stream to emit the textual representation
12547/// for @p diff_tree to.
12548void
12550 std::ostream& o)
12551{print_diff_tree(diff_tree.get(), o);}
12552
12553/// Emit a textual representation of a @ref corpus_diff tree to an
12554/// output stream.
12555///
12556/// @param diff_tree the @ref corpus_diff tree to emit the textual
12557/// representation for.
12558///
12559/// @param out the output stream to emit the textual representation
12560/// for @p diff_tree to.
12561void
12563 std::ostream& o)
12564{print_diff_tree(diff_tree.get(), o);}
12565
12566// <redundancy_marking_visitor>
12567
12568/// A tree visitor to categorize nodes with respect to the
12569/// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
12570/// present on several spots of the tree) and mark such nodes
12571/// appropriatly. This visitor also takes care of propagating the
12572/// REDUNDANT_CATEGORY of a given node to its parent nodes as
12573/// appropriate.
12574struct redundancy_marking_visitor : public diff_node_visitor
12575{
12576 bool skip_children_nodes_;
12577
12578 redundancy_marking_visitor()
12579 : skip_children_nodes_()
12580 {}
12581
12582 virtual void
12583 visit_begin(diff* d)
12584 {
12585 if (d->to_be_reported())
12586 {
12587 // A diff node that carries a change and that has been already
12588 // traversed elsewhere is considered redundant. So let's mark
12589 // it as such and let's not traverse it; that is, let's not
12590 // visit its children.
12591 if ((d->context()->diff_has_been_visited(d)
12592 || d->get_canonical_diff()->is_traversing())
12593 && d->has_changes())
12594 {
12595 // But if two diff nodes are redundant sibbling that carry
12596 // changes of base types, do not mark them as being
12597 // redundant. This is to avoid marking nodes as redundant
12598 // in this case:
12599 //
12600 // int foo(int a, int b);
12601 // compared with:
12602 // float foo(float a, float b); (in C).
12603 //
12604 // In this case, we want to report all the occurences of
12605 // the int->float change because logically, they are at
12606 // the same level in the diff tree.
12607
12608 bool redundant_with_sibling_node = false;
12609 const diff* p = d->parent_node();
12610
12611 // If this is a child node of a fn_parm_diff, look through
12612 // the fn_parm_diff node to get the function diff node.
12613 if (p && dynamic_cast<const fn_parm_diff*>(p))
12614 p = p->parent_node();
12615
12616 if (p)
12617 for (vector<diff*>::const_iterator s =
12618 p->children_nodes().begin();
12619 s != p->children_nodes().end();
12620 ++s)
12621 {
12622 if (*s == d)
12623 continue;
12624 diff* sib = *s;
12625 // If this is a fn_parm_diff, look through the
12626 // fn_parm_diff node to get at the real type node.
12627 if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
12628 sib = f->type_diff().get();
12629 if (sib == d)
12630 continue;
12631 if (sib->get_canonical_diff() == d->get_canonical_diff()
12632 // Sibbling diff nodes that carry base type
12633 // changes ar to be marked as redundant.
12634 && (is_base_diff(sib) || is_distinct_diff(sib)))
12635 {
12636 redundant_with_sibling_node = true;
12637 break;
12638 }
12639 }
12640 if (!redundant_with_sibling_node
12641 // Changes to basic types should never be considered
12642 // redundant. For instance, if a member of integer
12643 // type is changed into a char type in both a struct A
12644 // and a struct B, we want to see both changes.
12646 // The same goes for distinct type changes
12648 // Functions with similar *local* changes are never marked
12649 // redundant because otherwise one could miss important
12650 // similar local changes that are applied to different
12651 // functions.
12653 // Changes involving variadic parameters of functions
12654 // should never be marked redundant because we want to see
12655 // them all.
12658 // If the canonical diff itself has been filtered out,
12659 // then this one is not marked redundant, unless the
12660 // canonical diff was already redundant.
12661 && (!d->get_canonical_diff()->is_filtered_out()
12662 || (d->get_canonical_diff()->get_category()
12664 // If the *same* diff node (not one that is merely
12665 // equivalent to this one) has already been visited
12666 // the do not mark it as beind redundant. It's only
12667 // the other nodes that are equivalent to this one
12668 // that must be marked redundant.
12669 && d->context()->diff_has_been_visited(d) != d
12670 // If the diff node is a function parameter and is not
12671 // a reference/pointer (to a non basic or a non
12672 // distinct type diff) then do not mark it as
12673 // redundant.
12674 //
12675 // Children nodes of base class diff nodes are never
12676 // redundant either, we want to see them all.
12680 {
12682 // As we said in preamble, as this node is marked as
12683 // being redundant, let's not visit its children.
12684 // This is not an optimization; it's needed for
12685 // correctness. In the case of a diff node involving
12686 // a class type that refers to himself, visiting the
12687 // children nodes might cause them to be wrongly
12688 // marked as redundant.
12691 skip_children_nodes_ = true;
12692 }
12693 }
12694 }
12695 else
12696 {
12697 // If the node is not to be reported, do not look at it children.
12699 skip_children_nodes_ = true;
12700 }
12701 }
12702
12703 virtual void
12704 visit_begin(corpus_diff*)
12705 {
12706 }
12707
12708 virtual void
12709 visit_end(diff* d)
12710 {
12711 if (skip_children_nodes_)
12712 // When visiting this node, we decided to skip its children
12713 // node. Now that we are done visiting the node, lets stop
12714 // avoiding the children nodes visiting for the other tree
12715 // nodes.
12716 {
12718 skip_children_nodes_ = false;
12719 }
12720 else
12721 {
12722 // Propagate the redundancy categorization of the children nodes
12723 // to this node. But if this node has local changes, then it
12724 // doesn't inherit redundancy from its children nodes.
12725 if (!(d->get_category() & REDUNDANT_CATEGORY)
12726 && (!d->has_local_changes_to_be_reported()
12727 // By default, pointer, reference and qualified types
12728 // consider that a local changes to their underlying
12729 // type is always a local change for themselves.
12730 //
12731 // This is as if those types don't have local changes
12732 // in the same sense as other types. So we always
12733 // propagate redundancy to them, regardless of if they
12734 // have local changes or not.
12735 //
12736 // We also propagate redundancy to typedef types if
12737 // these /only/ carry changes to their underlying
12738 // type.
12739 //
12740 // Note that changes to the underlying type of a
12741 // typedef is considered local of
12742 // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
12743 // typedef itself are considered local of
12744 // LOCAL_NON_TYPE_CHANGE_KIND kind.
12745 || is_pointer_diff(d)
12747 // A typedef with local non-type changes should not
12748 // see redundancy propagation from its underlying
12749 // type, otherwise, the non-type change might be
12750 // "suppressed" away.
12751 || (is_typedef_diff(d)
12752 && (!(d->has_local_changes()
12754 // A (member) variable with non-type local changes
12755 // should not see redundacy propagation from its type.
12756 // If redundant local-type changes are carried by its
12757 // type however, then that redundancy is propagated to
12758 // the variable. This is key to keep the redundancy
12759 // consistency in the system; otherwise, a type change
12760 // would be rightfully considered redundant at some
12761 // places but not at others.
12762 || (is_var_diff(d)
12763 && (!(d->has_local_changes()
12765 // A function parameter with non-type local changes
12766 // should not see redundancy propagation either. But
12767 // a function parameter with local type changes can
12768 // definitely be redundant.
12769 || (is_fn_parm_diff(d)
12770 && (!(d->has_local_changes()
12772 ))
12773 {
12774 bool has_non_redundant_child = false;
12775 bool has_non_empty_child = false;
12776 for (vector<diff*>::const_iterator i =
12777 d->children_nodes().begin();
12778 i != d->children_nodes().end();
12779 ++i)
12780 {
12781 if ((*i)->has_changes())
12782 {
12783 has_non_empty_child = true;
12784 // Let's see if the current child node '*i' is
12785 // "non-redundant".
12786 //
12787 // A non-redundant node would be a node that
12788 // carries a change to be reported and has not
12789 // been marked as being redundant.
12790 if ((*i)->to_be_reported()
12791 && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
12792 has_non_redundant_child = true;
12793 }
12794 if (has_non_redundant_child)
12795 break;
12796 }
12797
12798 // A diff node for which at least a child node carries a
12799 // change, and for which all the children are redundant is
12800 // deemed redundant too, unless it has local changes.
12801 if (has_non_empty_child
12802 && !has_non_redundant_child)
12803 d->add_to_category(REDUNDANT_CATEGORY);
12804 }
12805 }
12806 }
12807
12808 virtual void
12809 visit_end(corpus_diff*)
12810 {
12811 }
12812
12813 virtual bool
12814 visit(diff*, bool)
12815 {return true;}
12816
12817 virtual bool
12818 visit(corpus_diff*, bool)
12819 {
12820 return true;
12821 }
12822};// end struct redundancy_marking_visitor
12823
12824/// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
12825/// category out of the nodes.
12826struct redundancy_clearing_visitor : public diff_node_visitor
12827{
12828 bool
12829 visit(corpus_diff*, bool)
12830 {return true;}
12831
12832 bool
12833 visit(diff* d, bool)
12834 {
12835 // clear the REDUNDANT_CATEGORY out of the current node.
12836 diff_category c = d->get_category();
12837 c &= ~REDUNDANT_CATEGORY;
12838 d->set_category(c);
12839 return true;
12840 }
12841}; // end struct redundancy_clearing_visitor
12842
12843/// Walk a given @ref diff sub-tree to categorize each of the nodes
12844/// with respect to the REDUNDANT_CATEGORY.
12845///
12846/// @param diff_tree the @ref diff sub-tree to walk.
12847void
12849{
12850 if (diff_tree->context()->show_redundant_changes())
12851 return;
12852 redundancy_marking_visitor v;
12853 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12854 diff_tree->context()->forbid_visiting_a_node_twice(false);
12855 diff_tree->traverse(v);
12856 diff_tree->context()->forbid_visiting_a_node_twice(s);
12857}
12858
12859/// Walk a given @ref diff sub-tree to categorize each of the nodes
12860/// with respect to the REDUNDANT_CATEGORY.
12861///
12862/// @param diff_tree the @ref diff sub-tree to walk.
12863void
12865{categorize_redundancy(diff_tree.get());}
12866
12867/// Walk a given @ref corpus_diff tree to categorize each of the nodes
12868/// with respect to the REDUNDANT_CATEGORY.
12869///
12870/// @param diff_tree the @ref corpus_diff tree to walk.
12871void
12873{
12874 redundancy_marking_visitor v;
12875 diff_tree->context()->forget_visited_diffs();
12876 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12877 diff_tree->context()->forbid_visiting_a_node_twice(false);
12878 diff_tree->traverse(v);
12879 diff_tree->context()->forbid_visiting_a_node_twice(s);
12880}
12881
12882/// Walk a given @ref corpus_diff tree to categorize each of the nodes
12883/// with respect to the REDUNDANT_CATEGORY.
12884///
12885/// @param diff_tree the @ref corpus_diff tree to walk.
12886void
12888{categorize_redundancy(diff_tree.get());}
12889
12890// </redundancy_marking_visitor>
12891
12892/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
12893/// out of the category of the nodes.
12894///
12895/// @param diff_tree the @ref diff sub-tree to walk.
12896void
12898{
12899 redundancy_clearing_visitor v;
12900 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12901 diff_tree->context()->forbid_visiting_a_node_twice(false);
12902 diff_tree->traverse(v);
12903 diff_tree->context()->forbid_visiting_a_node_twice(s);
12904 diff_tree->context()->forget_visited_diffs();
12905}
12906
12907/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
12908/// out of the category of the nodes.
12909///
12910/// @param diff_tree the @ref diff sub-tree to walk.
12911void
12913{clear_redundancy_categorization(diff_tree.get());}
12914
12915/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
12916/// out of the category of the nodes.
12917///
12918/// @param diff_tree the @ref corpus_diff tree to walk.
12919void
12921{
12922 redundancy_clearing_visitor v;
12923 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12924 diff_tree->context()->forbid_visiting_a_node_twice(false);
12925 diff_tree->traverse(v);
12926 diff_tree->context()->forbid_visiting_a_node_twice(s);
12927 diff_tree->context()->forget_visited_diffs();
12928}
12929
12930/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
12931/// out of the category of the nodes.
12932///
12933/// @param diff_tree the @ref corpus_diff tree to walk.
12934void
12936{clear_redundancy_categorization(diff_tree.get());}
12937
12938/// Apply the @ref diff tree filters that have been associated to the
12939/// context of the a given @ref corpus_diff tree. As a result, the
12940/// nodes of the @diff tree are going to be categorized into one of
12941/// several of the categories of @ref diff_category.
12942///
12943/// @param diff_tree the @ref corpus_diff instance which @ref diff are
12944/// to be categorized.
12945void
12947{
12948 diff_tree->context()->maybe_apply_filters(diff_tree);
12949 propagate_categories(diff_tree);
12950}
12951
12952/// Test if a diff node represents the difference between a variadic
12953/// parameter type and something else.
12954///
12955/// @param d the diff node to consider.
12956///
12957/// @return true iff @p d is a diff node that represents the
12958/// difference between a variadic parameter type and something else.
12959bool
12961{
12962 if (!d)
12963 return false;
12964
12965 type_base_sptr t = is_type(d->first_subject());
12966 if (t && t->get_environment().is_variadic_parameter_type(t))
12967 return true;
12968
12969 t = is_type(d->second_subject());
12970 if (t && t->get_environment().is_variadic_parameter_type(t))
12971 return true;
12972
12973 return false;
12974}
12975
12976/// Test if a diff node represents the difference between a variadic
12977/// parameter type and something else.
12978///
12979/// @param d the diff node to consider.
12980///
12981/// @return true iff @p d is a diff node that represents the
12982/// difference between a variadic parameter type and something else.
12983bool
12985{return is_diff_of_variadic_parameter_type(d.get());}
12986
12987/// Test if a diff node represents the difference between a variadic
12988/// parameter and something else.
12989///
12990/// @param d the diff node to consider.
12991///
12992/// @return true iff @p d is a diff node that represents the
12993/// difference between a variadic parameter and something else.
12994bool
12996{
12998 dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
12999 return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
13000}
13001
13002/// Test if a diff node represents the difference between a variadic
13003/// parameter and something else.
13004///
13005/// @param d the diff node to consider.
13006///
13007/// @return true iff @p d is a diff node that represents the
13008/// difference between a variadic parameter and something else.
13009bool
13011{return is_diff_of_variadic_parameter(d.get());}
13012
13013/// Test if a diff node represents a diff between two basic types.
13014///
13015/// @param d the diff node to consider.
13016///
13017/// @return true iff @p d is a diff between two basic types.
13018const type_decl_diff*
13020{return dynamic_cast<const type_decl_diff*>(d);}
13021
13022/// Test if a diff node represents a diff between two basic types, or
13023/// between pointers, references or qualified type to basic types.
13024///
13025/// @param diff the diff node to consider.
13026///
13027/// @param allow_indirect_type if true, then this function looks into
13028/// pointer, reference or qualified diff types to see if they "point
13029/// to" basic types.
13030///
13031/// @return true iff @p d is a diff between two basic types.
13032const type_decl_diff*
13033is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
13034{
13035 if (allow_indirect_type)
13038}
13039
13040/// If a diff node is about changes between two typedef types, get the
13041/// diff node about changes between the underlying types.
13042///
13043/// Note that this function walks the tree of underlying diff nodes
13044/// returns the first diff node about types that are not typedefs.
13045///
13046/// @param dif the dif node to consider.
13047///
13048/// @return the underlying diff node of @p dif, or just return @p dif
13049/// if it's not a typedef diff node.
13050const diff*
13052{
13053 const typedef_diff *d = 0;
13054 while ((d = is_typedef_diff(dif)))
13055 dif = d->underlying_type_diff().get();
13056 return dif;
13057}
13058
13059/// If a diff node is about changes between two pointer types, get the
13060/// diff node about changes between the underlying (pointed-to) types.
13061///
13062/// Note that this function walks the tree of underlying diff nodes
13063/// returns the first diff node about types that are not pointers.
13064///
13065/// @param dif the dif node to consider.
13066///
13067/// @return the underlying diff node of @p dif, or just return @p dif
13068/// if it's not a pointer diff node.
13069const diff*
13071{
13072 const pointer_diff *d = 0;
13073 while ((d = is_pointer_diff(dif)))
13074 dif = d->underlying_type_diff().get();
13075 return dif;
13076}
13077
13078/// If a diff node is about changes between two reference types, get
13079/// the diff node about changes between the underlying (pointed-to)
13080/// types.
13081///
13082/// Note that this function walks the tree of underlying diff nodes
13083/// returns the first diff node about types that are not references.
13084///
13085/// @param dif the dif node to consider.
13086///
13087/// @return the underlying diff node of @p dif, or just return @p dif
13088/// if it's not a reference diff node.
13089const diff*
13091{
13092 const reference_diff *d = 0;
13093 while ((d = is_reference_diff(dif)))
13094 dif = d->underlying_type_diff().get();
13095 return dif;
13096}
13097
13098/// If a diff node is about changes between two qualified types, get
13099/// the diff node about changes between the underlying (non-qualified)
13100/// types.
13101///
13102/// Note that this function walks the tree of underlying diff nodes
13103/// returns the first diff node about types that are not qualified.
13104///
13105/// @param dif the dif node to consider.
13106///
13107/// @return the underlying diff node of @p dif, or just return @p dif
13108/// if it's not a qualified diff node.
13109const diff*
13111{
13112 const qualified_type_diff *d = 0;
13113 while ((d = is_qualified_type_diff(dif)))
13114 dif = d->underlying_type_diff().get();
13115 return dif;
13116}
13117
13118/// If a diff node is about changes between two function parameters
13119/// get the diff node about changes between the types of the parameters.
13120///
13121/// @param dif the dif node to consider.
13122///
13123/// @return the diff of the types of the parameters.
13124const diff*
13126{
13127 const fn_parm_diff *d = 0;
13128 while ((d = is_fn_parm_diff(dif)))
13129 dif = d->type_diff().get();
13130 return dif;
13131}
13132
13133/// If a diff node is about changes between two pointer, reference or
13134/// qualified types, get the diff node about changes between the
13135/// underlying types.
13136///
13137/// Note that this function walks the tree of underlying diff nodes
13138/// returns the first diff node about types that are not pointer,
13139/// reference or qualified.
13140///
13141/// @param dif the dif node to consider.
13142///
13143/// @return the underlying diff node of @p dif, or just return @p dif
13144/// if it's not a pointer, reference or qualified diff node.
13145const diff*
13147{
13148 while (true)
13149 {
13150 if (const pointer_diff *d = is_pointer_diff(dif))
13151 dif = peel_pointer_diff(d);
13152 else if (const reference_diff *d = is_reference_diff(dif))
13153 dif = peel_reference_diff(d);
13154 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13155 dif = peel_qualified_diff(d);
13156 else
13157 break;
13158 }
13159 return dif;
13160}
13161
13162/// If a diff node is about changes between two typedefs or qualified
13163/// types, get the diff node about changes between the underlying
13164/// types.
13165///
13166/// Note that this function walks the tree of underlying diff nodes
13167/// returns the first diff node about types that are not typedef or
13168/// qualified types.
13169///
13170/// @param dif the dif node to consider.
13171///
13172/// @return the underlying diff node of @p dif, or just return @p dif
13173/// if it's not typedef or qualified diff node.
13174const diff*
13176{
13177 while (true)
13178 {
13179 if (const typedef_diff *d = is_typedef_diff(dif))
13180 dif = peel_typedef_diff(d);
13181 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13182 dif = peel_qualified_diff(d);
13183 else
13184 break;
13185 }
13186 return dif;
13187}
13188
13189/// If a diff node is about changes between two typedefs or qualified
13190/// types, get the diff node about changes between the underlying
13191/// types.
13192///
13193/// Note that this function walks the tree of underlying diff nodes
13194/// returns the first diff node about types that are neither typedef,
13195/// qualified type nor parameters.
13196///
13197/// @param dif the dif node to consider.
13198///
13199/// @return the diff node about changes between the underlying types.
13200const diff*
13202{
13203 while (true)
13204 {
13205 if (const typedef_diff *d = is_typedef_diff(dif))
13206 dif = peel_typedef_diff(d);
13207 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13208 dif = peel_qualified_diff(d);
13209 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
13210 dif = peel_fn_parm_diff(d);
13211 else
13212 break;
13213 }
13214 return dif;
13215}
13216
13217/// Test if a diff node represents a diff between two class or union
13218/// types.
13219///
13220/// @param d the diff node to consider.
13221///
13222/// @return iff @p is a diff between two class or union types then
13223/// return the instance of @ref class_or_union_diff that @p derives
13224/// from. Otherwise, return nil.
13227{return dynamic_cast<const class_or_union_diff*>(d);}
13228
13229/// Test if a given diff node carries *only* a local type change.
13230///
13231/// @param d the diff node to consider.
13232///
13233/// @return true iff @p has a change and that change is a local type
13234/// change.
13235static bool
13236has_local_type_change_only(const diff *d)
13237{
13238 if (enum change_kind k = d->has_local_changes())
13239 if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
13240 && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
13241 return true;
13242
13243 return false;
13244}
13245
13246/// Test if a diff node is a decl diff that only carries a basic type
13247/// change on its type diff sub-node.
13248///
13249///Note that that pointers/references/qualified types diffs to basic
13250/// type diffs are considered as having basic type change only.
13251///
13252/// @param d the diff node to consider.
13253///
13254/// @return true iff @p d is a decl diff that only carries a basic
13255/// type change on its type diff sub-node.
13256bool
13258{
13260
13261 if (is_diff_of_basic_type(d, true) && d->has_changes())
13262 return true;
13263 else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
13264 return (has_local_type_change_only(v)
13265 && is_diff_of_basic_type(v->type_diff().get(), true));
13266 else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
13267 return (has_local_type_change_only(p)
13268 && is_diff_of_basic_type(p->type_diff().get(), true));
13269 else if (const function_decl_diff* f =
13270 dynamic_cast<const function_decl_diff*>(d))
13271 return (has_local_type_change_only(f)
13272 && f->type_diff()
13273 && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
13274 true));
13275 return false;
13276}
13277}// end namespace comparison
13278} // end namespace abigail
The private data and functions of the abigail::ir::comparison types.
#define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED
Skip the processing of the current member function if its virtual-ness is disallowed by the user.
#define ABG_ASSERT(cond)
This is a wrapper around the 'assert' glibc call. It allows for its argument to have side effects,...
Definition: abg-fwd.h:1612
#define ABG_ASSERT_NOT_REACHED
A macro that expands to aborting the program when executed.
The abstraction of a diff between two arrays.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of array_diff.
const diff_sptr & element_type_diff() const
Getter for the diff between the two types of array elements.
array_diff(const array_type_def_sptr first, const array_type_def_sptr second, diff_sptr element_type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for array_diff.
const array_type_def_sptr second_array() const
Getter for the second array of the diff.
const array_type_def_sptr first_array() const
Getter for the first array of the diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
An abstraction of a diff between two instances of class_decl::base_spec.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of base_diff.
void set_underlying_class_diff(class_diff_sptr d)
Setter for the diff object for the diff of the underlyng base classes.
class_decl::base_spec_sptr second_base() const
Getter for the second base spec of the diff object.
base_diff(class_decl::base_spec_sptr first, class_decl::base_spec_sptr second, class_diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
const class_diff_sptr get_underlying_class_diff() const
Getter for the diff object for the diff of the underlying base classes.
class_decl::base_spec_sptr first_base() const
Getter for the first base spec of the diff object.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Generates a report for the current instance of base_diff.
This type abstracts changes for a class_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_diff.
class_decl_sptr first_class_decl() const
const base_diff_sptrs_type & changed_bases()
Getter for the changed base classes of the diff.
const vector< class_decl::base_spec_sptr > & moved_bases() const
Getter for the vector of bases that "moved". That is, the vector of base types which position changed...
const string_base_sptr_map & inserted_bases() const
Getter for the inserted base classes of the diff.
const string_base_sptr_map & deleted_bases() const
Getter for the deleted base classes of the diff.
virtual enum change_kind has_local_changes() const
const edit_script & base_changes() const
virtual const string & get_pretty_representation() const
class_diff(class_decl_sptr first_scope, class_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor of class_diff.
friend class_diff_sptr compute_diff(const class_decl_sptr first, const class_decl_sptr second, diff_context_sptr ctxt)
Compute the set of changes between two instances of class_decl.
class_decl_sptr second_class_decl() const
Getter of the second class involved in the diff.
virtual void report(ostream &, const string &indent="") const
Produce a basic report about the changes between two class_decl.
This is the base class of class_diff and union_diff.
virtual bool has_changes() const
Test if the current diff node carries a change.
const edit_script & member_fn_tmpls_changes() const
size_t count_filtered_subtype_changed_data_members(bool local_only=false) const
Count the number of /filtered/ data members with a sub-type change.
const class_or_union_diff::priv_ptr & get_priv() const
Getter of the private data of the class_or_union_diff type.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_or_un...
const edit_script & member_class_tmpls_changes() const
void allocate_priv_data()
Allocate the memory for the priv_ pimpl data member of the class_or_union_diff class.
class_or_union_diff(class_or_union_sptr first_scope, class_or_union_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the class_or_union_diff class.
const edit_script & member_types_changes() const
const string_member_function_sptr_map & deleted_member_fns() const
class_or_union_sptr first_class_or_union() const
const var_diff_sptrs_type & sorted_subtype_changed_data_members() const
Getter of the sorted vector of data members with a (sub-)type change.
bool lookup_tables_empty(void) const
Tests if the lookup tables are empty.
const string_decl_base_sptr_map & data_members_replaced_by_adms() const
Get the map of data members that got replaced by anonymous data members.
void clear_lookup_tables(void)
Clear the lookup tables useful for reporting.
const string_decl_base_sptr_map & deleted_data_members() const
Getter for the data members that got deleted.
virtual ~class_or_union_diff()
Destructor of class_or_union_diff.
const string_decl_base_sptr_map & inserted_data_members() const
Getter for the data members that got inserted.
void ensure_lookup_tables_populated(void) const
If the lookup tables are not yet built, walk the differences and fill them.
const string_member_function_sptr_map & inserted_member_fns() const
const function_decl_diff_sptrs_type & changed_member_fns() const
Getter for the virtual members functions that have had a change in a sub-type, without having a chang...
const edit_script & data_members_changes() const
const changed_var_sptrs_type & ordered_data_members_replaced_by_adms() const
Get an ordered vector of of data members that got replaced by anonymous data members.
virtual enum change_kind has_local_changes() const
size_t count_filtered_changed_data_members(bool local_only=false) const
Count the number of /filtered/ data members that got replaced by another data member.
const edit_script & member_fns_changes() const
class_or_union_sptr second_class_or_union() const
const var_diff_sptrs_type & sorted_changed_data_members() const
Getter of the sorted vector of data members that got replaced by another data member.
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current class_or_union_diff node in a textual format.
This is a document class that aims to capture statistics about the changes carried by a corpus_diff t...
size_t num_changed_unreachable_types_filtered_out() const
Getter of the number of changed types that are unreachable from public interfaces and that have been ...
size_t num_func_removed() const
Getter for the number of functions removed.
size_t num_removed_unreachable_types_filtered_out() const
Getter of the number of removed types that are not reachable from public interfaces and that have bee...
size_t num_vars_changed() const
Getter for the number of variables that have a change in one of their sub-types.
size_t net_num_leaf_var_changes() const
Getter for the net number of leaf variable change diff nodes.
size_t num_vars_added() const
Getter for the number of variables added.
size_t num_removed_unreachable_types() const
Getter of the number of removed types that are unreachable from the public interface of the ABI corpu...
size_t num_changed_vars_filtered_out() const
Getter for the number of variables that have a change in one of their sub-types, and that have been f...
size_t num_changed_func_filtered_out() const
Getter for the number of functions that have a change in one of their sub-types, and that have been f...
size_t num_removed_vars_filtered_out() const
Getter for the number removed variables that have been filtered out.
size_t net_num_func_changed() const
Getter for the number of functions that have a change in their sub-types, minus the number of these f...
size_t net_num_vars_removed() const
Getter for the net number of removed variables.
size_t net_num_added_unreachable_types() const
Getter of the number of added types that are unreachable from public interfaces and that are *NOT* fi...
size_t num_removed_var_syms_filtered_out() const
Getter for the number of removed variable symbols, not referenced by any debug info,...
size_t net_num_added_func_syms() const
Getter of the net number of added function symbols that are not referenced by any debug info.
size_t num_added_var_syms_filtered_out() const
Getter for the number of added variable symbols, not referenced by any debug info,...
size_t num_added_unreachable_types() const
Getter of the number of added types that are unreachable from the public interface of the ABI corpus.
size_t net_num_removed_func_syms() const
Getter of the net number of removed function symbols that are not referenced by any debug info.
size_t num_var_syms_added() const
Getter for the number of variable symbols (not referenced by any debug info) that got added.
size_t num_leaf_var_changes() const
Getter for the number of leaf variable change diff nodes.
size_t net_num_removed_var_syms() const
Getter of the net number of removed variable symbols that are not referenced by any debug info.
size_t net_num_func_removed() const
Getter for the net number of function removed.
size_t net_num_func_added() const
Getter for the net number of added functions.
size_t net_num_removed_unreachable_types() const
Getter of the number of removed types that are not reachable from public interfaces and that have *NO...
size_t net_num_leaf_changes() const
Getter of the net number of leaf change diff nodes.
size_t num_removed_func_syms_filtered_out() const
Getter for the number of removed function symbols, not referenced by debug info, that have been filte...
size_t num_added_unreachable_types_filtered_out() const
Getter of the number of added types that are unreachable from public interfaces and that are filtered...
size_t num_added_func_filtered_out() const
Getter for the number of added function that have been filtered out.
size_t num_func_syms_added() const
Getter for the number of function symbols (not referenced by any debug info) that got added.
size_t net_num_leaf_type_changes() const
Getter for the net number of leaf type change diff nodes.
size_t num_func_added() const
Getter for the number of functions added.
size_t net_num_added_var_syms() const
Getter of the net number of added variable symbols that are not referenced by any debug info.
size_t num_leaf_type_changes() const
Getter for the number of leaf type change diff nodes.
size_t num_leaf_var_changes_filtered_out() const
Getter for the number of leaf variable changes diff nodes that have been filtered out.
size_t num_added_vars_filtered_out() const
Getter for the number of added variables that have been filtered out.
size_t num_func_with_virtual_offset_changes() const
Getter for the number of functions that carry virtual member offset changes.
size_t num_func_changed() const
Getter for the number of functions that have a change in one of their sub-types.
size_t num_removed_func_filtered_out() const
Getter for the number of removed functions that have been filtered out.
size_t net_num_vars_added() const
Getter for the net number of added variables.
size_t num_leaf_changes() const
Getter of the number of leaf type change diff nodes.
size_t num_leaf_func_changes_filtered_out() const
Getter for the number of leaf function change diff nodes that were filtered out.
size_t num_added_func_syms_filtered_out() const
Getter for the number of added function symbols, not referenced by any debug info,...
size_t num_leaf_type_changes_filtered_out() const
Getter for the number of filtered out leaf type change diff nodes.
size_t num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from the public interface of the ABI corpu...
size_t net_num_leaf_func_changes() const
Getter for the net number of leaf function change diff nodes.
size_t num_leaf_func_changes() const
Getter for the number of leaf function change diff nodes.
size_t net_num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from public interfaces and that have *NOT*...
size_t num_func_syms_removed() const
Getter for the number of function symbols (not referenced by any debug info) that got removed.
size_t num_leaf_changes_filtered_out() const
Getter of the number of leaf type change diff nodes that have been filtered out.
size_t num_vars_removed() const
Getter for the number of variables removed.
size_t num_var_syms_removed() const
Getter for the number of variable symbols (not referenced by any debug info) that got removed.
size_t net_num_vars_changed() const
Getter for the number of variables that have a change in their sub-types, minus the number of these v...
An abstraction of a diff between between two abi corpus.
bool has_incompatible_changes() const
Test if the current instance of corpus_diff carries changes that we are sure are incompatible....
bool has_changes() const
Return true iff the current corpus_diff node carries a change.
void finish_diff_type()
Finish building the current instance of corpus_diff.
virtual void chain_into_hierarchy()
Populate the vector of children node of the corpus_diff type.
const string_var_ptr_map & deleted_variables() const
Getter for the variables that got deleted from the first subject of the diff.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Getter of a sorted vector of changed types that are not reachable from global functions/variables.
bool soname_changed() const
Test if the soname of the underlying corpus has changed.
friend corpus_diff_sptr compute_diff(const corpus_sptr f, const corpus_sptr s, diff_context_sptr ctxt)
Compute the diff between two instances of corpus.
const vector< type_base_sptr > & deleted_unreachable_types_sorted() const
Getter of a sorted vector of deleted types that are not reachable from global functions/variables.
edit_script & function_changes() const
edit_script & variable_changes() const
const vector< diff * > & children_nodes() const
const string_diff_sptr_map & changed_unreachable_types() const
Getter for a map of changed types that are not reachable from global functions/variables.
const var_diff_sptrs_type & changed_variables_sorted()
Getter for the sorted vector of variables which signature didn't change but which do have some indire...
const string_elf_symbol_map & deleted_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got deleted.
const string_elf_symbol_map & deleted_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got deleted.
corpus_diff(corpus_sptr first, corpus_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for corpus_diff.
bool do_log() const
Test if logging was requested.
const string_elf_symbol_map & added_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got added.
bool has_net_subtype_changes() const
Test if the current instance of corpus_diff carries subtype changes whose reports are not suppressed ...
const string_var_ptr_map & added_variables() const
Getter for the added variables of the diff.
diff_maps & get_leaf_diffs()
Get the set of maps that contain leaf nodes. A leaf node being a node with a local change.
const diff_context_sptr context() const
Getter of the diff context of this diff.
bool has_net_changes() const
Test if the current instance of corpus_diff carries changes whose reports are not suppressed by any s...
virtual bool traverse(diff_node_visitor &v)
Traverse the diff sub-tree under the current instance corpus_diff.
const diff_stats & apply_filters_and_suppressions_before_reporting()
Apply the different filters that are registered to be applied to the diff tree; that includes the cat...
const string_var_diff_sptr_map & changed_variables()
Getter for the non-sorted map of variables which signature didn't change but which do have some indir...
const string_function_ptr_map & added_functions()
Getter for the added functions of the diff.
void mark_leaf_diff_nodes()
Walks the diff nodes associated to the current corpus diff and mark those that carry local changes....
const string_type_base_sptr_map & deleted_unreachable_types() const
Getter for a map of deleted types that are not reachable from global functions/variables.
const vector< type_base_sptr > & added_unreachable_types_sorted() const
Getter of a sorted vector of added types that are not reachable from global functions/variables.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
const string_elf_symbol_map & added_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got added.
const function_decl_diff_sptrs_type & changed_functions_sorted()
Getter for a sorted vector of functions which signature didn't change, but which do have some indirec...
const string & get_pretty_representation() const
const string_function_ptr_map & deleted_functions() const
Getter for the deleted functions of the diff.
void append_child_node(diff_sptr)
Append a new child node to the vector of children nodes for the current instance of corpus_diff node.
friend void apply_suppressions(const corpus_diff *diff_tree)
Walk a corpus_diff tree and appply the suppressions carried by the context. If the suppression applie...
const string_type_base_sptr_map & added_unreachable_types() const
Getter for a map of added types that are not reachable from global functions/variables.
const string_function_decl_diff_sptr_map & changed_functions()
Getter for the functions which signature didn't change, but which do have some indirect changes in th...
bool architecture_changed() const
Test if the architecture of the underlying corpus has changed.
The base class of diff between decls.
decl_diff_base(decl_base_sptr first_subject, decl_base_sptr second_subject, diff_context_sptr ctxt)
Constructor of decl_diff_base.
The default, initial, reporter of the libabigail comparison engine.
Definition: abg-reporter.h:154
The context of the diff. This type holds various bits of information that is going to be used through...
void add_suppressions(const suppr::suppressions_type &supprs)
Add new suppression specifications that specify which diff node reports should be dropped on the floo...
diff_category get_allowed_category() const
Getter for the bitmap that represents the set of categories that the user wants to see reported.
void forget_visited_diffs()
Unmark all the diff nodes that were marked as being traversed.
corpus_sptr get_first_corpus() const
Getter for the first corpus of the corpus diff of the current context.
bool show_architecture_change() const
Getter for the property that says if the comparison module should show the architecture changes in it...
bool show_offsets_sizes_in_bits() const
Get the flag that indicates if diff reports using this context should show sizes and offsets in bits,...
void forbid_visiting_a_node_twice(bool f)
This sets a flag that, if it's true, then during the traversing of a diff nodes tree each node is vis...
void initialize_canonical_diff(const diff_sptr diff)
Set the canonical diff node property of a given diff node appropriately.
bool show_redundant_changes() const
A getter for the flag that says if we should report about functions or variables diff nodes that have...
void forbid_visiting_a_node_twice_per_interface(bool)
This function sets a flag os that if forbid_visiting_a_node_twice() returns true, then each time the ...
void keep_diff_alive(diff_sptr &)
Add a diff node to the set of diff nodes that are kept alive for the life time of the current instanc...
diff * diff_has_been_visited(const diff *) const
Test if a diff node has been traversed.
bool visiting_a_node_twice_is_forbidden_per_interface() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
void set_corpus_diff(const corpus_diff_sptr &)
Set the corpus diff relevant to this context.
bool show_leaf_changes_only() const
Get the flag that indicates if the diff using this context should show only leaf changes or not.
bool perform_change_categorization() const
Test if it's requested to perform diff node categorization.
bool show_impacted_interfaces() const
Getter of the flag that indicates if the leaf reporter should display a summary of the interfaces imp...
bool show_soname_change() const
Getter for the property that says if the comparison module should show the soname changes in its repo...
reporter_base_sptr get_reporter() const
Getter of the reporter to be used in this context.
void add_diff_filter(filtering::filter_base_sptr)
Setter for the diff filters to apply to a given diff sub-tree.
bool do_log() const
Test if logging was requested.
const suppr::suppressions_type & direct_suppressions() const
Getter of the direct suppression specification (those that are not negated) comprised in the general ...
void maybe_apply_filters(diff_sptr diff)
Apply the diff filters to a given diff sub-tree.
const suppr::suppressions_type & suppressions() const
Getter for the vector of suppressions that specify which diff node reports should be dropped on the f...
bool show_relative_offset_changes(void)
Get the flag saying if offset changes should be reported in a relative way. That is,...
bool visiting_a_node_twice_is_forbidden() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
void do_dump_diff_tree(const diff_sptr) const
Emit a textual representation of a diff tree to the error output stream of the current context,...
const suppr::suppressions_type & negated_suppressions() const
Getter of the negated suppression specifications that are comprised in the general vector of suppress...
void add_suppression(const suppr::suppression_sptr suppr)
Add a new suppression specification that specifies which diff node reports should be dropped on the f...
bool show_hex_values() const
Get the flag that indicates if the diff reports using this context should show sizes and offsets in a...
void switch_categories_off(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
bool show_stats_only() const
Test if the comparison module should only show the diff stats.
const filtering::filters & diff_filters() const
Getter for the diff tree nodes filters to apply to diff sub-trees.
bool show_unreachable_types()
Getter for the flag that indicates if changes on types unreachable from global functions and variable...
const corpus_diff_sptr & get_corpus_diff() const
Get the corpus diff for the current context.
void mark_diff_as_visited(const diff *)
Mark a diff node as traversed by a traversing algorithm.
diff_sptr get_canonical_diff_for(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second) const
Getter for the canonical diff node for the diff represented by their two subjects.
void switch_categories_on(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
ostream * default_output_stream()
Getter for the default output stream used by code of the comparison engine. By default the default ou...
bool dump_diff_tree() const
Test if the comparison engine should dump the diff tree for the changed functions and variables it ha...
bool show_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info are to be compared and...
bool show_added_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info and that got added are...
corpus_sptr get_second_corpus() const
Getter for the second corpus of the corpus diff of the current context.
void set_allowed_category(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
void set_reporter(reporter_base_sptr &)
Setter of the reporter to be used in this context.
ostream * error_output_stream() const
Getter for the errror output stream used by code of the comparison engine. By default the error outpu...
This type contains maps. Each map associates a type name to a diff of that type. Not all kinds of dif...
const string_diff_ptr_map & get_function_decl_diff_map() const
Getter of the map that contains function decl diffs.
const string_diff_ptr_map & get_var_decl_diff_map() const
Getter of the map that contains var decl diffs.
const string_diff_ptr_map & get_enum_diff_map() const
Getter of the map that contains enum type diffs.
bool insert_diff_node(const diff *d, const type_or_decl_base_sptr &impacted_iface)
Insert a new diff node into the current instance of diff_maps.
diff_maps()
Default constructor of the diff_maps type.
const string_diff_ptr_map & get_union_diff_map() const
Getter of the map that contains union type diffs.
artifact_sptr_set_type * lookup_impacted_interfaces(const diff *d) const
Lookup the interfaces that are impacted by a given leaf diff node.
const string_diff_ptr_map & get_function_type_diff_map() const
Getter of the map that contains function type diffs.
const string_diff_ptr_map & get_typedef_diff_map() const
Getter of the map that contains typedef type diffs.
const string_diff_ptr_map & get_distinct_diff_map() const
Getter of the map that contains distinct diffs.
const string_diff_ptr_map & get_subrange_diff_map() const
Getter of the map that contains subrange type diffs.
const string_diff_ptr_map & get_reference_diff_map() const
Getter of the map that contains reference type diffs.
const string_diff_ptr_map & get_array_diff_map() const
Getter of the map that contains array type diffs.
const string_diff_ptr_map & get_type_decl_diff_map() const
Getter of the map that contains basic type diffs.
const string_diff_ptr_map & get_fn_parm_diff_map() const
Getter of the map that contains function parameter diffs.
const string_diff_ptr_map & get_class_diff_map() const
Getter of the map that contains class type diffs.
The base class for the node visitors. These are the types used to visit each node traversed by the di...
void or_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor....
virtual bool visit(diff *, bool)
Default visitor implementation.
virtual bool visit(distinct_diff *, bool)
Default visitor implementation.
virtual void visit_end(corpus_diff *)
This is called by the traversing code on a corpus_diff node just after visiting it....
void set_current_topmost_iface_diff(diff *)
Setter of the diff current topmost interface which is impacted by the current diff node being visited...
virtual void visit_begin(diff *)
This is called by the traversing code on a diff node just before visiting it. That is,...
visiting_kind get_visiting_kind() const
Getter for the visiting policy of the traversing code while invoking this visitor.
virtual void visit_end(diff *)
This is called by the traversing code on a diff node just after visiting it. That is after visiting i...
diff_node_visitor()
Default constructor of the diff_node_visitor type.
void set_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor.
diff * get_current_topmost_iface_diff() const
Getter of the diff current topmost interface which is impacted by the current diff node being visited...
virtual bool traverse(diff_node_visitor &v)
The default traverse function.
The abstraction of a change between two ABI artifacts, a.k.a an artifact change.
void begin_traversing()
Flag a given diff node as being traversed.
void set_category(diff_category c)
Set the category of the current diff node. This category includes the categories inherited from the c...
virtual void finish_diff_type()
Finish the insertion of a diff tree node into the diff graph.
virtual void chain_into_hierarchy()
This constructs the relation between this diff node and its detail diff nodes, in the generic view of...
diff_category remove_from_category(diff_category c)
Remove the current diff tree node from an a existing sef of categories. The categories include those ...
type_or_decl_base_sptr second_subject() const
Getter of the second subject of the diff.
bool is_traversing() const
Tell if a given node is being traversed or not.
type_or_decl_base_sptr first_subject() const
Getter of the first subject of the diff.
bool is_suppressed() const
Test if the current diff node has been suppressed by a user-provided suppression specification.
bool is_filtered_out_without_looking_at_allowed_changes() const
Test if this diff tree node is to be filtered out for reporting purposes, but without considering the...
diff * get_canonical_diff() const
Getter for the canonical diff of the current instance of diff.
bool has_parent_allowed_by_specific_negated_suppression() const
Test if the current diff node has a parent node which is specifically allowed by a negated suppressio...
bool has_local_changes_to_be_reported() const
Test if this diff tree node should be reported when considering the categories that were *NOT* inheri...
const vector< diff * > & children_nodes() const
Getter for the children nodes of the current diff node.
diff_category get_category() const
Getter for the category of the current diff tree node.
bool is_allowed_by_specific_negated_suppression() const
Test if this diff node is allowed (prevented from being suppressed) by at least one negated suppressi...
diff_category remove_from_local_category(diff_category c)
Remove the current diff tree node from the categories resulting from the local changes.
void add_to_local_and_inherited_categories(diff_category c)
Adds the current diff tree node to the categories resulting from the local and inherited changes of t...
bool do_log() const
Test if logging was requested.
diff_category get_local_category() const
Getter for the local category of the current diff tree node.
diff_category add_to_category(diff_category c)
Adds the current diff tree node to an additional set of categories. Note that the categories include ...
const diff_context_sptr context() const
Getter of the context of the current diff.
virtual enum change_kind has_local_changes() const =0
Pure interface to know if the current instance of @diff carries a local change. A local change is a c...
virtual bool traverse(diff_node_visitor &v)
The generic traversing code that walks a given diff sub-tree.
bool currently_reporting() const
Tests if we are currently in the middle of emitting a report for this diff.
virtual bool has_changes() const =0
Pure interface to get the length of the changes encapsulated by this diff. A length of zero means tha...
bool has_descendant_allowed_by_specific_negated_suppression() const
Test if the current diff node has a descendant node which is specifically allowed by a negated suppre...
bool to_be_reported() const
Test if this diff tree node should be reported.
const diff * parent_node() const
Getter for the parent node of the current diff node.
diff_category get_class_of_equiv_category() const
Getter of the category of the class of equivalence of the current diff tree node.
void set_canonical_diff(diff *)
Setter for the canonical diff of the current instance of diff.
bool is_filtered_out_wrt_non_inherited_categories() const
Test if this diff tree node is to be filtered out for reporting purposes, but by considering only the...
diff_category add_to_local_category(diff_category c)
Adds the current diff tree node to the categories resulting from the local changes of the current dif...
void set_local_category(diff_category c)
Set the local category of the current diff node.
virtual const string & get_pretty_representation() const
Get a pretty representation of the current diff node.
void append_child_node(diff_sptr)
Add a new child node to the vector of children nodes for the current diff node.
bool is_filtered_out() const
Test if this diff tree node is to be filtered out for reporting purposes.
void end_traversing()
Flag a given diff node as not being traversed anymore.
bool reported_once() const
Tests if a report has already been emitted for the current diff.
An abstraction of a diff between entities that are of a different kind (disctinct).
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of @distinct_d...
const diff_sptr compatible_child_diff() const
Getter for the child diff of this distinct_diff instance.
distinct_diff(type_or_decl_base_sptr first, type_or_decl_base_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for distinct_diff.
static bool entities_are_of_distinct_kinds(type_or_decl_base_sptr first, type_or_decl_base_sptr second)
Test if the two arguments are of different kind, or that are both NULL.
virtual void report(ostream &out, const string &indent="") const
Emit a report about the current diff instance.
const type_or_decl_base_sptr first() const
Getter for the first subject of the diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const type_or_decl_base_sptr second() const
Getter for the second subject of the diff.
Abstraction of a diff between two enums.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of enum_diff.
enum_diff(const enum_type_decl_sptr, const enum_type_decl_sptr, const diff_sptr, diff_context_sptr ctxt=diff_context_sptr())
Constructor for enum_diff.
diff_sptr underlying_type_diff() const
const string_changed_enumerator_map & changed_enumerators() const
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const enum_type_decl_sptr first_enum() const
const string_enumerator_map & deleted_enumerators() const
const enum_type_decl_sptr second_enum() const
const string_enumerator_map & inserted_enumerators() const
virtual void report(ostream &, const string &indent="") const
Report the differences between the two enums.
A filter that walks the diff nodes tree and tags relevant diff nodes into categories considered to re...
Abstraction of a diff between two function parameters.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children nodes of the diff base type sub-object of this instance of fn_parm_di...
const function_decl::parameter_sptr first_parameter() const
Getter for the first subject of this diff node.
virtual enum change_kind has_local_changes() const
Check if the current diff node carries a local change.
virtual const string & get_pretty_representation() const
Build and return a textual representation of the current instance of fn_parm_diff.
const function_decl::parameter_sptr second_parameter() const
Getter for the second subject of this diff node.
diff_sptr type_diff() const
Getter for the diff representing the changes on the type of the function parameter involved in the cu...
virtual void report(ostream &, const string &indent="") const
Emit a textual report about the current fn_parm_diff instance.
Abstraction of a diff between two function_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_de...
const function_decl_sptr second_function_decl() const
function_decl_diff(const function_decl_sptr first, const function_decl_sptr second, diff_context_sptr ctxt)
Constructor for function_decl_diff.
virtual enum change_kind has_local_changes() const
const function_decl_sptr first_function_decl() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Serialize a report of the changes encapsulated in the current instance of function_decl_diff over to ...
Abstraction of a diff between two function types.
virtual bool has_changes() const
Test if the current diff node carries changes.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_ty...
const string_fn_parm_diff_sptr_map & subtype_changed_parms() const
Getter for the map of function parameter changes of the current diff.
const diff_sptr return_type_diff() const
Getter for the diff of the return types of the two function types of the current diff.
const string_parm_map & removed_parms() const
Getter for the map of parameters that got removed.
const string_parm_map & added_parms() const
Getter for the map of parameters that got added.
friend function_type_diff_sptr compute_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of function_type.
const vector< function_decl::parameter_sptr > & sorted_added_parms() const
Getter for the sorted vector of added parameters .
const function_type_sptr first_function_type() const
Getter for the first subject of the diff.
const function_type_sptr second_function_type() const
Getter for the second subject of the diff.
function_type_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Consutrctor of the function_type type.
virtual enum change_kind has_local_changes() const
Test if the current diff node carries local changes.
virtual const string & get_pretty_representation() const
Build and return a copy of a pretty representation of the current instance of function_type_diff.
const vector< function_decl::parameter_sptr > & sorted_deleted_parms() const
Getter for the sorted vector of deleted parameters.
virtual void report(ostream &, const string &indent="") const
Build and emit a textual report about the current function_type_diff instance.
A reporter that only reports leaf changes.
Definition: abg-reporter.h:267
The abstraction of a diff between two pointers.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const pointer_type_def_sptr first_pointer() const
Getter for the first subject of a pointer diff.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of pointer_dif...
const pointer_type_def_sptr second_pointer() const
Getter for the second subject of a pointer diff.
diff_sptr underlying_type_diff() const
Getter for the diff between the pointed-to types of the pointers of this diff.
pointer_diff(pointer_type_def_sptr first, pointer_type_def_sptr second, diff_sptr underlying_type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for a pointer_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
Abstraction of a diff between two qualified types.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of qualified_t...
diff_sptr leaf_underlying_type_diff() const
Getter for the diff between the most underlying non-qualified types of two qualified types.
diff_sptr underlying_type_diff() const
Getter for the diff between the underlying types of the two qualified types.
qualified_type_diff(qualified_type_def_sptr first, qualified_type_def_sptr second, diff_sptr underling, diff_context_sptr ctxt=diff_context_sptr())
Constructor for qualified_type_diff.
const qualified_type_def_sptr second_qualified_type() const
Getter for the second qualified type of the diff.
virtual enum change_kind has_local_changes() const
const qualified_type_def_sptr first_qualified_type() const
Getter for the first qualified type of the diff.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
The abstraction of a diff between two references.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of reference_d...
reference_type_def_sptr first_reference() const
Getter for the first reference of the diff.
reference_type_def_sptr second_reference() const
Getter for the second reference of the diff.
reference_diff(const reference_type_def_sptr first, const reference_type_def_sptr second, diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
Constructor for reference_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const diff_sptr & underlying_type_diff() const
Getter for the diff between the two referred-to types.
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
An abstractions of the changes between two scopes.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of scope_diff.
const diff_sptrs_type & changed_types() const
const scope_decl_sptr second_scope() const
Getter for the second scope of the diff.
const scope_decl_sptr first_scope() const
Getter for the first scope of the diff.
const decl_base_sptr deleted_member_at(unsigned index) const
Accessor that eases the manipulation of the edit script associated to this instance....
const diff_sptrs_type & changed_decls() const
scope_diff(scope_decl_sptr first_scope, scope_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for scope_diff.
friend scope_diff_sptr compute_diff(const scope_decl_sptr first, const scope_decl_sptr second, scope_diff_sptr d, diff_context_sptr ctxt)
Compute the diff between two scopes.
const decl_base_sptr inserted_member_at(unsigned i)
Accessor that eases the manipulation of the edit script associated to this instance....
virtual void report(ostream &out, const string &indent="") const
Report the changes of one scope against another.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const edit_script & member_changes() const
Accessor of the edit script of the members of a scope.
The abstraction of the diff between two subrange types.
virtual bool has_changes() const
Test if the current subrange_diff node carries any change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of subrange_di...
const array_type_def::subrange_sptr second_subrange() const
Getter of the second subrange of the current instance subrange_diff.
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=diff_context_sptr())
Constructor of the subrange_diff diff node type.
const array_type_def::subrange_sptr first_subrange() const
Getter of the first subrange of the current instance subrange_diff.
const diff_sptr underlying_type_diff() const
Getter of the diff node of the underlying types of the current subrange_diff diff node.
virtual enum change_kind has_local_changes() const
Test if the current subrange_diff node carries any local change.
virtual const string & get_pretty_representation() const
Getter the pretty representation of the subrange_diff diff node.
virtual void report(ostream &, const string &indent="") const
Report about the changes carried by this node.
An abstraction of a diff between two translation units.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const translation_unit_sptr second_translation_unit() const
Getter for the second translation unit of this diff.
translation_unit_diff(translation_unit_sptr first, translation_unit_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for translation_unit_diff.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
virtual enum change_kind has_local_changes() const
const translation_unit_sptr first_translation_unit() const
Getter for the first translation unit of this diff.
Abstraction of a diff between two basic type declarations.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const type_decl_sptr first_type_decl() const
Getter for the first subject of the type_decl_diff.
const type_decl_sptr second_type_decl() const
Getter for the second subject of the type_decl_diff.
virtual void report(ostream &out, const string &indent="") const
Ouputs a report of the differences between of the two type_decl involved in the type_decl_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
The base class of diff between types.
Abstraction of a diff between two typedef_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of typedef_dif...
const typedef_decl_sptr second_typedef_decl() const
Getter for the second typedef_decl involved in the diff.
const typedef_decl_sptr first_typedef_decl() const
Getter for the firt typedef_decl involved in the diff.
const diff_sptr underlying_type_diff() const
Getter for the diff between the two underlying types of the typedefs.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Reports the difference between the two subjects of the diff in a serialized form.
union_diff(union_decl_sptr first_union, union_decl_sptr second_union, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the union_diff type.
union_decl_sptr first_union_decl() const
union_decl_sptr second_union_decl() const
virtual ~union_diff()
Destructor of the union_diff node.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current union_diff node in a textual format.
Abstracts a diff between two instances of var_decl.
virtual bool has_changes() const
Return true iff the diff node has a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of var_diff.
var_diff(var_decl_sptr first, var_decl_sptr second, diff_sptr type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for var_diff.
var_decl_sptr first_var() const
Getter for the first var_decl of the diff.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
virtual enum change_kind has_local_changes() const
friend var_diff_sptr compute_diff(const var_decl_sptr first, const var_decl_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of var_decl.
virtual const string & get_pretty_representation() const
diff_sptr type_diff() const
Getter for the diff of the types of the instances of var_decl.
var_decl_sptr second_var() const
Getter for the second var_decl of the diff.
The abstraction of an edit script for transforming a sequence A into a sequence B.
shared_ptr< subrange_type > subrange_sptr
Convenience typedef for a shared pointer on a function_decl::subrange.
Definition: abg-ir.h:2473
shared_ptr< base_spec > base_spec_sptr
Convenience typedef.
Definition: abg-ir.h:4168
vector< base_spec_sptr > base_specs
Convenience typedef.
Definition: abg-ir.h:4169
vector< method_decl_sptr > member_functions
Convenience typedef.
Definition: abg-ir.h:3979
The abstraction of the version of an ELF symbol.
Definition: abg-ir.h:1180
Abstraction of an elf symbol.
Definition: abg-ir.h:909
const string & get_id_string() const
Get a string that is representative of a given elf_symbol.
Definition: abg-ir.cc:2430
std::vector< enumerator > enumerators
Convenience typedef for a list of enumerator.
Definition: abg-ir.h:2702
Abstraction for a function declaration.
Definition: abg-ir.h:3033
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3057
const function_type_sptr get_type() const
Return the type of the current instance of function_decl.
Definition: abg-ir.cc:20999
interned_string get_id() const
Return an ID that tries to uniquely identify the function inside a program or a library.
Definition: abg-ir.cc:21336
An abstraction helper for type declarations.
Definition: abg-ir.h:1960
The base class of both types and declarations.
Definition: abg-ir.h:1354
Abstracts a variable declaration.
Definition: abg-ir.h:2930
interned_string get_id() const
Return an ID that tries to uniquely identify the variable inside a program or a library.
Definition: abg-ir.cc:19784
change_kind
The kind of change the current function suppression should apply to.
@ ADDED_FUNCTION_CHANGE_KIND
The function was added to the second subject of the diff.
@ DELETED_FUNCTION_CHANGE_KIND
The function was deleted from the second subject of the diff.
change_kind
The kind of change the current variable suppression should apply to.
@ ADDED_VARIABLE_CHANGE_KIND
The variable was added to the second second subject of the diff.
@ DELETED_VARIABLE_CHANGE_KIND
The variable was deleted from the second subject of the diff.
A type used to time various part of the libabigail system.
bool stop()
Stop the timer.
bool start()
Start the timer.
std::vector< filter_base_sptr > filters
Convenience typedef for a vector of filter_base_sptr.
bool is_decl_only_class_with_size_change(const class_or_union &first, const class_or_union &second)
Test if two classes that are decl-only (have the decl-only flag and carry no data members) but are di...
shared_ptr< filter_base > filter_base_sptr
Convenience typedef for a shared pointer to filter_base.
bool has_harmful_name_change(const decl_base_sptr &f, const decl_base_sptr &s)
Test if two decls represents a harmful name change.
bool has_decl_only_def_change(const decl_base_sptr &first, const decl_base_sptr &second)
Test if two decl_base_sptr are different just by the fact that one is decl-only and the other one is ...
bool has_basic_or_class_type_name_change(const diff *d)
Test if a diff node carries a basic or class type name change.
void apply_filter(filter_base &filter, corpus_diff_sptr d)
Walk the diff sub-trees of a a corpus_diff and apply a filter to the nodes visted....
bool is_mostly_distinct_diff(const diff *d)
Test if a diff node carries a distinct type change or a pointer/reference/typedef to distinct type ch...
shared_ptr< diff > diff_sptr
Convenience typedef for a shared_ptr for the diff class.
Definition: abg-fwd.h:79
visiting_kind operator~(visiting_kind l)
The overloaded 'bit inversion' operator for visiting_kind.
const decl_diff_base * is_decl_diff(const diff *diff)
Test if a diff node is about differences between declarations.
const diff * peel_qualified_diff(const diff *dif)
If a diff node is about changes between two qualified types, get the diff node about changes between ...
const diff * peel_pointer_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two pointer, reference or qualified types,...
void categorize_redundancy(diff *diff_tree)
Walk a given diff sub-tree to categorize each of the nodes with respect to the REDUNDANT_CATEGORY.
vector< diff * > diff_ptrs_type
Convenience typedef for a vector of diff*.
void sort_string_diff_ptr_map(const string_diff_ptr_map &map, diff_ptrs_type &sorted)
Sort a map ofg string -> diff* into a vector of diff_ptr. The diff_ptr are sorted lexicographically w...
diff_category
An enum for the different categories that a diff tree node falls into, regarding the kind of changes ...
@ ACCESS_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries access related changes,...
@ HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless data member change....
@ SUPPRESSED_CATEGORY
This means that a diff node was marked as suppressed by a user-provided suppression specification.
@ VIRTUAL_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an incompatible change to a vtable.
@ REDUNDANT_CATEGORY
A diff node in this category is redundant. That means it's present as a child of a other nodes in the...
@ SIZE_OR_OFFSET_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries a change that modifies the...
@ NON_VIRT_MEM_FUN_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a non-virtual member fu...
@ HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
A diff node in this category has a descendant node that is in the HAS_ALLOWED_CHANGE_CATEGORY categor...
@ HARMLESS_ENUM_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition of enumerator to an enum type.
@ FN_PARM_ADD_REMOVE_CHANGE_CATEGORY
A diff node in this category is a function (or function type) with at least one parameter added or re...
@ VOID_PTR_TO_PTR_CHANGE_CATEGORY
A diff node in this category carries a change from void pointer to non-void pointer.
@ PRIVATE_TYPE_CATEGORY
This means that a diff node was warked as being for a private type. That is, the diff node is meant t...
@ COMPATIBLE_TYPE_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries a change involving two com...
@ TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a type that was declaration-only and that is now ...
@ STATIC_DATA_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a static data member.
@ HARMLESS_DECL_NAME_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless declaration name change....
@ EVERYTHING_CATEGORY
A special enumerator that is the logical 'or' all the enumerators above.
@ NO_CHANGE_CATEGORY
This means the diff node does not carry any (meaningful) change, or that it carries changes that have...
@ HARMLESS_UNION_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless union change.
@ HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
A diff node in this category has a parent node that is in the HAS_ALLOWED_CHANGE_CATEGORY category....
@ BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY
A diff node in this category carries a change in the size of the array type of a global variable,...
@ VAR_TYPE_CV_CHANGE_CATEGORY
A diff node in this category is for a variable which type holds a cv-qualifier change.
@ HAS_ALLOWED_CHANGE_CATEGORY
A diff node in this category carries a change that must be reported, even if the diff node is also in...
@ FN_PARM_TYPE_CV_CHANGE_CATEGORY
A diff node in this category has a function parameter type with a cv-qualifiers change.
@ FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
A diff node in this category is a function parameter type which top cv-qualifiers change.
@ FN_RETURN_TYPE_CV_CHANGE_CATEGORY
A diff node in this category is a function return type with a cv-qualifier change.
@ HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an a symbol alias change that is harmless.
shared_ptr< reporter_base > reporter_base_sptr
A convenience typedef for a shared pointer to a reporter_base.
Definition: abg-reporter.h:53
void sort_string_var_diff_sptr_map(const string_var_diff_sptr_map &map, var_diff_sptrs_type &sorted)
Sort of an instance of string_var_diff_sptr_map map.
unordered_map< string, var_diff_sptr > string_var_diff_sptr_map
Convenience typedef for a map whose key is a string and whose value is a changed variable of type var...
const class_or_union_diff * is_diff_of_class_or_union_type(const diff *d)
Test if a diff node represents a diff between two class or union types.
const pointer_diff * is_pointer_diff(const diff *diff)
Test if a diff node is about differences between two pointers.
vector< var_diff_sptr > var_diff_sptrs_type
Convenience typedef for a vector of var_diff_sptr.
unordered_map< string, class_decl::base_spec_sptr > string_base_sptr_map
Convenience typedef for a map of string and class_decl::basse_spec_sptr.
diff_sptr try_to_diff(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
</distinct_diff>
bool has_basic_type_change_only(const diff *d)
Test if a diff node is a decl diff that only carries a basic type change on its type diff sub-node.
void propagate_categories(diff *diff_tree)
Visit all the nodes of a given sub-tree. For each node that has a particular category set,...
const subrange_diff * is_subrange_diff(const diff *diff)
Test if a diff node is a subrange_diff node.
unordered_map< unsigned, fn_parm_diff_sptr > unsigned_fn_parm_diff_sptr_map
Convenience typedef for a map which key is an integer and which value is a changed parameter.
void sort_string_var_ptr_map(const string_var_ptr_map &map, vector< var_decl * > &sorted)
Sort a map of string -> pointer to var_decl.
void sort_string_base_sptr_map(const string_base_sptr_map &m, class_decl::base_specs &sorted)
Lexicographically sort base specifications found in instances of string_base_sptr_map.
diff_category get_default_harmless_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmless.
vector< diff_sptr > diff_sptrs_type
Convenience typedef for a vector of diff_sptr.
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)
Try to diff entities that are of distinct kinds.
void sort_changed_data_members(changed_var_sptrs_type &input)
Sort (in place) a vector of changed data members.
unordered_map< string, type_base_sptr > string_type_base_sptr_map
Convenience typedef for a map which key is a string and which value is a type_base_sptr.
diff_sptr try_to_diff< class_decl >(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
This is a specialization of try_to_diff() template to diff instances of class_decl.
shared_ptr< type_decl_diff > type_decl_diff_sptr
Convenience typedef for a shared pointer on a type_decl_diff type.
bool is_diff_of_variadic_parameter(const diff *d)
Test if a diff node represents the difference between a variadic parameter and something else.
shared_ptr< diff_context > diff_context_sptr
Convenience typedef for a shared pointer of diff_context.
Definition: abg-fwd.h:71
bool is_diff_of_global_decls(const diff *)
Tests if a given diff node is to represent the changes between two gobal decls.
shared_ptr< subrange_diff > subrange_diff_sptr
A convenience typedef for a shared pointer to subrange_diff type.
bool is_diff_of_variadic_parameter_type(const diff *d)
Test if a diff node represents the difference between a variadic parameter type and something else.
diff_category get_default_harmful_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmful.
unordered_map< string, function_decl::parameter_sptr > string_parm_map
Convenience typedef for a map which value is a function parameter. The key is the name of the functio...
unordered_map< string, enum_type_decl::enumerator > string_enumerator_map
Convenience typedef for a map which value is an enumerator. The key is the name of the enumerator.
shared_ptr< var_diff > var_diff_sptr
Convenience typedef for a shared pointer to a var_diff type.
unordered_map< string, method_decl_sptr > string_member_function_sptr_map
Convenience typedef for a hash map of strings and member functions.
const diff * peel_typedef_diff(const diff *dif)
If a diff node is about changes between two typedef types, get the diff node about changes between th...
shared_ptr< reference_diff > reference_diff_sptr
Convenience typedef for a shared pointer on a reference_diff type.
vector< base_diff_sptr > base_diff_sptrs_type
Convenience typedef for a vector of base_diff_sptr.
unordered_map< string, function_decl * > string_function_ptr_map
Convenience typedef for a map which key is a string and which value is a pointer to decl_base.
shared_ptr< function_decl_diff > function_decl_diff_sptr
Convenience typedef for a shared pointer to a function_decl type.
void sort_string_elf_symbol_map(const string_elf_symbol_map &map, vector< elf_symbol_sptr > &sorted)
Sort a map of string -> pointer to elf_symbol.
const function_decl_diff * is_function_decl_diff(const diff *diff)
Test if a diff node is about differences between functions.
void sort_string_function_decl_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort the values of a string_function_decl_diff_sptr_map map and store the result in a vector of funct...
shared_ptr< fn_parm_diff > fn_parm_diff_sptr
Convenience typedef for a shared pointer to a fn_parm_diff type.
unordered_map< string, function_decl_diff_sptr > string_function_decl_diff_sptr_map
Convenience typedef for a map which key is a string and which value is a function_decl_diff_sptr.
void clear_redundancy_categorization(diff *diff_tree)
Walk a given diff sub-tree to clear the REDUNDANT_CATEGORY out of the category of the nodes.
void sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map, var_diff_sptrs_type &sorted)
Sort the values of a unsigned_var_diff_sptr_map map and store the result into a vector of var_diff_sp...
void sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map &map, vector< fn_parm_diff_sptr > &sorted)
Sort a map of fn_parm_diff by the indexes of the function parameters.
bool is_child_node_of_base_diff(const diff *diff)
Test if a diff node is a child node of a base diff node.
visiting_kind
An enum for the different ways to visit a diff tree node.
@ SKIP_CHILDREN_VISITING_KIND
This says that the traversing code should avoid visiting the children nodes of the current node being...
@ DO_NOT_MARK_VISITED_NODES_AS_VISITED
This says that the traversing code should not mark visited nodes as having been traversed....
visiting_kind operator&(visiting_kind l, visiting_kind r)
The overloaded and operator for visiting_kind.
unordered_map< string, var_decl * > string_var_ptr_map
Convenience typedef for a map which key is a string and which value is a point to var_decl.
const diff * peel_fn_parm_diff(const diff *dif)
If a diff node is about changes between two function parameters get the diff node about changes betwe...
const function_type_diff * is_function_type_diff(const diff *diff)
Test if a diff node is a function_type_diff node.
const distinct_diff * is_distinct_diff(const diff *diff)
Test if a diff node is about differences between two diff nodes of different kinds.
unordered_map< string, changed_enumerator > string_changed_enumerator_map
Convenience typedef for a map which value is a changed enumerator. The key is the name of the changed...
visiting_kind operator|(visiting_kind l, visiting_kind r)
The overloaded or operator for visiting_kind.
const array_diff * is_array_diff(const diff *diff)
Test if a diff node is a array_diff node.
const diff * peel_reference_diff(const diff *dif)
If a diff node is about changes between two reference types, get the diff node about changes between ...
unordered_map< string, fn_parm_diff_sptr > string_fn_parm_diff_sptr_map
Convenience typedef for a map which value is a changed function parameter and which key is the name o...
string get_pretty_representation(diff *d)
Get a copy of the pretty representation of a diff node.
void sort_artifacts_set(const artifact_sptr_set_type &set, vector< type_or_decl_base_sptr > &sorted)
Sort the set of ABI artifacts contained in a artifact_sptr_set_type.
unordered_map< string, decl_base_sptr > string_decl_base_sptr_map
Convenience typedef for a map which key is a string and which value is a decl_base_sptr.
const class_or_union_diff * is_anonymous_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff between two anonymous classes or unions.
shared_ptr< base_diff > base_diff_sptr
Convenience typedef for a shared pointer to a base_diff type.
shared_ptr< scope_diff > scope_diff_sptr
Convenience typedef for a shared pointer on a scope_diff.
shared_ptr< class_diff > class_diff_sptr
Convenience typedef for a shared pointer on a class_diff type.
const base_diff * is_base_diff(const diff *diff)
Test if a diff node is about differences between two base class specifiers.
const fn_parm_diff * is_fn_parm_diff(const diff *diff)
Test if a diff node is about differences between two function parameters.
void sort_string_member_function_sptr_map(const string_member_function_sptr_map &map, class_or_union::member_functions &sorted)
Sort a map that's an instance of string_member_function_sptr_map and fill a vector of member function...
const union_diff * is_union_diff(const diff *diff)
Test if a diff node is a union_diff node.
vector< changed_var_sptr > changed_var_sptrs_type
Convenience typedef for a vector of @changed_var_sptr.gg381.
shared_ptr< pointer_diff > pointer_diff_sptr
Convenience typedef for a shared pointer on a pointer_diff type.
const diff * peel_pointer_diff(const diff *dif)
If a diff node is about changes between two pointer types, get the diff node about changes between th...
void apply_suppressions(diff *diff_tree)
Walk a given diff-sub tree and appply the suppressions carried by the context. If the suppression app...
void sort_string_parm_map(const string_parm_map &map, vector< function_decl::parameter_sptr > &sorted)
Sort a map of string -> function parameters.
void sort_string_type_base_sptr_map(string_type_base_sptr_map &map, vector< type_base_sptr > &sorted)
Sort a map of string to type_base_sptr entities.
const enum_diff * is_enum_diff(const diff *diff)
Test if a diff node is a enum_diff node.
unordered_map< string, base_diff_sptr > string_base_diff_sptr_map
Convenience typedef for a map of string and base_diff_sptr.
void sort_data_members(const string_decl_base_sptr_map &data_members, vector< decl_base_sptr > &sorted)
Sort a map of data members by the offset of their initial value.
const class_or_union_diff * is_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff node.
const corpus_diff * is_corpus_diff(const diff *diff)
Test if a diff node is a corpus_diff node.
const diff * get_typedef_diff_underlying_type_diff(const diff *diff)
Return the leaf underlying diff node of a typedef_diff node.
const typedef_diff * is_typedef_diff(const diff *diff)
Test if a diff node is a typedef_diff node.
unordered_map< unsigned, var_diff_sptr > unsigned_var_diff_sptr_map
Convenience typedef for a map whose key is an unsigned int and whose value is a changed variable of t...
type_base_sptr get_leaf_type(qualified_type_def_sptr t)
Return the first underlying type that is not a qualified type.
const diff * peel_typedef_qualified_type_or_parameter_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
shared_ptr< array_diff > array_diff_sptr
Convenience typedef for a shared pointer on a array_diff type.
bool is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff *diff)
Test if a diff node is a reference or pointer diff node to a change that is neither basic type change...
const class_diff * is_class_diff(const diff *diff)
Test if a diff node is a class_diff node.
const type_decl_diff * is_diff_of_basic_type(const diff *d)
Test if a diff node represents a diff between two basic types.
unordered_map< string, diff_sptr > string_diff_sptr_map
Convenience typedef for a map which value is a diff_sptr. The key of the map is the qualified name of...
unordered_map< const diff *, artifact_sptr_set_type, diff_hash, diff_equal > diff_artifact_set_map_type
A convenience typedef for an unordered_map which key is a diff* and which value is a artifact_sptr_se...
const qualified_type_diff * is_qualified_type_diff(const diff *diff)
Test if a diff node is about differences between two qualified types.
diff_sptr compute_diff(const decl_base_sptr first, const decl_base_sptr second, diff_context_sptr ctxt)
Compute the difference between two decls. The decls can represent either type declarations,...
unordered_map< string, diff * > string_diff_ptr_map
Convenience typedef for a map which value is a diff*. The key of the map is the qualified name of the...
void sort_string_base_diff_sptr_map(const string_base_diff_sptr_map &map, base_diff_sptrs_type &sorted)
Sort a map of string -> base_diff_sptr into a sorted vector of base_diff_sptr. The base_diff_sptr are...
void sort_changed_enumerators(const string_changed_enumerator_map &enumerators_map, changed_enumerators_type &sorted)
Sort a map of changed enumerators.
void print_diff_tree(diff *diff_tree, ostream &out)
Emit a textual representation of a diff sub-tree to an output stream.
vector< changed_enumerator > changed_enumerators_type
Convenience typedef for a vector of changed enumerators.
vector< function_decl_diff_sptr > function_decl_diff_sptrs_type
Convenience typedef for a vector of function_decl_diff_sptr.
bool is_child_node_of_function_parm_diff(const diff *diff)
Test if a diff node is a child node of a function parameter diff node.
void sort_string_virtual_member_function_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort an map of string -> virtual member function into a vector of virtual member functions....
shared_ptr< function_type_diff > function_type_diff_sptr
A convenience typedef for a shared pointer to function_type_type_diff.
const function_type_diff * is_function_type_diff_with_local_changes(const diff *diff)
Test if a given diff node carries a function type change with local changes.
const var_diff * is_var_diff(const diff *diff)
Test if a diff node is about differences between variables.
const type_diff_base * is_type_diff(const diff *diff)
Test if a diff node is about differences between types.
unordered_map< string, elf_symbol_sptr > string_elf_symbol_map
Convenience typedef for a map whose key is a string and whose value is an elf_symbol_sptr.
void sort_string_diff_sptr_map(const string_diff_sptr_map &map, diff_sptrs_type &sorted)
Sort a map ofg string -> diff_sptr into a vector of diff_sptr. The diff_sptr are sorted lexicographic...
const reference_diff * is_reference_diff(const diff *diff)
Test if a diff node is about differences between two references.
void sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map &map, var_diff_sptrs_type &sorted)
Sort the values of a string_var_diff_sptr_map and store the result in a vector of var_diff_sptr.
void apply_filters(corpus_diff_sptr diff_tree)
Apply the diff tree filters that have been associated to the context of the a given corpus_diff tree....
shared_ptr< distinct_diff > distinct_diff_sptr
Convenience typedef for a shared pointer to distinct_types_diff.
shared_ptr< corpus_diff > corpus_diff_sptr
A convenience typedef for a shared pointer to corpus_diff.
std::pair< var_decl_sptr, var_decl_sptr > changed_var_sptr
Convenience typedef for a pair of var_decl_sptr representing a var_decl change. The first member of t...
shared_ptr< typedef_diff > typedef_diff_sptr
Convenience typedef for a shared pointer on a typedef_diff type.
const diff * peel_typedef_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
void sort_enumerators(const string_enumerator_map &enumerators_map, enum_type_decl::enumerators &sorted)
Sort a map of enumerators by their value.
ostream & operator<<(ostream &o, diff_category c)
Serialize an instance of diff_category to an output stream.
shared_ptr< translation_unit_diff > translation_unit_diff_sptr
Convenience typedef for a shared pointer on a translation_unit_diff type.
void sort_string_function_ptr_map(const string_function_ptr_map &map, vector< function_decl * > &sorted)
Sort an instance of string_function_ptr_map map and stuff a resulting sorted vector of pointers to fu...
void compute_diff(RandomAccessOutputIterator a_base, RandomAccessOutputIterator a_begin, RandomAccessOutputIterator a_end, RandomAccessOutputIterator b_base, RandomAccessOutputIterator b_begin, RandomAccessOutputIterator b_end, vector< point > &lcs, edit_script &ses, int &ses_len)
Compute the longest common subsequence of two (sub-regions of) sequences as well as the shortest edit...
shared_ptr< reference_type_def > reference_type_def_sptr
Convenience typedef for a shared pointer on a reference_type_def.
Definition: abg-fwd.h:232
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc:6487
bool get_member_is_static(const decl_base &d)
Gets a flag saying if a class member is static or not.
Definition: abg-ir.cc:5717
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition: abg-fwd.h:266
unordered_set< type_or_decl_base_sptr, type_or_decl_hash, type_or_decl_equal > artifact_sptr_set_type
A convenience typedef for a hash set of type_or_decl_base_sptr.
Definition: abg-ir.h:550
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition: abg-ir.cc:10248
bool is_anonymous_data_member(const decl_base &d)
Test if a decl is an anonymous data member.
Definition: abg-ir.cc:5946
array_type_def::subrange_type * is_subrange_type(const type_or_decl_base *type)
Test if a type is an array_type_def::subrange_type.
Definition: abg-ir.cc:11226
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:874
change_kind
A bitfield that gives callers of abigail::ir::equals() some insight about how different two internal ...
Definition: abg-ir.h:1309
@ LOCAL_TYPE_CHANGE_KIND
This means that a given IR artifact has a local type change.
Definition: abg-ir.h:1313
@ ALL_LOCAL_CHANGES_MASK
Testing (anding) against this mask means that a given IR artifact has local differences,...
Definition: abg-ir.h:1324
@ LOCAL_NON_TYPE_CHANGE_KIND
This means that a given IR artifact has a local non-type change. That is a change that is carried by ...
Definition: abg-ir.h:1318
bool is_user_defined_type(const type_base *t)
Test if a type is user-defined.
Definition: abg-ir.cc:5621
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:10512
shared_ptr< array_type_def > array_type_def_sptr
Convenience typedef for a shared pointer on a array_type_def.
Definition: abg-fwd.h:237
string get_pretty_representation(const type_or_decl_base *tod, bool internal)
Build and return a copy of the pretty representation of an ABI artifact that could be either a type o...
Definition: abg-ir.cc:9198
class_or_union * is_class_or_union_type(const type_or_decl_base *t)
Test if a type is a class_or_union.
Definition: abg-ir.cc:10586
const var_decl_sptr get_next_data_member(const class_or_union *klass, const var_decl_sptr &data_member)
In the context of a given class or union, this function returns the data member that is located after...
Definition: abg-ir.cc:5884
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:190
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition: abg-fwd.h:207
shared_ptr< typedef_decl > typedef_decl_sptr
Convenience typedef for a shared pointer on a typedef_decl.
Definition: abg-fwd.h:164
var_decl_sptr find_data_member_from_anonymous_data_member(const var_decl_sptr &anon_dm, const string &name)
Find a data member inside an anonymous data member.
Definition: abg-ir.cc:10091
const global_scope * get_global_scope(const decl_base &decl)
return the global scope as seen by a given declaration.
Definition: abg-ir.cc:8440
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition: abg-fwd.h:249
shared_ptr< scope_decl > scope_decl_sptr
Convenience typedef for a shared pointer on a scope_decl.
Definition: abg-fwd.h:261
shared_ptr< type_or_decl_base > type_or_decl_base_sptr
A convenience typedef for a shared_ptr to type_or_decl_base.
Definition: abg-fwd.h:121
shared_ptr< translation_unit > translation_unit_sptr
Convenience typedef for a shared pointer on a translation_unit type.
Definition: abg-fwd.h:137
bool equals(const decl_base &l, const decl_base &r, change_kind *k)
Compares two instances of decl_base.
Definition: abg-ir.cc:5268
shared_ptr< pointer_type_def > pointer_type_def_sptr
Convenience typedef for a shared pointer on a pointer_type_def.
Definition: abg-fwd.h:223
uint64_t get_absolute_data_member_offset(const var_decl &m)
Get the absolute offset of a data member.
Definition: abg-ir.cc:6306
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition: abg-ir.cc:6401
var_decl * is_var_decl(const type_or_decl_base *tod)
Tests if a declaration is a variable declaration.
Definition: abg-ir.cc:11084
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition: abg-ir.cc:10188
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition: abg-fwd.h:172
type_base_sptr strip_typedef(const type_base_sptr type)
Recursively returns the the underlying type of a typedef. The return type should not be a typedef of ...
Definition: abg-ir.cc:6764
uint64_t get_data_member_offset(const var_decl &m)
Get the offset of a data member.
Definition: abg-ir.cc:6217
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6674
class_or_union * look_through_decl_only_class(class_or_union *the_class)
If a class (or union) is a decl-only class, get its definition. Otherwise, just return the initial cl...
Definition: abg-ir.cc:10943
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition: abg-ir.cc:10605
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition: abg-ir.cc:5755
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition: abg-ir.cc:9881
shared_ptr< type_decl > type_decl_sptr
Convenience typedef for a shared pointer on a type_decl.
Definition: abg-fwd.h:158
bool is_unique_type(const type_base_sptr &t)
Test if a type is unique in the entire environment.
Definition: abg-ir.cc:26691
method_type_sptr is_method_type(const type_or_decl_base_sptr &t)
Test whether a type is a method_type.
Definition: abg-ir.cc:10913
interned_string get_function_id_or_pretty_representation(function_decl *fn)
Get the ID of a function, or, if the ID can designate several different functions,...
Definition: abg-ir.cc:9072
bool is_at_global_scope(const decl_base &decl)
Tests whether a given declaration is at global scope.
Definition: abg-ir.cc:10021
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition: abg-ir.cc:5559
shared_ptr< variable_suppression > variable_suppression_sptr
A convenience typedef for a shared pointer to variable_suppression.
vector< suppression_sptr > suppressions_type
Convenience typedef for a vector of suppression_sptr.
Definition: abg-fwd.h:1556
shared_ptr< function_suppression > function_suppression_sptr
Convenience typedef for a shared pointer to function_suppression.
variable_suppression_sptr is_variable_suppression(const suppression_sptr s)
Test if an instance of suppression is an instance of variable_suppression.
bool is_private_type_suppr_spec(const type_suppression &s)
Test if a type suppression specification represents a private type suppression automatically generate...
shared_ptr< type_suppression > type_suppression_sptr
Convenience typedef for a shared pointer to type_suppression.
function_suppression_sptr is_function_suppression(const suppression_sptr suppr)
Test if an instance of suppression is an instance of function_suppression.
type_suppression_sptr is_type_suppression(suppression_sptr suppr)
Test if an instance of suppression is an instance of type_suppression.
shared_ptr< suppression_base > suppression_sptr
Convenience typedef for a shared pointer to a suppression.
Definition: abg-fwd.h:1553
bool is_negated_suppression(const suppression_base &s)
Test if a suppression specification is a negated suppression.
Toplevel namespace for libabigail.
A comparison function for instances of base_diff.
A functor to compare instances of class_decl::base_spec.
A functor to compare two changed enumerators, based on their initial value.
size_t count_filtered_bases()
Count the number of bases classes whose changes got filtered out.
class_decl::base_spec_sptr base_has_changed(class_decl::base_spec_sptr) const
Test whether a given base class has changed. A base class has changed if it's in both in deleted *and...
The type of private data of class_or_union_diff.
size_t count_filtered_changed_dm(bool local_only=false)
Get the number of data member changes carried by the current diff node that were filtered out.
size_t count_filtered_subtype_changed_dm(bool local_only=false)
Get the number of data member sub-type changes carried by the current diff node that were filtered ou...
size_t get_deleted_non_static_data_members_number() const
Get the number of non static data members that were deleted.
size_t count_filtered_changed_mem_fns(const diff_context_sptr &)
Get the number of member functions changes carried by the current diff node that were filtered out.
decl_base_sptr subtype_changed_dm(decl_base_sptr) const
Test if the current diff node carries a data member change for a data member which name is the same a...
type_or_decl_base_sptr member_type_has_changed(decl_base_sptr) const
Test if the current diff node carries a member type change for a member type which name is the same a...
decl_base_sptr member_class_tmpl_has_changed(decl_base_sptr) const
Test if the current diff node carries a member class template change for a member class template whic...
size_t count_filtered_inserted_mem_fns(const diff_context_sptr &)
Get the number of member functions insertions carried by the current diff node that were filtered out...
size_t count_filtered_deleted_mem_fns(const diff_context_sptr &)
Get the number of member functions deletions carried by the current diff node that were filtered out.
size_t get_inserted_non_static_data_members_number() const
Get the number of non static data members that were inserted.
The type of the private data of corpus_diff::diff_stats.
bool added_unreachable_type_is_suppressed(const type_base *t) const
Test if an added type that is unreachable from public interface has been suppressed by a suppression ...
void ensure_lookup_tables_populated()
If the lookup tables are not yet built, walk the differences and fill the lookup tables.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Get the sorted vector of diff nodes representing changed unreachable types.
diff_context_sptr get_context()
Getter of the context associated with this corpus.
void categorize_redundant_changed_sub_nodes()
Walk the changed functions and variables diff nodes to categorize redundant nodes.
bool added_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added variable symbol (that is not referenced by any debug inf...
bool lookup_tables_empty() const
Tests if the lookup tables are empty.
bool deleted_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted function symbol (that is not referenced by any debug i...
void apply_filters_and_compute_diff_stats(corpus_diff::diff_stats &)
Compute the diff stats.
bool added_variable_is_suppressed(const var_decl *var) const
Test if the change reports for a given added variable have been suppressed.
bool deleted_unreachable_type_is_suppressed(const type_base *t) const
Test if a deleted type that is unreachable from public interface has been suppressed by a suppression...
bool deleted_variable_is_suppressed(const var_decl *var) const
Test if the change reports for a give given deleted variable has been deleted.
bool deleted_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted variable symbol (that is not referenced by any debug i...
void maybe_dump_diff_tree()
If the user asked to dump the diff tree node (for changed variables and functions) on the error outpu...
void count_unreachable_types(size_t &num_added, size_t &num_removed, size_t &num_changed, size_t &num_filtered_added, size_t &num_filtered_removed, size_t &num_filtered_changed)
Count the number of types not reachable from the interface (i.e, not reachable from global functions ...
void clear_redundancy_categorization()
Walk the changed functions and variables diff nodes and clear the redundancy categorization they migh...
void count_leaf_changes(size_t &num_changes, size_t &num_filtered)
Count the number of leaf changes as well as the number of the changes that have been filtered out.
void count_leaf_type_changes(size_t &num_type_changes, size_t &num_type_changes_filtered)
Count the number of leaf *type* changes as well as the number of the leaf type changes that have been...
bool added_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added function symbol (that is not referenced by any debug inf...
bool deleted_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a given deleted function have been deleted.
void apply_supprs_to_added_removed_fns_vars_unreachable_types()
Apply suppression specifications for this corpus diff to the set of added/removed functions/variables...
void emit_diff_stats(const diff_stats &stats, ostream &out, const string &indent)
Emit the summary of the functions & variables that got removed/changed/added.
bool added_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a give given added function has been deleted.
void clear_lookup_tables()
Clear the lookup tables useful for reporting an enum_diff.
A comparison functor to compare two data members based on their offset.
A comparison functor to compare two instances of var_diff that represent changed data members based o...
A comparison functor for instances of diff.
A functor to compare two instances of diff_sptr.
The private data structure for distinct_diff.
A functor to compare instances of elf_symbol base on their names.
A functor to compare two enumerators based on their value. This implements the "less than" operator.
A comparison functor to compare two instances of fn_parm_diff based on their indexes.
"Less than" functor to compare instances of function_decl.
A "Less Than" functor to compare instance of function_decl_diff.
Functor that compares two function parameters for the purpose of sorting them.
The internal type for the impl idiom implementation of pointer_diff.
The internal type for the impl idiom implementation of subrange_diff.
A functor to compare instances of var_decl base on their qualified names.
The internal type for the impl idiom implementation of var_diff.
Functor to sort instances of var_diff_sptr.
A comparison functor for instances of function_decl_diff that represent changes between two virtual m...
An equality functor to deeply compare pointers.
A comparison functor to compare pointer to instances of type_or_decl_base.
Definition: abg-ir.h:3164
A deleter for shared pointers that ... doesn't delete the object managed by the shared pointer.