libabigail
Loading...
Searching...
No Matches
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-2026 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 <sstream>
16#include <set>
17
18#include "abg-comparison-priv.h"
19#include "abg-reporter-priv.h"
20#include "abg-tools-utils.h"
21#include "abg-ir-priv.h"
22
23namespace abigail
24{
25
26namespace comparison
27{
28
29///
30///
31///@defgroup DiffNode Internal Representation of the comparison engine
32/// @{
33///
34/// @brief How changes are represented in libabigail's comparison engine.
35///
36///@par diff nodes
37///
38/// The internal representation of the comparison engine is basically
39/// a graph of @ref instances of @ref diff node. We refer to these
40/// just as <em>diff nodes</em>. A diff node represents a change
41/// between two ABI artifacts represented by instances of types of the
42/// abigail::ir namespace. These two artifacts that are being
43/// compared are called the <em>subjects of the diff</em>.
44///
45/// The types of that IR are in the abigail::comparison namespace.
46///
47///@par comparing diff nodes
48///
49/// Comparing two instances of @ref diff nodes amounts to comparing
50/// the subject of the diff. In other words, two @ref diff nodes are
51/// equal if and only if their subjects are equal. Thus, two @ref
52/// diff nodes can have different memory addresses and yet be equal.
53///
54///@par diff reporting and context
55///
56/// A diff node can be serialized to an output stream to express, in
57/// a human-readable textual form, the different changes that exist
58/// between its two subjects. This is done by invoking the
59/// diff::report() method. That reporting is controlled by several
60/// parameters that are conceptually part of the context of the diff.
61/// That context is materialized by an instance of the @ref
62/// diff_context type.
63///
64/// Please note that the role of the instance(s) of @ref diff_context
65/// is boreader than just controlling the reporting of @ref diff
66/// nodes. Basically, a @ref diff node itself is created following
67/// behaviours that are controlled by a particular instance of
68/// diff_context. A diff node is created in a particular diff
69/// context, so to speak.
70///
71/// @}
72///
73
74///
75///@defgroup CanonicalDiff Canonical diff tree nodes
76/// @{
77///
78/// @brief How equivalent diff nodes are quickly spotted.
79///
80/// @par Equivalence of diff nodes.
81///
82/// Each @ref diff node has a property named <em>Canonical Diff
83/// Node</em>. If \c D is a diff node, the canonical diff node of @c
84/// D, noted @c C(D) is a particular diff node that is equal to @c D.
85/// Thus, a fast way to compare two @ref diff node is to perform a
86/// pointer comparison of their canonical diff nodes.
87///
88/// A set of equivalent @ref diff nodes is a set of diff nodes that
89/// all have the same canonical node. All the nodes of that set are
90/// equal.
91///
92/// A canonical node is registereded for a given diff node by invoking
93/// the method diff_context::initialize_canonical_diff().
94///
95/// Please note that the diff_context holds all the canonical diffs
96/// that got registered through it. Thus, the life time of all of
97/// canonical diff objects is the same as the life time of the @ref
98/// diff_context they relate to.
99///
100/// @}
101///
102
103// -----------------------------------------
104// <private functions re-usable elsewhere>
105// -----------------------------------------
106/// Sort a map of enumerators by their value.
107///
108/// @param enumerators_map the map to sort.
109///
110/// @param sorted the resulting vector of sorted enumerators.
111void
114{
115 for (string_enumerator_map::const_iterator i = enumerators_map.begin();
116 i != enumerators_map.end();
117 ++i)
118 sorted.push_back(i->second);
120 std::sort(sorted.begin(), sorted.end(), comp);
121}
122
123/// Sort a map of changed enumerators.
124///
125/// @param enumerators_map the map to sort.
126///
127///@param output parameter. The resulting sorted enumerators.
128void
131{
132 for (string_changed_enumerator_map::const_iterator i =
133 enumerators_map.begin();
134 i != enumerators_map.end();
135 ++i)
136 sorted.push_back(i->second);
137
139 std::sort(sorted.begin(), sorted.end(), comp);
140}
141
142/// Sort a map of data members by the offset of their initial value.
143///
144/// @param data_members the map of changed data members to sort.
145///
146/// @param sorted the resulting vector of sorted changed data members.
147void
149 vector<decl_base_sptr>& sorted)
150{
151 sorted.reserve(data_members.size());
152 for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
153 i != data_members.end();
154 ++i)
155 sorted.push_back(i->second);
156
157 data_member_comp comp;
158 std::sort(sorted.begin(), sorted.end(), comp);
159}
160
161/// Sort (in place) a vector of changed data members.
162///
163/// @param to_sort the vector to sort.
164void
166{
167 data_member_comp comp;
168 std::sort(to_sort.begin(), to_sort.end(), comp);
169}
170
171/// Get the ELF symbol associated to a decl.
172///
173/// Please note that ELF symbol are only associated to function or
174/// global variable decls. So for any other kind of decl, this
175/// function returns nullptr.
176///
177/// @param d the decl to consider.
178///
179/// @return the ELF symbol associated to @p if any or nullptr.
180static elf_symbol_sptr
181get_symbol(const decl_base_sptr& d)
182{
184 return fn->get_symbol();
185 else if (var_decl_sptr var = is_var_decl(d))
186 return var->get_symbol();
187
188 return elf_symbol_sptr();
189}
190
191/// Compare two decl diff nodes (@ref decl_diff_base) for the purpose
192/// of sorting.
193///
194/// @param first the first @ref decl_diff to consider.
195///
196/// @param second the second @ref function_decl_diff to consider.
197///
198/// @return true iff @p first compares less than @p second.
199bool
200is_less_than(const decl_diff_base& first, const decl_diff_base& second)
201{
202 decl_base_sptr f = is_decl(first.first_subject()),
203 s = is_decl(second.first_subject());
204
205 string fr = f->get_qualified_name(), sr = s->get_qualified_name();
206
207 if (fr != sr)
208 return fr < sr;
209
210 if (!f->get_linkage_name().empty()
211 && !s->get_linkage_name().empty())
212 {
213 fr = f->get_linkage_name();
214 sr = s->get_linkage_name();
215 if (fr != sr)
216 return fr < sr;
217 }
218
219 if (get_symbol(f) && get_symbol(s))
220 {
221 fr = get_symbol(f)->get_id_string();
222 sr = get_symbol(s)->get_id_string();
223 if (fr != sr)
224 return fr < sr;
225 }
226
227 fr = f->get_pretty_representation(true, true);
228 sr = s->get_pretty_representation(true, true);
229
230 return fr < sr;
231}
232
233/// Compare two decl diff nodes (@ref decl_diff_base) for the purpose
234/// of sorting.
235///
236/// @param first the first @ref decl_diff to consider.
237///
238/// @param second the second @ref function_decl_diff to consider.
239///
240/// @return true iff @p first compares less than @p second.
241bool
243 const decl_diff_base_sptr& second)
244{
245 if (!first || !second)
246 return false;
247
248 return is_less_than(*first, *second);
249}
250
251/// Sort an instance of @ref string_function_ptr_map map and stuff a
252/// resulting sorted vector of pointers to function_decl.
253///
254/// @param map the map to sort.
255///
256/// @param sorted the resulting sorted vector.
257void
259 vector<const function_decl*>& sorted)
260{
261 sorted.reserve(map.size());
262 for (string_function_ptr_map::const_iterator i = map.begin();
263 i != map.end();
264 ++i)
265 sorted.push_back(i->second);
266
267 function_comp comp;
268 std::sort(sorted.begin(), sorted.end(), comp);
269}
270
271/// Sort a map that's an instance of @ref
272/// string_member_function_sptr_map and fill a vector of member
273/// functions with the sorted result.
274///
275/// @param map the map to sort.
276///
277/// @param sorted the resulting sorted vector.
278void
281{
282 sorted.reserve(map.size());
283 for (string_member_function_sptr_map::const_iterator i = map.begin();
284 i != map.end();
285 ++i)
286 sorted.push_back(i->second);
287
288 function_comp comp;
289 std::sort(sorted.begin(), sorted.end(), comp);
290}
291
292/// Sort the values of a @ref string_function_decl_diff_sptr_map map
293/// and store the result in a vector of @ref function_decl_diff_sptr
294/// objects.
295///
296/// @param map the map whose values to store.
297///
298/// @param sorted the vector of function_decl_diff_sptr to store the
299/// result of the sort into.
300void
304{
305 sorted.reserve(map.size());
306 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
307 i != map.end();
308 ++i)
309 sorted.push_back(i->second);
311 std::sort(sorted.begin(), sorted.end(), comp);
312}
313
314/// Sort a vector of @ref function_decl_diff_sptr.
315///
316/// The comparison functor used is function_decl_diff_comp.
317///
318/// @param fn_diffs in/out parameter. The vector of @ref
319/// function_decl_diff_sptr to sort.
320void
322{
324 std::sort(fn_diffs.begin(), fn_diffs.end(), comp);
325}
326
327/// Sort of an instance of @ref string_var_diff_sptr_map map.
328///
329/// @param map the input map to sort.
330///
331/// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
332/// It's populated with the sorted content.
333void
335 var_diff_sptrs_type& sorted)
336{
337 sorted.reserve(map.size());
338 for (string_var_diff_sptr_map::const_iterator i = map.begin();
339 i != map.end();
340 ++i)
341 sorted.push_back(i->second);
342
344 std::sort(sorted.begin(), sorted.end(), comp);
345}
346
347/// Sort a vector of @ref var_diff_sptr.
348///
349/// The comparison functor used is @ref var_diff_sptr_comp.
350///
351/// @param var_diffs in/out parameter the vector of @ref var_diff_sptr
352/// to sort.
353void
355{
357 std::sort(var_diffs.begin(), var_diffs.end(), comp);
358}
359
360/// Sort a map of string -> pointer to @ref elf_symbol.
361///
362/// The result is a vector of @ref elf_symbol_sptr sorted by the
363/// name of the symbol.
364///
365/// @param map the map to sort.
366///
367/// @param sorted out parameter; the sorted vector of @ref
368/// elf_symbol_sptr.
369void
371 vector<elf_symbol_sptr>& sorted)
372{
373 for (string_elf_symbol_map::const_iterator i = map.begin();
374 i!= map.end();
375 ++i)
376 sorted.push_back(i->second);
377
378 elf_symbol_comp comp;
379 std::sort(sorted.begin(), sorted.end(), comp);
380}
381
382/// Sort a map of string -> pointer to @ref var_decl.
383///
384/// The result is a vector of var_decl* sorted by the qualified name
385/// of the variables.
386///
387/// @param map the map to sort.
388///
389/// @param sorted out parameter; the sorted vector of @ref var_decl.
390void
392 vector<var_decl_sptr>& sorted)
393{
394 for (string_var_ptr_map::const_iterator i = map.begin();
395 i != map.end();
396 ++i)
397 sorted.push_back(i->second);
398
399 var_comp comp;
400 std::sort(sorted.begin(), sorted.end(), comp);
401}
402
403/// Sort the values of a string_var_diff_sptr_map and store the result
404/// in a vector of var_diff_sptr.
405///
406/// @param map the map of changed data members to sort.
407///
408/// @param sorted the resulting vector of var_diff_sptr.
409void
411 var_diff_sptrs_type& sorted)
412{
413 sorted.reserve(map.size());
414 for (string_var_diff_sptr_map::const_iterator i = map.begin();
415 i != map.end();
416 ++i)
417 sorted.push_back(i->second);
419 std::sort(sorted.begin(), sorted.end(), comp);
420}
421
422/// Sort the values of a unsigned_var_diff_sptr_map map and store the
423/// result into a vector of var_diff_sptr.
424///
425/// @param map the map of changed data members to sort.
426///
427/// @param sorted the resulting vector of sorted var_diff_sptr.
428void
430 var_diff_sptrs_type& sorted)
431{
432 sorted.reserve(map.size());
433 for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
434 i != map.end();
435 ++i)
436 sorted.push_back(i->second);
438 std::sort(sorted.begin(), sorted.end(), comp);
439}
440
441/// Sort an map of string -> virtual member function into a vector of
442/// virtual member functions. The virtual member functions are sorted
443/// by increasing order of their virtual index.
444///
445/// @param map the input map.
446///
447/// @param sorted the resulting sorted vector of virtual function
448/// member.
449void
453{
454 sorted.reserve(map.size());
455 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
456 i != map.end();
457 ++i)
458 sorted.push_back(i->second);
459
461 sort(sorted.begin(), sorted.end(), comp);
462}
463
464/// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
465/// diff_sptr. The diff_sptr are sorted lexicographically wrt
466/// qualified names of their first subjects.
467///
468/// @param map the map to sort.
469///
470/// @param sorted the resulting sorted vector.
471void
473 diff_sptrs_type& sorted)
474{
475 sorted.reserve(map.size());
476 for (string_diff_sptr_map::const_iterator i = map.begin();
477 i != map.end();
478 ++i)
479 sorted.push_back(i->second);
480
481 diff_comp comp;
482 sort(sorted.begin(), sorted.end(), comp);
483}
484
485/// Sort a map ofg string -> @ref diff* into a vector of @ref
486/// diff_ptr. The diff_ptr are sorted lexicographically wrt
487/// qualified names of their first subjects.
488///
489/// @param map the map to sort.
490///
491/// @param sorted the resulting sorted vector.
492void
494 diff_ptrs_type& sorted)
495{
496 sorted.reserve(map.size());
497 for (string_diff_ptr_map::const_iterator i = map.begin();
498 i != map.end();
499 ++i)
500 sorted.push_back(i->second);
501
502 diff_comp comp;
503 sort(sorted.begin(), sorted.end(), comp);
504}
505
506/// Sort a map of string -> base_diff_sptr into a sorted vector of
507/// base_diff_sptr. The base_diff_sptr are sorted by increasing value
508/// of their offset in their containing type.
509///
510/// @param map the input map to sort.
511///
512/// @param sorted the resulting sorted vector.
513void
515 base_diff_sptrs_type& sorted)
516{
517 for (string_base_diff_sptr_map::const_iterator i = map.begin();
518 i != map.end();
519 ++i)
520 sorted.push_back(i->second);
521 base_diff_comp comp;
522 sort(sorted.begin(), sorted.end(), comp);
523}
524
525/// Lexicographically sort base specifications found
526/// in instances of string_base_sptr_map.
527void
530{
531 for (string_base_sptr_map::const_iterator i = m.begin();
532 i != m.end();
533 ++i)
534 sorted.push_back(i->second);
535
536 base_spec_comp comp;
537 std::sort(sorted.begin(), sorted.end(), comp);
538}
539
540/// Sort a map of @ref fn_parm_diff by the indexes of the function
541/// parameters.
542///
543/// @param map the map to sort.
544///
545/// @param sorted the resulting sorted vector of changed function
546/// parms.
547void
549 vector<fn_parm_diff_sptr>& sorted)
550{
551 sorted.reserve(map.size());
552 for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
553 i != map.end();
554 ++i)
555 sorted.push_back(i->second);
556
558 std::sort(sorted.begin(), sorted.end(), comp);
559}
560
561/// Sort a map of changed function parameters by the indexes of the
562/// function parameters.
563///
564/// @param map the map to sort.
565///
566/// @param sorted the resulting sorted vector of instances of @ref
567/// fn_parm_diff_sptr
568void
570 vector<fn_parm_diff_sptr>& sorted)
571{
572 sorted.reserve(map.size());
573 for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
574 i != map.end();
575 ++i)
576 sorted.push_back(i->second);
577
579 std::sort(sorted.begin(), sorted.end(), comp);
580}
581
582/// Sort a map of string -> function parameters.
583///
584/// @param map the map to sort.
585///
586/// @param sorted the resulting sorted vector of
587/// @ref vector<function_decl::parameter_sptr>
588void
590 vector<function_decl::parameter_sptr>& sorted)
591{
592 for (string_parm_map::const_iterator i = map.begin();
593 i != map.end();
594 ++i)
595 sorted.push_back(i->second);
596
597 parm_comp comp;
598 std::sort(sorted.begin(), sorted.end(), comp);
599}
600
601/// Sort the set of ABI artifacts contained in a @ref
602/// artifact_sptr_set_type.
603///
604/// @param set the set of ABI artifacts to sort.
605///
606/// @param output parameter the vector containing the sorted ABI
607/// artifacts.
608void
610 vector<type_or_decl_base_sptr>& sorted)
611{
612
613 for (artifact_sptr_set_type::const_iterator it = set.begin();
614 it != set.end();
615 ++it)
616 sorted.push_back(*it);
617
619 std::sort(sorted.begin(), sorted.end(), comp);
620}
621
622/// Sort a map of string to type_base_sptr entities.
623///
624/// The entries are sorted based on the lexicographic order of the
625/// pretty representation of the type_sptr_sptr. The sorted result is
626/// put in a vector of type_base_sptr.
627///
628/// @param map the map to sort.
629///
630/// @param sorted the resulting vector of type_base_sptr
631/// lexicographically sorted using their pretty representation.
632void
634 vector<type_base_sptr>& sorted)
635{
636 for (string_type_base_sptr_map::const_iterator i = map.begin();
637 i != map.end();
638 ++i)
639 sorted.push_back(i->second);
640
642 std::sort(sorted.begin(), sorted.end(), comp);
643}
644
645/// Return the first underlying type that is not a qualified type.
646/// @param t the qualified type to consider.
647///
648/// @return the first underlying type that is not a qualified type, or
649/// NULL if t is NULL.
650type_base_sptr
651get_leaf_type(qualified_type_def_sptr t)
652{
653 if (!t)
654 return type_base_sptr();
655
656 type_base_sptr ut = t->get_underlying_type();
657 qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
658
659 if (!qut)
660 return ut;
661 return get_leaf_type(qut);
662}
663
664/// Tests if a given diff node is to represent the changes between two
665/// gobal decls.
666///
667/// @param d the diff node to consider.
668///
669/// @return true iff @p d represents the changes between two global
670/// decls.
671bool
673{
674 ABG_ASSERT(d != 0);
675
676 if (d == 0)
677 return false;
678
680 ABG_ASSERT(first);
681
683 ABG_ASSERT(second);
684
685 if (decl_base_sptr decl = is_decl(first))
686 if (is_at_global_scope(decl))
687 if ((decl = is_decl(second)))
688 if (is_at_global_scope(decl))
689 return true;
690
691 return false;
692}
693
694// -----------------------------------------
695// </private functions re-usable elsewhere>
696// -----------------------------------------
697
698/// The overloaded or operator for @ref visiting_kind.
701{return static_cast<visiting_kind>(static_cast<unsigned>(l)
702 | static_cast<unsigned>(r));}
703
704/// The overloaded and operator for @ref visiting_kind.
707{
708 return static_cast<visiting_kind>(static_cast<unsigned>(l)
709 & static_cast<unsigned>(r));
710}
711
712/// The overloaded 'bit inversion' operator for @ref visiting_kind.
715{return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
716
717/// Test if a diff node is about differences between types.
718///
719/// @param diff the diff node to test.
720///
721/// @return a pointer to the actual type_diff_base* that @p diff
722/// extends, iff it is about differences between types.
723const type_diff_base*
725{return dynamic_cast<const type_diff_base*>(diff);}
726
727/// Test if a diff node is about differences between declarations.
728///
729/// @param diff the diff node to test.
730///
731/// @return a pointer to the actual decl_diff_base @p diff extends,
732/// iff it is about differences between declarations.
733const decl_diff_base*
735{return dynamic_cast<const decl_diff_base*>(diff);}
736
737/// Test if a diff node is a @ref class_diff node.
738///
739/// @param diff the diff node to consider.
740///
741/// @return a non-nil pointer to a @ref class_diff iff @p diff is a
742/// @ref class_diff node.
743const class_diff*
745{return dynamic_cast<const class_diff*>(diff);}
746
747/// Test if a diff node is a @ref enum_diff node.
748///
749/// @param diff the diff node to consider.
750///
751/// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
752/// a @ref enum_diff node.
753const enum_diff*
755{return dynamic_cast<const enum_diff*>(diff);}
756
757/// Test if a diff node is a @ref union_diff node.
758///
759/// @param diff the diff node to consider.
760///
761/// @return a non-nil pointer to a @ref union_diff iff @p diff is a
762/// @ref union_diff node.
763const union_diff*
765{return dynamic_cast<const union_diff*>(diff);}
766
767/// Test if a diff node is a @ref class_or_union_diff node.
768///
769/// @param d the diff node to consider.
770///
771/// @return a non-nil pointer to the @ref class_or_union_diff denoted
772/// by @p d iff @p d is a @ref class_or_union_diff.
775{return dynamic_cast<const class_or_union_diff*>(d);}
776
777/// Test if a diff node is a @ref class_or_union_diff between two
778/// anonymous classes or unions.
779///
780/// @param d the diff node to consider.
781///
782/// @return a non-nil pointer to the @ref class_or_union_diff denoted
783/// by @p d iff @p is a pointer to an anonymous class or union diff.
786{
788 if (dif->first_class_or_union()->get_is_anonymous())
789 return dif;
790 return 0;
791}
792
793/// Test if a diff node is a @ref typedef_diff node.
794///
795/// @param diff the diff node to consider.
796///
797/// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
798/// @ref typedef_diff node.
799const typedef_diff*
801{return dynamic_cast<const typedef_diff*>(diff);}
802
803/// Test if a diff node is a @ref subrange_diff node.
804///
805/// @param diff the diff node to consider.
806///
807/// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
808/// @ref subrange_diff node.
809const subrange_diff*
811{return dynamic_cast<const subrange_diff*>(diff);}
812
813/// Test if a diff node is a @ref subrange_diff between two anonymous
814/// subranges.
815///
816/// @param d the diff node to consider.
817///
818/// @return a non-nil pointer to the @ref subrange_diff denoted by @p
819/// d iff @p d is a pointer to an anonymous @ref subrange_diff.
820const subrange_diff*
822{
823 if (const subrange_diff* dif = is_subrange_diff(d))
824 if (dif->first_subrange()->get_is_anonymous())
825 return dif;
826
827 return nullptr;
828}
829
830/// Test if a diff node is a @ref array_diff node.
831///
832/// @param diff the diff node to consider.
833///
834/// @return a non-nil pointer to a @ref array_diff iff @p diff is a
835/// @ref array_diff node.
836const array_diff*
838{return dynamic_cast<const array_diff*>(diff);}
839
840/// Test if a diff node is a @ref function_type_diff node.
841///
842/// @param diff the diff node to consider.
843///
844/// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
845/// @ref function_type_diff node.
848{return dynamic_cast<const function_type_diff*>(diff);}
849
850/// Test if a given diff node carries a function type change with
851/// local changes.
852///
853/// @param diff the diff node to consider.
854///
855/// @return a non-nil pointer to a @ref function_type_diff iff @p diff
856/// is a function_type_diff node that carries a local change.
859{
861 if (d->has_local_changes())
862 return d;
863
864 return 0;
865}
866
867/// Test if a diff node is about differences between variables.
868///
869/// @param diff the diff node to test.
870///
871/// @return a pointer to the actual var_diff that @p diff is a type
872/// of, iff it is about differences between variables.
873const var_diff*
875{
876 const var_diff* d = dynamic_cast<const var_diff*>(diff);
877 if (d)
879 return d;
880}
881
882/// Test if a diff node is about differences between functions.
883///
884/// @param diff the diff node to test.
885///
886/// @return a pointer to the actual var_diff that @p diff is a type
887/// of, iff it is about differences between variables.
890{
891 const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
892 if (d)
894 return d;
895}
896
897/// Test if a diff node is about differences between two pointers.
898///
899/// @param diff the diff node to consider.
900///
901/// @return the @p diff converted into an instance of @ref
902/// pointer_diff iff @p diff is about differences between two
903/// pointers.
904const pointer_diff*
906{return dynamic_cast<const pointer_diff*>(diff);}
907
908/// Test if a diff node is about differences between two references.
909///
910/// @param diff the diff node to consider.
911///
912/// @return the @p diff converted into an instance of @ref
913/// reference_diff iff @p diff is about differences between two
914/// references.
915const reference_diff*
917{return dynamic_cast<const reference_diff*>(diff);}
918
919/// Test if a diff node is about differences between two qualified
920/// types.
921///
922/// @param diff the diff node to consider.
923///
924/// @return @p diff converted into an instance of @ref
925/// qualified_type_diff iff @p diff is about differences between two
926/// qualified types.
929{return dynamic_cast<const qualified_type_diff*>(diff);}
930
931/// Test if a diff node is a reference or pointer diff node to a
932/// change that is neither basic type change nor distinct type change.
933///
934/// Note that this function also works on diffs of typedefs of
935/// reference or pointer.
936///
937/// @param diff the diff node to consider.
938///
939/// @return true iff @p diff is a eference or pointer diff node to a
940/// change that is neither basic type change nor distinct type change.
941bool
943{
945 if (const reference_diff* d = is_reference_diff(diff))
946 {
949 return false;
950 return true;
951 }
952 else if (const pointer_diff *d = is_pointer_diff(diff))
953 {
956 return false;
957 return true;
958 }
959
960 return false;
961}
962
963/// Test if a diff node is about differences between two function
964/// parameters.
965///
966/// @param diff the diff node to consider.
967///
968/// @return the @p diff converted into an instance of @ref
969/// reference_diff iff @p diff is about differences between two
970/// function parameters.
971const fn_parm_diff*
973{return dynamic_cast<const fn_parm_diff*>(diff);}
974
975/// Test if a diff node is about differences between two base class
976/// specifiers.
977///
978/// @param diff the diff node to consider.
979///
980/// @return the @p diff converted into an instance of @ref base_diff
981/// iff @p diff is about differences between two base class
982/// specifiers.
983const base_diff*
985{return dynamic_cast<const base_diff*>(diff);}
986
987/// Test if a diff node is about differences between two diff nodes of
988/// different kinds.
989///
990/// @param diff the diff node to consider.
991///
992/// @return the @p diff converted into an instance of @ref
993/// distintc_diff iff @p diff is about differences between two diff
994/// nodes of different kinds.
995const distinct_diff*
997{return dynamic_cast<const distinct_diff*>(diff);}
998
999/// Test if a diff node is a @ref corpus_diff node.
1000///
1001/// @param diff the diff node to consider.
1002///
1003/// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
1004/// @ref corpus_diff node.
1005const corpus_diff*
1007{return dynamic_cast<const corpus_diff*>(diff);}
1008
1009/// Test if a diff node is a child node of a function parameter diff node.
1010///
1011/// @param diff the diff node to test.
1012///
1013/// @return true iff @p diff is a child node of a function parameter
1014/// diff node.
1015bool
1018
1019/// Test if a diff node is a child node of a base diff node.
1020///
1021/// @param diff the diff node to test.
1022///
1023/// @return true iff @p diff is a child node of a base diff node.
1024bool
1027
1028/// The default traverse function.
1029///
1030/// @return true.
1031bool
1034
1035diff_context::diff_context()
1036 : priv_(new diff_context::priv)
1037{
1038
1039 // By default, only the changes categorized as harmful are emitted.
1040 set_allowed_category(get_default_harmful_categories_bitmap());
1041
1042 // Setup all the diff output filters we have.
1044
1046 add_diff_filter(f);
1047
1048 // f.reset(new filtering::harmless_filter);
1049 // add_diff_filter(f);
1050
1051 // f.reset(new filtering::harmful_filter);
1052 // add_diff_filter(f);
1053}
1054
1055diff_context::~diff_context() = default;
1056
1057/// Test if logging was requested.
1058///
1059/// @return true iff logging was requested.
1060bool
1062{return priv_->do_log_;}
1063
1064/// Set logging as requested.
1065///
1066/// @param f the flag
1067void
1069{priv_->do_log_ = f;}
1070
1071/// Set the corpus diff relevant to this context.
1072///
1073/// @param d the corpus_diff we are interested in.
1074void
1076{priv_->corpus_diff_ = d;}
1077
1078/// Get the corpus diff for the current context.
1079///
1080/// @return the corpus diff of this context.
1081const corpus_diff_sptr&
1083{return priv_->corpus_diff_;}
1084
1085/// Getter for the first corpus of the corpus diff of the current context.
1086///
1087/// @return the first corpus of the corpus diff of the current
1088/// context, if no corpus diff is associated to the context.
1089corpus_sptr
1091{
1092 if (priv_->corpus_diff_)
1093 return priv_->corpus_diff_->first_corpus();
1094 return corpus_sptr();
1095}
1096
1097/// Getter for the second corpus of the corpus diff of the current
1098/// context.
1099///
1100/// @return the second corpus of the corpus diff of the current
1101/// context, if no corpus diff is associated to the context.
1102corpus_sptr
1104{
1105 if (priv_->corpus_diff_)
1106 return priv_->corpus_diff_->second_corpus();
1107 return corpus_sptr();
1108}
1109
1110/// Getter of the reporter to be used in this context.
1111///
1112/// @return the reporter to be used in this context.
1115{
1116 if (!priv_->reporter_)
1117 {
1119 priv_->reporter_.reset(new leaf_reporter);
1120 else
1121 priv_->reporter_.reset(new default_reporter);
1122 }
1123 ABG_ASSERT(priv_->reporter_);
1124 return priv_->reporter_;
1125}
1126
1127/// Setter of the reporter to be used in this context.
1128///
1129/// @param r the reporter to be used in this context.
1130void
1132{priv_->reporter_ = r;}
1133
1134/// Tests if the current diff context already has a diff for two decls.
1135///
1136/// @param first the first decl to consider.
1137///
1138/// @param second the second decl to consider.
1139///
1140/// @return a pointer to the diff for @p first @p second if found,
1141/// null otherwise.
1143diff_context::has_diff_for(const type_or_decl_base_sptr first,
1144 const type_or_decl_base_sptr second) const
1145{
1146 types_or_decls_diff_map_type::const_iterator i =
1147 priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1148 if (i != priv_->types_or_decls_diff_map.end())
1149 return i->second;
1150 return diff_sptr();
1151}
1152
1153/// Tests if the current diff context already has a diff for two types.
1154///
1155/// @param first the first type to consider.
1156///
1157/// @param second the second type to consider.
1158///
1159/// @return a pointer to the diff for @p first @p second if found,
1160/// null otherwise.
1162diff_context::has_diff_for_types(const type_base_sptr first,
1163 const type_base_sptr second) const
1164{return has_diff_for(first, second);}
1165
1166/// Tests if the current diff context already has a given diff.
1167///
1168///@param d the diff to consider.
1169///
1170/// @return a pointer to the diff found for @p d
1171const diff*
1172diff_context::has_diff_for(const diff* d) const
1173{return has_diff_for(d->first_subject(), d->second_subject()).get();}
1174
1175/// Tests if the current diff context already has a given diff.
1176///
1177///@param d the diff to consider.
1178///
1179/// @return a pointer to the diff found for @p d
1181diff_context::has_diff_for(const diff_sptr d) const
1182{return has_diff_for(d->first_subject(), d->second_subject());}
1183
1184/// Getter for the bitmap that represents the set of categories that
1185/// the user wants to see reported.
1186///
1187/// @return a bitmap that represents the set of categories that the
1188/// user wants to see reported.
1191{return priv_->allowed_category_;}
1192
1193/// Setter for the bitmap that represents the set of categories that
1194/// the user wants to see reported.
1195///
1196/// @param c a bitmap that represents the set of categories that the
1197/// user wants to see represented.
1198void
1200{priv_->allowed_category_ = c;}
1201
1202/// Setter for the bitmap that represents the set of categories that
1203/// the user wants to see reported
1204///
1205/// This function perform a bitwise or between the new set of
1206/// categories and the current ones, and then sets the current
1207/// categories to the result of the or.
1208///
1209/// @param c a bitmap that represents the set of categories that the
1210/// user wants to see represented.
1211void
1213{priv_->allowed_category_ = priv_->allowed_category_ | c;}
1214
1215/// Setter for the bitmap that represents the set of categories that
1216/// the user wants to see reported
1217///
1218/// This function actually unsets bits from the current categories.
1219///
1220/// @param c a bitmap that represents the set of categories to unset
1221/// from the current categories.
1222void
1224{priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1225
1226/// Add a diff for two decls to the cache of the current diff_context.
1227///
1228/// Doing this allows to later find the added diff from its two
1229/// subject decls.
1230///
1231/// @param first the first decl to consider.
1232///
1233/// @param second the second decl to consider.
1234///
1235/// @param the diff to add.
1236void
1237diff_context::add_diff(type_or_decl_base_sptr first,
1239 const diff_sptr d)
1240{priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1241
1242/// Add a diff tree node to the cache of the current diff_context
1243///
1244/// @param d the diff tree node to add.
1245void
1246diff_context::add_diff(const diff* d)
1247{
1248 if (d)
1249 {
1250 diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1251 add_diff(d->first_subject(), d->second_subject(), dif);
1252 }
1253}
1254
1255/// Add a diff tree node to the cache of the current diff_context
1256///
1257/// @param d the diff tree node to add.
1258void
1259diff_context::add_diff(const diff_sptr d)
1260{
1261 if (d)
1262 add_diff(d->first_subject(), d->second_subject(), d);
1263}
1264
1265/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1266/// @ref diff represented by their two subjects.
1267///
1268/// @param first the first subject of the diff.
1269///
1270/// @param second the second subject of the diff.
1271///
1272/// @return the canonical diff for the diff node represented by the
1273/// two diff subjects @p first and @p second. If no canonical diff
1274/// node was registered for these subjects, then a nil node is
1275/// returned.
1278 const type_or_decl_base_sptr second) const
1279{return has_diff_for(first, second);}
1280
1281/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1282/// @ref diff represented by the two subjects of a given diff node.
1283///
1284/// @param d the diff node to get the canonical node for.
1285///
1286/// @return the canonical diff for the diff node represented by the
1287/// two diff subjects of @p d. If no canonical diff node was
1288/// registered for these subjects, then a nil node is returned.
1291{return has_diff_for(d);}
1292
1293/// Setter for the @ref CanonicalDiff "canonical diff node" for the
1294/// @ref diff represented by their two subjects.
1295///
1296/// @param first the first subject of the diff.
1297///
1298/// @param second the second subject of the diff.
1299///
1300/// @param d the new canonical diff.
1301void
1302diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1303 const type_or_decl_base_sptr second,
1304 const diff_sptr d)
1305{
1306 ABG_ASSERT(d);
1307 if (!has_diff_for(first, second))
1308 {
1309 add_diff(first, second, d);
1310 priv_->canonical_diffs.push_back(d);
1311 }
1312}
1313
1314/// If there is is a @ref CanonicalDiff "canonical diff node"
1315/// registered for two diff subjects, return it. Otherwise, register
1316/// a canonical diff node for these two diff subjects and return it.
1317///
1318/// @param first the first subject of the diff.
1319///
1320/// @param second the second subject of the diff.
1321///
1322/// @param d the new canonical diff node.
1323///
1324/// @return the canonical diff node.
1326diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1327 const type_or_decl_base_sptr second,
1328 const diff_sptr canonical_diff)
1329{
1330 ABG_ASSERT(canonical_diff);
1331
1332 diff_sptr canonical = get_canonical_diff_for(first, second);
1333 if (!canonical)
1334 {
1335 canonical = canonical_diff;
1336 set_canonical_diff_for(first, second, canonical);
1337 }
1338 return canonical;
1339}
1340
1341/// Set the canonical diff node property of a given diff node
1342/// appropriately.
1343///
1344/// For a given diff node that has no canonical diff node, retrieve
1345/// the canonical diff node (by looking at its diff subjects and at
1346/// the current context) and set the canonical diff node property of
1347/// the diff node to that canonical diff node. If no canonical diff
1348/// node has been registered to the diff context for the subjects of
1349/// the diff node then, register the canonical diff node as being the
1350/// diff node itself; and set its canonical diff node property as
1351/// such. Otherwise, if the diff node already has a canonical diff
1352/// node, do nothing.
1353///
1354/// @param diff the diff node to initialize the canonical diff node
1355/// property for.
1356void
1358{
1359 if (diff->get_canonical_diff() == 0)
1360 {
1361 diff_sptr canonical =
1362 set_or_get_canonical_diff_for(diff->first_subject(),
1364 diff);
1365 diff->set_canonical_diff(canonical.get());
1366 }
1367}
1368
1369/// Add a diff node to the set of diff nodes that are kept alive for
1370/// the life time of the current instance of diff_context.
1371///
1372/// Note that diff added to the diff cache are kept alive as well, and
1373/// don't need to be passed to this function to be kept alive.
1374///
1375/// @param d the diff node to be kept alive during the life time of
1376/// the current instance of @ref diff_context.
1377void
1379{priv_->live_diffs_.insert(d);}
1380
1381/// Test if a diff node has been traversed.
1382///
1383/// @param d the diff node to consider.
1384///
1385/// @return the first diff node against which @p d is redundant.
1386diff*
1388{
1389 const diff* canonical = d->get_canonical_diff();
1390 ABG_ASSERT(canonical);
1391
1392 size_t ptr_value = reinterpret_cast<size_t>(canonical);
1393 pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1394 if (it != priv_->visited_diff_nodes_.end())
1395 return reinterpret_cast<diff*>(it->second);
1396 else
1397 return 0;
1398}
1399
1400/// Test if a diff node has been traversed.
1401///
1402/// @param d the diff node to consider.
1403///
1404/// @return the first diff node against which @p d is redundant.
1407{
1409 return diff;
1410}
1411
1412/// Mark a diff node as traversed by a traversing algorithm.
1413///
1414/// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1415/// node that is marked as traversed.
1416///
1417/// Subsequent invocations of diff_has_been_visited() on the diff node
1418/// will yield true.
1419void
1421{
1422 if (diff_has_been_visited(d))
1423 return;
1424
1425 const diff* canonical = d->get_canonical_diff();
1426 ABG_ASSERT(canonical);
1427
1428 size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1429 size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1430 priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1431}
1432
1433/// Unmark all the diff nodes that were marked as being traversed.
1434void
1436{priv_->visited_diff_nodes_.clear();}
1437
1438/// This sets a flag that, if it's true, then during the traversing of
1439/// a diff nodes tree each node is visited at most once.
1440///
1441/// @param f if true then during the traversing of a diff nodes tree
1442/// each node is visited at most once.
1443///
1444void
1446{priv_->forbid_visiting_a_node_twice_ = f;}
1447
1448/// This function sets a flag os that if @ref
1449/// forbid_visiting_a_node_twice() returns true, then each time the
1450/// node visitor starts visiting a new interface, it resets the
1451/// memory the systems has about already visited node.
1452///
1453/// @param f the flag to set.
1454void
1456{priv_->reset_visited_diffs_for_each_interface_ = f;}
1457
1458/// Return a flag that, if true, then during the traversing of a diff
1459/// nodes tree each node is visited at most once.
1460///
1461/// @return the boolean flag.
1462bool
1464{return priv_->forbid_visiting_a_node_twice_;}
1465
1466/// Return a flag that, if true, then during the traversing of a diff
1467/// nodes tree each node is visited at most once, while visiting the
1468/// diff tree underneath a given interface (public function or
1469/// variable). Each time a new interface is visited, the nodes
1470/// visited while visiting previous interfaces can be visited again.
1471///
1472/// @return the boolean flag.
1473///
1474/// @return the boolean flag.
1475bool
1477{
1478 return (priv_->forbid_visiting_a_node_twice_
1479 && priv_->reset_visited_diffs_for_each_interface_);
1480}
1481
1482/// Getter for the diff tree nodes filters to apply to diff sub-trees.
1483///
1484/// @return the vector of tree filters to apply to diff sub-trees.
1485const filtering::filters&
1487{return priv_->filters_;}
1488
1489/// Setter for the diff filters to apply to a given diff sub-tree.
1490///
1491/// @param f the new diff filter to add to the vector of diff filters
1492/// to apply to diff sub-trees.
1493void
1495{priv_->filters_.push_back(f);}
1496
1497/// Apply the diff filters to a given diff sub-tree.
1498///
1499/// If the current context is instructed to filter out some categories
1500/// then this function walks the given sub-tree and categorizes its
1501/// nodes by using the filters held by the context.
1502///
1503/// @param diff the diff sub-tree to apply the filters to.
1504void
1506{
1507 if (!diff)
1508 return;
1509
1510 if (!diff->has_changes())
1511 return;
1512
1513 for (filtering::filters::const_iterator i = diff_filters().begin();
1514 i != diff_filters().end();
1515 ++i)
1516 {
1518 if (do_log())
1519 {
1520 std::cerr << "applying a filter to diff '"
1522 << "'...\n";
1523 t.start();
1524 }
1525
1527
1528 if (do_log())
1529 {
1530 t.stop();
1531 std::cerr << "filter applied in:" << t << "\n";
1532
1533 std::cerr << "propagating categories for the same diff node ... \n";
1534 t.start();
1535 }
1536
1538
1539 if (do_log())
1540 {
1541 t.stop();
1542 std::cerr << "categories propagated in: " << t << "\n";
1543 }
1544 }
1545
1546 }
1547
1548/// Apply the diff filters to the diff nodes of a @ref corpus_diff
1549/// instance.
1550///
1551/// If the current context is instructed to filter out some categories
1552/// then this function walks the diff tree and categorizes its nodes
1553/// by using the filters held by the context.
1554///
1555/// @param diff the corpus diff to apply the filters to.
1556void
1558{
1559
1560 if (!diff || !diff->has_changes())
1561 return;
1562
1563 for (filtering::filters::const_iterator i = diff_filters().begin();
1564 i != diff_filters().end();
1565 ++i)
1566 {
1569 }
1570}
1571
1572/// Getter for the vector of suppressions that specify which diff node
1573/// reports should be dropped on the floor.
1574///
1575/// @return the set of suppressions.
1576const suppressions_type&
1578{return priv_->suppressions_;}
1579
1580/// Getter for the vector of suppressions that specify which diff node
1581/// reports should be dropped on the floor.
1582///
1583/// @return the set of suppressions.
1586{
1587 // Invalidate negated and direct suppressions caches that are built
1588 // from priv_->suppressions_;
1589 priv_->negated_suppressions_.clear();
1590 priv_->direct_suppressions_.clear();
1591 return priv_->suppressions_;
1592}
1593
1594/// Getter of the negated suppression specifications that are
1595/// comprised in the general vector of suppression specifications
1596/// returned by diff_context::suppressions().
1597///
1598/// Note that the first invocation of this function scans the vector
1599/// returned by diff_context::suppressions() and caches the negated
1600/// suppressions from there.
1601///
1602/// Subsequent invocations of this function just return the cached
1603/// negated suppressions.
1604///
1605/// @return the negated suppression specifications stored in this diff
1606/// context.
1609{
1610 if (priv_->negated_suppressions_.empty())
1611 for (auto s : suppressions())
1613 priv_->negated_suppressions_.push_back(s);
1614
1615 return priv_->negated_suppressions_;
1616}
1617
1618/// Getter of the direct suppression specification (those that are
1619/// not negated) comprised in the general vector of suppression
1620/// specifications returned by diff_context::suppression().
1621///
1622/// Note that the first invocation of this function scans the vector
1623/// returned by diff_context::suppressions() and caches the direct
1624/// suppressions from there.
1625///
1626/// Subsequent invocations of this function just return the cached
1627/// direct suppressions.
1628///
1629/// @return the direct suppression specifications.
1632{
1633 if (priv_->direct_suppressions_.empty())
1634 {
1635 for (auto s : suppressions())
1636 if (!is_negated_suppression(s))
1637 priv_->direct_suppressions_.push_back(s);
1638 }
1639 return priv_->direct_suppressions_;
1640}
1641
1642/// Add a new suppression specification that specifies which diff node
1643/// reports should be dropped on the floor.
1644///
1645/// @param suppr the new suppression specification to add to the
1646/// existing set of suppressions specifications of the diff context.
1647void
1649{
1650 priv_->suppressions_.push_back(suppr);
1651 // Invalidate negated and direct suppressions caches that are built
1652 // from priv_->suppressions_;
1653 priv_->negated_suppressions_.clear();
1654 priv_->direct_suppressions_.clear();
1655}
1656
1657/// Add new suppression specifications that specify which diff node
1658/// reports should be dropped on the floor.
1659///
1660/// @param supprs the new suppression specifications to add to the
1661/// existing set of suppression specifications of the diff context.
1662void
1664{
1665 priv_->suppressions_.insert(priv_->suppressions_.end(),
1666 supprs.begin(), supprs.end());
1667}
1668
1669/// Test if it's requested to perform diff node categorization.
1670///
1671/// @return true iff it's requested to perform diff node
1672/// categorization.
1673bool
1675{return priv_->perform_change_categorization_;}
1676
1677/// Request change categorization or not.
1678///
1679/// @param f true iff change categorization is requested.
1680void
1682{priv_->perform_change_categorization_ = f;}
1683
1684/// Set the flag that indicates if the diff using this context should
1685/// show only leaf changes or not.
1686///
1687/// @param f the new value of the flag that indicates if the diff
1688/// using this context should show only leaf changes or not.
1689void
1691{
1692 // This function can be called only if the reporter hasn't yet been
1693 // created. Once it's been created, we are supposed to live with
1694 // it.
1695 ABG_ASSERT(priv_->reporter_ == 0);
1696 priv_->leaf_changes_only_ = f;
1697}
1698
1699/// Get the flag that indicates if the diff using this context should
1700/// show only leaf changes or not.
1701///
1702/// @return the value of the flag that indicates if the diff using
1703/// this context should show only leaf changes or not.
1704bool
1706{return priv_->leaf_changes_only_;}
1707
1708/// Get the flag that indicates if the diff reports using this context
1709/// should show sizes and offsets in an hexadecimal base or not. If
1710/// not, then they are to be shown in a decimal base.
1711///
1712/// @return true iff sizes and offsets are to be shown in an
1713/// hexadecimal base.
1714bool
1716{return priv_->hex_values_;}
1717
1718/// Set the flag that indicates if diff reports using this context
1719/// should show sizes and offsets in an hexadecimal base or not. If
1720/// not, then they are to be shown in a decimal base.
1721///
1722/// @param f if true then sizes and offsets are to be shown in an
1723/// hexadecimal base.
1724void
1726{priv_->hex_values_ = f;}
1727
1728/// Get the flag that indicates if diff reports using this context
1729/// should show sizes and offsets in bits, rather than bytes.
1730///
1731/// @return true iff sizes and offsets are to be shown in bits.
1732/// Otherwise they are to be shown in bytes.
1733bool
1735{return priv_->show_offsets_sizes_in_bits_;}
1736
1737/// Set the flag that indicates if diff reports using this context
1738/// should show sizes and offsets in bits, rather than bytes.
1739///
1740/// @param f if true then sizes and offsets are to be shown in bits.
1741/// Otherwise they are to be shown in bytes.
1742void
1744{priv_->show_offsets_sizes_in_bits_ = f;}
1745
1746/// Set a flag saying if offset changes should be reported in a
1747/// relative way. That is, if the report should say how of many bits
1748/// a class/struct data member did move.
1749///
1750/// @param f the new boolean value of the flag.
1751void
1753{priv_->show_relative_offset_changes_ = f;}
1754
1755/// Get the flag saying if offset changes should be reported in a
1756/// relative way. That is, if the report should say how of many bits
1757/// a class/struct data member did move.
1758///
1759/// @return the boolean value of the flag.
1760bool
1762{return priv_->show_relative_offset_changes_;}
1763
1764/// Set a flag saying if the comparison module should only show the
1765/// diff stats.
1766///
1767/// @param f the flag to set.
1768void
1770{priv_->show_stats_only_ = f;}
1771
1772/// Test if the comparison module should only show the diff stats.
1773///
1774/// @return true if the comparison module should only show the diff
1775/// stats, false otherwise.
1776bool
1778{return priv_->show_stats_only_;}
1779
1780/// Setter for the property that says if the comparison module should
1781/// show the soname changes in its report.
1782///
1783/// @param f the new value of the property.
1784void
1786{priv_->show_soname_change_ = f;}
1787
1788/// Getter for the property that says if the comparison module should
1789/// show the soname changes in its report.
1790///
1791/// @return the value of the property.
1792bool
1794{return priv_->show_soname_change_;}
1795
1796/// Setter for the property that says if the comparison module should
1797/// show the architecture changes in its report.
1798///
1799/// @param f the new value of the property.
1800void
1802{priv_->show_architecture_change_ = f;}
1803
1804/// Getter for the property that says if the comparison module should
1805/// show the architecture changes in its report.
1806///
1807/// @return the value of the property.
1808bool
1810{return priv_->show_architecture_change_;}
1811
1812/// Set a flag saying to show the deleted functions.
1813///
1814/// @param f true to show deleted functions.
1815void
1817{priv_->show_deleted_fns_ = f;}
1818
1819/// @return true if we want to show the deleted functions, false
1820/// otherwise.
1821bool
1823{return priv_->show_deleted_fns_;}
1824
1825/// Set a flag saying to show the changed functions.
1826///
1827/// @param f true to show the changed functions.
1828void
1830{priv_->show_changed_fns_ = f;}
1831
1832/// @return true if we want to show the changed functions, false otherwise.
1833bool
1835{return priv_->show_changed_fns_;}
1836
1837/// Set a flag saying to show the added functions.
1838///
1839/// @param f true to show the added functions.
1840void
1842{priv_->show_added_fns_ = f;}
1843
1844/// @return true if we want to show the added functions, false
1845/// otherwise.
1846bool
1848{return priv_->show_added_fns_;}
1849
1850/// Set a flag saying to show the deleted variables.
1851///
1852/// @param f true to show the deleted variables.
1853void
1855{priv_->show_deleted_vars_ = f;}
1856
1857/// @return true if we want to show the deleted variables, false
1858/// otherwise.
1859bool
1861{return priv_->show_deleted_vars_;}
1862
1863/// Set a flag saying to show the changed variables.
1864///
1865/// @param f true to show the changed variables.
1866void
1868{priv_->show_changed_vars_ = f;}
1869
1870/// @return true if we want to show the changed variables, false otherwise.
1871bool
1873{return priv_->show_changed_vars_;}
1874
1875/// Set a flag saying to show the added variables.
1876///
1877/// @param f true to show the added variables.
1878void
1880{priv_->show_added_vars_ = f;}
1881
1882/// @return true if we want to show the added variables, false
1883/// otherwise.
1884bool
1886{return priv_->show_added_vars_;}
1887
1888/// Set whether to show the number of filtered data members.
1889///
1890/// @param f the value of the flag.
1891void
1893{priv_->show_num_filtered_data_members_ = f;}
1894
1895/// Get whether to show the number of filtered data members.
1896///
1897/// @return the value of the flag.
1898bool
1900{return priv_->show_num_filtered_data_members_;}
1901
1902bool
1903diff_context::show_linkage_names() const
1904{return priv_->show_linkage_names_;}
1905
1906void
1907diff_context::show_linkage_names(bool f)
1908{priv_->show_linkage_names_= f;}
1909
1910/// Set a flag saying to show location information.
1911///
1912/// @param f true to show location information.
1913void
1915{priv_->show_locs_= f;}
1916
1917/// @return true if we want to show location information, false
1918/// otherwise.
1919bool
1921{return priv_->show_locs_;}
1922
1923/// A getter for the flag that says if we should report about
1924/// functions or variables diff nodes that have *exclusively*
1925/// redundant diff tree children nodes.
1926///
1927/// @return the flag.
1928bool
1930{return priv_->show_redundant_changes_;}
1931
1932/// A setter for the flag that says if we should report about
1933/// functions or variables diff nodes that have *exclusively*
1934/// redundant diff tree children nodes.
1935///
1936/// @param f the flag to set.
1937void
1939{
1940 priv_->show_redundant_changes_ = f;
1941
1942 if (priv_->show_redundant_changes_)
1944 else
1946}
1947
1948/// Getter for the flag that indicates if symbols not referenced by
1949/// any debug info are to be compared and reported about.
1950///
1951/// @return the boolean flag.
1952bool
1954{return priv_->show_syms_unreferenced_by_di_;}
1955
1956/// Setter for the flag that indicates if symbols not referenced by
1957/// any debug info are to be compared and reported about.
1958///
1959/// @param f the new flag to set.
1960void
1962{priv_->show_syms_unreferenced_by_di_ = f;}
1963
1964/// Getter for the flag that indicates if symbols not referenced by
1965/// any debug info and that got added are to be reported about.
1966///
1967/// @return true iff symbols not referenced by any debug info and that
1968/// got added are to be reported about.
1969bool
1971{return priv_->show_added_syms_unreferenced_by_di_;}
1972
1973/// Setter for the flag that indicates if symbols not referenced by
1974/// any debug info and that got added are to be reported about.
1975///
1976/// @param f the new flag that says if symbols not referenced by any
1977/// debug info and that got added are to be reported about.
1978void
1980{priv_->show_added_syms_unreferenced_by_di_ = f;}
1981
1982/// Setter for the flag that indicates if changes on types unreachable
1983/// from global functions and variables are to be reported.
1984///
1985/// @param f if true, then changes on types unreachable from global
1986/// functions and variables are to be reported.
1987void
1989{priv_->show_unreachable_types_ = f;}
1990
1991/// Getter for the flag that indicates if changes on types unreachable
1992/// from global functions and variables are to be reported.
1993///
1994/// @return true iff changes on types unreachable from global
1995/// functions and variables are to be reported.
1996bool
1998{return priv_->show_unreachable_types_;}
1999
2000/// Getter of the flag that indicates if the leaf reporter should
2001/// display a summary of the interfaces impacted by a given leaf
2002/// change or not.
2003///
2004/// @return the flag that indicates if the leaf reporter should
2005/// display a summary of the interfaces impacted by a given leaf
2006/// change or not.
2007bool
2009{return priv_->show_impacted_interfaces_;}
2010
2011/// Setter of the flag that indicates if the leaf reporter should
2012/// display a summary of the interfaces impacted by a given leaf
2013/// change or not.
2014///
2015/// @param f the new value of the flag that indicates if the leaf
2016/// reporter should display a summary of the interfaces impacted by a
2017/// given leaf change or not.
2018void
2020{priv_->show_impacted_interfaces_ = f;}
2021
2022/// Setter for the default output stream used by code of the
2023/// comparison engine. By default the default output stream is a NULL
2024/// pointer.
2025///
2026/// @param o a pointer to the default output stream.
2027void
2029{priv_->default_output_stream_ = o;}
2030
2031/// Getter for the default output stream used by code of the
2032/// comparison engine. By default the default output stream is a NULL
2033/// pointer.
2034///
2035/// @return a pointer to the default output stream.
2036ostream*
2038{return priv_->default_output_stream_;}
2039
2040/// Setter for the errror output stream used by code of the comparison
2041/// engine. By default the error output stream is a NULL pointer.
2042///
2043/// @param o a pointer to the error output stream.
2044void
2046{priv_->error_output_stream_ = o;}
2047
2048/// Getter for the errror output stream used by code of the comparison
2049/// engine. By default the error output stream is a NULL pointer.
2050///
2051/// @return a pointer to the error output stream.
2052ostream*
2054{return priv_->error_output_stream_;}
2055
2056/// Test if the comparison engine should dump the diff tree for the
2057/// changed functions and variables it has.
2058///
2059/// @return true if after the comparison, the engine should dump the
2060/// diff tree for the changed functions and variables it has.
2061bool
2063{return priv_->dump_diff_tree_;}
2064
2065/// Set if the comparison engine should dump the diff tree for the
2066/// changed functions and variables it has.
2067///
2068/// @param f true if after the comparison, the engine should dump the
2069/// diff tree for the changed functions and variables it has.
2070void
2072{priv_->dump_diff_tree_ = f;}
2073
2074/// Emit a textual representation of a diff tree to the error output
2075/// stream of the current context, for debugging purposes.
2076///
2077/// @param d the diff tree to serialize to the error output associated
2078/// to the current instance of @ref diff_context.
2079void
2085
2086/// Emit a textual representation of a @ref corpus_diff tree to the error
2087/// output stream of the current context, for debugging purposes.
2088///
2089/// @param d the @ref corpus_diff tree to serialize to the error
2090/// output associated to the current instance of @ref diff_context.
2091void
2097// </diff_context stuff>
2098
2099// <diff stuff>
2100
2101/// Constructor for the @ref diff type.
2102///
2103/// This constructs a diff between two subjects that are actually
2104/// declarations; the first and the second one.
2105///
2106/// @param first_subject the first decl (subject) of the diff.
2107///
2108/// @param second_subject the second decl (subject) of the diff.
2109diff::diff(type_or_decl_base_sptr first_subject,
2110 type_or_decl_base_sptr second_subject)
2111 : priv_(new priv(first_subject, second_subject,
2114 /*reported_once=*/false,
2115 /*currently_reporting=*/false))
2116{}
2117
2118/// Constructor for the @ref diff type.
2119///
2120/// This constructs a diff between two subjects that are actually
2121/// declarations; the first and the second one.
2122///
2123/// @param first_subject the first decl (subject) of the diff.
2124///
2125/// @param second_subject the second decl (subject) of the diff.
2126///
2127/// @param ctxt the context of the diff. Note that this context
2128/// object must stay alive during the entire life time of the current
2129/// instance of @ref diff. Otherwise, memory corruption issues occur.
2130diff::diff(type_or_decl_base_sptr first_subject,
2131 type_or_decl_base_sptr second_subject,
2132 diff_context_sptr ctxt)
2133 : priv_(new priv(first_subject, second_subject,
2134 ctxt, NO_CHANGE_CATEGORY,
2135 /*reported_once=*/false,
2136 /*currently_reporting=*/false))
2137{}
2138
2139/// Test if logging was requested
2140///
2141/// @return true iff logging was requested.
2142bool
2144{return context()->do_log();}
2145
2146/// Request logging (or not)
2147///
2148/// @param f true iff logging is to be requested.
2149void
2151{context()->do_log(f);}
2152
2153/// Flag a given diff node as being traversed.
2154///
2155/// For certain diff nodes like @ref class_diff, it's important to
2156/// avoid traversing the node again while it's already being
2157/// traversed; otherwise this leads to infinite loops. So the
2158/// diff::begin_traversing() and diff::end_traversing() methods flag a
2159/// given node as being traversed (or not), so that
2160/// diff::is_traversing() can tell if the node is being traversed.
2161///
2162/// Note that traversing a node means visiting it *and* visiting its
2163/// children nodes.
2164///
2165/// The canonical node is marked as being traversed too.
2166///
2167/// These functions are called by the traversing code.
2168void
2170{
2172 if (priv_->canonical_diff_)
2173 priv_->canonical_diff_->priv_->traversing_ = true;
2174 priv_->traversing_ = true;
2175}
2176
2177/// Tell if a given node is being traversed or not.
2178///
2179/// Note that traversing a node means visiting it *and* visiting its
2180/// children nodes.
2181///
2182/// It's the canonical node which is looked at, actually.
2183///
2184/// Please read the comments for the diff::begin_traversing() for mode
2185/// context.
2186///
2187/// @return true if the current instance of @diff is being traversed.
2188bool
2190{
2191 if (priv_->canonical_diff_)
2192 return priv_->canonical_diff_->priv_->traversing_;
2193 return priv_->traversing_;
2194}
2195
2196/// Flag a given diff node as not being traversed anymore.
2197///
2198/// Note that traversing a node means visiting it *and* visiting its
2199/// children nodes.
2200///
2201/// Please read the comments of the function diff::begin_traversing()
2202/// for mode context.
2203void
2205{
2207 if (priv_->canonical_diff_)
2208 priv_->canonical_diff_->priv_->traversing_ = false;
2209 priv_->traversing_ = false;
2210}
2211
2212/// Finish the insertion of a diff tree node into the diff graph.
2213///
2214/// This function might be called several times. It must perform the
2215/// insertion only once.
2216///
2217/// For instance, certain kinds of diff tree node have specific
2218/// children nodes that are populated after the constructor of the
2219/// diff tree node has been called. In that case, calling overloads
2220/// of this method ensures that these children nodes are properly
2221/// gathered and setup.
2222void
2224{
2225 if (diff::priv_->finished_)
2226 return;
2228 diff::priv_->finished_ = true;
2229}
2230
2231/// Getter of the first subject of the diff.
2232///
2233/// @return the first subject of the diff.
2236{return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2237
2238/// Getter of the second subject of the diff.
2239///
2240/// @return the second subject of the diff.
2243{return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2244
2245/// Getter for the children nodes of the current @ref diff node.
2246///
2247/// @return a vector of the children nodes.
2248const vector<diff*>&
2250{return priv_->children_;}
2251
2252/// Getter for the parent node of the current @ref diff node.
2253///
2254/// @return the parent node of the current @ref diff node.
2255const diff*
2257{return priv_->parent_;}
2258
2259/// Getter for the canonical diff of the current instance of @ref
2260/// diff.
2261///
2262/// Note that the canonical diff node for the current instanc eof diff
2263/// node must have been set by invoking
2264/// class_diff::initialize_canonical_diff() on the current instance of
2265/// diff node.
2266///
2267/// @return the canonical diff node or null if none was set.
2268diff*
2270{return priv_->canonical_diff_;}
2271
2272/// Setter for the canonical diff of the current instance of @ref
2273/// diff.
2274///
2275/// @param d the new canonical node to set.
2276void
2278{priv_->canonical_diff_ = d;}
2279
2280/// Add a new child node to the vector of children nodes for the
2281/// current @ref diff node.
2282///
2283/// @param d the new child node to add to the children nodes.
2284void
2286{
2287 ABG_ASSERT(d);
2288
2289 // Ensure 'd' is kept alive for the life time of the context of this
2290 // diff.
2291 context()->keep_diff_alive(d);
2292
2293 // Add the underlying pointer of 'd' to the vector of children.
2294 // Note that this vector holds no reference to 'd'. This is to avoid
2295 // reference cycles. The reference to 'd' is held by the context of
2296 // this diff, thanks to the call to context()->keep_diff_alive(d)
2297 // above.
2298 priv_->children_.push_back(d.get());
2299
2300 d->priv_->parent_ = this;
2301}
2302
2303/// Getter of the context of the current diff.
2304///
2305/// @return the context of the current diff.
2308{return priv_->get_context();}
2309
2310/// Setter of the context of the current diff.
2311///
2312/// @param c the new context to set.
2313void
2315{priv_->ctxt_ = c;}
2316
2317/// Tests if we are currently in the middle of emitting a report for
2318/// this diff.
2319///
2320/// @return true if we are currently emitting a report for the
2321/// current diff, false otherwise.
2322bool
2324{
2325 if (priv_->canonical_diff_)
2326 return priv_->canonical_diff_->priv_->currently_reporting_;
2327 return priv_->currently_reporting_;
2328}
2329
2330/// Sets a flag saying if we are currently in the middle of emitting
2331/// a report for this diff.
2332///
2333/// @param f true if we are currently emitting a report for the
2334/// current diff, false otherwise.
2335void
2337{
2338 if (priv_->canonical_diff_)
2339 priv_->canonical_diff_->priv_->currently_reporting_ = f;
2340 priv_->currently_reporting_ = f;
2341}
2342
2343/// Tests if a report has already been emitted for the current diff.
2344///
2345/// @return true if a report has already been emitted for the
2346/// current diff, false otherwise.
2347bool
2349{
2350 ABG_ASSERT(priv_->canonical_diff_);
2351 return priv_->canonical_diff_->priv_->reported_once_;
2352}
2353
2354/// The generic traversing code that walks a given diff sub-tree.
2355///
2356/// Note that there is a difference between traversing a diff node and
2357/// visiting it. Basically, traversing a diff node means visiting it
2358/// and visiting its children nodes too. So one can visit a node
2359/// without traversing it. But traversing a node without visiting it
2360/// is not possible.
2361///
2362/// Note that the insertion of the "generic view" of the diff node
2363/// into the graph being traversed is done "on the fly". The
2364/// insertion of the "typed view" of the diff node into the graph is
2365/// done implicitely. To learn more about the generic and typed view
2366/// of the diff node, please read the introductory comments of the
2367/// @ref diff class.
2368///
2369/// Note that by default this traversing code visits a given class of
2370/// equivalence of a diff node only once. This behaviour can been
2371/// changed by calling
2372/// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2373/// very risky as it might create endless loops while visiting a diff
2374/// tree graph that has changes that refer to themselves; that is,
2375/// diff tree graphs with cycles.
2376///
2377/// When a diff node is encountered, the
2378/// diff_node_visitor::visit_begin() method is invoked on the diff
2379/// node first.
2380///
2381/// If the diff node has already been visited, then
2382/// node_visitor::visit_end() is called on it and the node traversing
2383/// is done; the children of the diff node are not visited in this
2384/// case.
2385///
2386/// If the diff node has *NOT* been visited yet, then the
2387/// diff_node_visitor::visit() method is invoked with it's 'pre'
2388/// argument set to true. Then if the diff_node_visitor::visit()
2389/// returns true, then the children nodes of the diff node are
2390/// visited. Otherwise, no children nodes of the diff node is
2391/// visited and the diff_node_visitor::visit_end() is called.
2392
2393/// After the children nodes are visited (and only if they are
2394/// visited) the diff_node_visitor::visit() method is invoked with
2395/// it's 'pre' argument set to false. And then the
2396/// diff_node_visitor::visit_end() is called.
2397///
2398/// @param v the entity that visits each node of the diff sub-tree.
2399///
2400/// @return true to tell the caller that all of the sub-tree could be
2401/// walked. This instructs the caller to keep walking the rest of the
2402/// tree. Return false otherwise.
2403bool
2405{
2406 // Insert the "generic view" of the diff node into its graph.
2408
2409 v.visit_begin(this);
2410
2411 bool already_visited = false;
2412 if (context()->visiting_a_node_twice_is_forbidden()
2413 && context()->diff_has_been_visited(this))
2414 already_visited = true;
2415
2416 bool mark_visited_nodes_as_traversed =
2418
2419 if (!already_visited && !v.visit(this, /*pre=*/true))
2420 {
2421 v.visit_end(this);
2422 if (mark_visited_nodes_as_traversed)
2423 context()->mark_diff_as_visited(this);
2424 return false;
2425 }
2426
2428 && !is_traversing()
2429 && !already_visited)
2430 {
2432 for (vector<diff*>::const_iterator i = children_nodes().begin();
2433 i != children_nodes().end();
2434 ++i)
2435 {
2436 if (!(*i)->traverse(v))
2437 {
2438 v.visit_end(this);
2439 if (mark_visited_nodes_as_traversed)
2440 context()->mark_diff_as_visited(this);
2442 return false;
2443 }
2444 }
2446 }
2447
2448 if (!v.visit(this, /*pref=*/false))
2449 {
2450 v.visit_end(this);
2451 if (mark_visited_nodes_as_traversed)
2452 context()->mark_diff_as_visited(this);
2453 return false;
2454 }
2455
2456 v.visit_end(this);
2457 if (!already_visited && mark_visited_nodes_as_traversed)
2458 context()->mark_diff_as_visited(this);
2459
2460 return true;
2461}
2462
2463/// Sets a flag saying if a report has already been emitted for the
2464/// current diff.
2465///
2466/// @param f true if a report has already been emitted for the
2467/// current diff, false otherwise.
2468void
2470{
2471 ABG_ASSERT(priv_->canonical_diff_);
2472 priv_->canonical_diff_->priv_->reported_once_ = f;
2473 priv_->reported_once_ = f;
2474}
2475
2476/// Getter for the local category of the current diff tree node.
2477///
2478/// The local category represents the set of categories of a diff
2479/// node, not taking in account the categories inherited from its
2480/// children nodes.
2481///
2482/// @return the local category of the current diff tree node.
2485{return priv_->local_category_;}
2486
2487/// Getter of the category of the class of equivalence of the current
2488/// diff tree node.
2489///
2490/// That is, if the current diff tree node has a canonical node,
2491/// return the category of that canonical node. Otherwise, return the
2492/// category of the current node.
2493///
2494/// @return the category of the class of equivalence of the current
2495/// tree node.
2498{
2499 diff* canonical = get_canonical_diff();
2500 return canonical ? canonical->get_category() : get_category();
2501}
2502
2503/// Getter for the category of the current diff tree node.
2504///
2505/// This category represents the union of the local category and the
2506/// categories inherited from the children diff nodes.
2507///
2508/// @return the category of the current diff tree node.
2511{return priv_->category_;}
2512
2513/// Adds the current diff tree node to an additional set of
2514/// categories. Note that the categories include thoses inherited
2515/// from the children nodes of this diff node.
2516///
2517/// @param c a bit-map representing the set of categories to add the
2518/// current diff tree node to.
2519///
2520/// @return the resulting bit-map representing the categories this
2521/// current diff tree node belongs to, including those inherited from
2522/// its children nodes.
2525{
2526 priv_->category_ = priv_->category_ | c;
2527 return priv_->category_;
2528}
2529
2530/// Adds the current diff tree node to the categories resulting from
2531/// the local changes of the current diff node.
2532///
2533/// @param c a bit-map representing the set of categories to add the
2534/// current diff tree node to.
2535///
2536/// @return the resulting bit-map representing the categories this
2537/// current diff tree node belongs to.
2540{
2541 priv_->local_category_ = priv_->local_category_ | c;
2542 return priv_->local_category_;
2543}
2544
2545/// Adds the current diff tree node to the categories resulting from
2546/// the local and inherited changes of the current diff node.
2547///
2548/// @param c a bit-map representing the set of categories to add the
2549/// current diff tree node to.
2550void
2556
2557/// Remove the current diff tree node from an a existing sef of
2558/// categories. The categories include those inherited from the
2559/// children nodes of the current diff node.
2560///
2561/// @param c a bit-map representing the set of categories to add the
2562/// current diff tree node to.
2563///
2564/// @return the resulting bit-map representing the categories this
2565/// current diff tree onde belongs to, including the categories
2566/// inherited from the children nodes of the current diff node.
2569{
2570 priv_->category_ = priv_->category_ & ~c;
2571 return priv_->category_;
2572}
2573
2574/// Remove the current diff tree node from the categories resulting
2575/// from the local changes.
2576///
2577/// @param c a bit-map representing the set of categories to add the
2578/// current diff tree node to.
2579///
2580/// @return the resulting bit-map representing the categories this
2581/// current diff tree onde belongs to.
2584{
2585 priv_->local_category_ = priv_->local_category_ & ~c;
2586 return priv_->local_category_;
2587}
2588
2589/// Set the category of the current @ref diff node. This category
2590/// includes the categories inherited from the children nodes of the
2591/// current diff node.
2592///
2593/// @param c the new category for the current diff node.
2594void
2596{priv_->category_ = c;}
2597
2598/// Set the local category of the current @ref diff node.
2599///
2600/// @param c the new category for the current diff node.
2601void
2603{priv_->local_category_ = c;}
2604
2605/// Test if this diff tree node is to be filtered out for reporting
2606/// purposes.
2607///
2608/// There is a difference between a diff node being filtered out and
2609/// being suppressed. Being suppressed means that there is a
2610/// suppression specification that suppresses the diff node
2611/// specifically. Being filtered out mean the node is either
2612/// suppressed, or it's filtered out because the suppression of a set
2613/// of (children) nodes caused this node to be filtered out as well.
2614/// For instance, if a function diff has all its children diff nodes
2615/// suppressed and if the function diff node carries no local change,
2616/// then the function diff node itself is going to be filtered out.
2617///
2618/// The function tests if the categories of the diff tree node are
2619/// "forbidden" by the context or not.
2620///
2621/// @return true iff the current diff node should NOT be reported.
2622bool
2624{
2625 if (diff * canonical = get_canonical_diff())
2626 if ((canonical->get_category() & SUPPRESSED_CATEGORY
2627 || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2628 && !canonical->is_allowed_by_specific_negated_suppression()
2629 && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2630 && !canonical->has_parent_allowed_by_specific_negated_suppression())
2631 // The canonical type was suppressed either by a user-provided
2632 // suppression specification or by a "private-type" suppression
2633 // specification.. This means all the classes of equivalence of
2634 // that canonical type were suppressed. So this node should be
2635 // filtered out.
2636 return true;
2637 return priv_->is_filtered_out(get_category());
2638}
2639
2640/// Test if this diff tree node is to be filtered out for reporting
2641/// purposes, but by considering only the categories that were *NOT*
2642/// inherited from its children nodes.
2643///
2644/// The function tests if the local categories of the diff tree node
2645/// are "forbidden" by the context or not.
2646///
2647/// @return true iff the current diff node should NOT be reported,
2648/// with respect to its local categories.
2649bool
2651{return priv_->is_filtered_out(get_local_category());}
2652
2653/// Test if this diff tree node is to be filtered out for reporting
2654/// purposes, but without considering the categories that can /force/
2655/// the node to be unfiltered.
2656///
2657/// The function tests if the categories of the diff tree node are
2658/// "forbidden" by the context or not.
2659///
2660/// @return true iff the current diff node should should NOT be
2661/// reported, with respect to the categories that might filter it out
2662/// only.
2663bool
2673
2674/// Test if the current diff node has been suppressed by a
2675/// user-provided suppression specification.
2676///
2677/// @return true if the current diff node has been suppressed by a
2678/// user-provided suppression list.
2679bool
2681{
2682 bool is_private = false;
2683 return is_suppressed(is_private);
2684}
2685
2686/// Test if the current diff node has been suppressed by a
2687/// user-provided suppression specification or by an auto-generated
2688/// "private type" suppression specification.
2689///
2690/// Note that private type suppressions are auto-generated from the
2691/// path to where public headers are, as given by the user.
2692///
2693/// Here is the current algorithm:
2694///
2695/// First, suppress this diff node if it's not matched by any
2696/// negated suppression specifications. If it's not
2697/// suppressed, then suppress it if it's matched by direct
2698/// suppression specifications.
2699///
2700/// @param is_private_type out parameter if the current diff node was
2701/// suppressed because it's a private type then this parameter is set
2702/// to true.
2703///
2704/// @return true if the current diff node has been suppressed by a
2705/// user-provided suppression list.
2706bool
2707diff::is_suppressed(bool &is_private_type) const
2708{
2709 // If there is at least one negated suppression, then suppress the
2710 // current diff node by default ...
2711 bool do_suppress = !context()->negated_suppressions().empty();
2712
2713 // ... unless there is at least one negated suppression that
2714 // specifically asks to keep this diff node around (un-suppressed).
2715 for (auto n : context()->negated_suppressions())
2716 if (!n->suppresses_diff(this))
2717 {
2718 do_suppress = false;
2719 break;
2720 }
2721
2722 // Then walk the set of non-negated, AKA direct, suppressions. If at
2723 // least one suppression suppresses the current diff node then the
2724 // diff node must be suppressed.
2725 for (auto d : context()->direct_suppressions())
2726 if (d->suppresses_diff(this))
2727 {
2728 do_suppress = true;
2730 is_private_type = true;
2731 break;
2732 }
2733
2734 return do_suppress;
2735}
2736
2737/// Test if the current diff node has been suppressed by a suppression
2738/// specification or it has been categorized as suppressed due to
2739/// category propagation.
2740///
2741/// @return true iff the current diff node has been suppressed by a
2742/// suppression specification or it has been categorized as suppressed
2743/// due to category propagation.
2744bool
2750
2751/// Test if this diff tree node should be reported.
2752///
2753/// @return true iff the current node should be reported.
2754bool
2756{
2757 if (has_changes() && !is_filtered_out())
2758 return true;
2759 return false;
2760}
2761
2762/// Test if this diff tree node should be reported when considering
2763/// the categories that were *NOT* inherited from its children nodes.
2764///
2765/// @return true iff the current node should be reported.
2766bool
2768{
2769 if (has_local_changes()
2771 return true;
2772 return false;
2773}
2774
2775/// Test if this diff node is allowed (prevented from being
2776/// suppressed) by at least one negated suppression specification.
2777///
2778/// @return true if this diff node is meant to be allowed by at least
2779/// one negated suppression specification.
2780bool
2782{
2783 const suppressions_type& suppressions = context()->suppressions();
2784 for (suppressions_type::const_iterator i = suppressions.begin();
2785 i != suppressions.end();
2786 ++i)
2787 {
2789 && !(*i)->suppresses_diff(this))
2790 return true;
2791 }
2792 return false;
2793}
2794
2795/// Test if the current diff node has a descendant node which is
2796/// specifically allowed by a negated suppression specification.
2797///
2798/// @return true iff the current diff node has a descendant node
2799/// which is specifically allowed by a negated suppression
2800/// specification.
2801bool
2807
2808/// Test if the current diff node has a parent node which is
2809/// specifically allowed by a negated suppression specification.
2810///
2811/// @return true iff the current diff node has a parent node which is
2812/// specifically allowed by a negated suppression specification.
2813bool
2819
2820/// Get a pretty representation of the current @ref diff node.
2821///
2822/// This is suitable for e.g. emitting debugging traces for the diff
2823/// tree nodes.
2824///
2825/// @return the pretty representation of the diff node.
2826const string&
2828{
2829 if (priv_->pretty_representation_.empty())
2830 priv_->pretty_representation_ = "empty_diff";
2831 return priv_->pretty_representation_;
2832}
2833
2834/// Default implementation of the hierachy chaining virtual function.
2835///
2836/// There are several types of diff nodes that have logical children
2837/// nodes; for instance, a typedef_diff has the diff of the underlying
2838/// type as a child node. A var_diff has the diff of the types of the
2839/// variables as a child node, etc.
2840///
2841/// But because the @ref diff base has a generic representation for
2842/// children nodes of the all the types of @ref diff nodes (regardless
2843/// of the specific most-derived type of diff node) that one can get
2844/// using the method diff::children_nodes(), one need to populate that
2845/// vector of children node.
2846///
2847/// Populating that vector of children node is done by this function;
2848/// it must be overloaded by each most-derived type of diff node that
2849/// extends the @ref diff type.
2850void
2853
2854// </diff stuff>
2855
2856// <type_diff_base stuff>
2857
2858type_diff_base::type_diff_base(type_base_sptr first_subject,
2859 type_base_sptr second_subject,
2860 diff_context_sptr ctxt)
2861 : diff(first_subject, second_subject, ctxt),
2862 priv_(new priv)
2863{}
2864
2865type_diff_base::~type_diff_base()
2866{}
2867// </type_diff_base stuff>
2868
2869// <decl_diff_base stuff>
2870
2871/// Constructor of @ref decl_diff_base.
2872///
2873/// @param first_subject the first subject of the diff.
2874///
2875/// @param second_subject the second subject of the diff.
2876///
2877/// @param ctxt the context of the diff. This object must stay alive
2878/// at least during the life time of the current instance of @ref
2879/// decl_diff_base, otherwise, memory corruption issues occur.
2880decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2881 decl_base_sptr second_subject,
2882 diff_context_sptr ctxt)
2883 : diff(first_subject, second_subject, ctxt),
2884 priv_(new priv)
2885{}
2886
2887decl_diff_base::~decl_diff_base()
2888{}
2889
2890// </decl_diff_base stuff>
2891
2892// <distinct_diff stuff>
2893
2894/// @return a pretty representation for the @ref distinct_diff node.
2895const string&
2897{
2898 if (diff::priv_->pretty_representation_.empty())
2899 {
2900 std::ostringstream o;
2901 o << "distinct_diff[";
2902 if (first_subject())
2904 else
2905 o << "null";
2906 o << ", ";
2907 if (second_subject())
2908 o << second_subject()->get_pretty_representation() ;
2909 else
2910 o << "null";
2911 o << "]" ;
2912 diff::priv_->pretty_representation_ = o.str();
2913 }
2914 return diff::priv_->pretty_representation_;
2915}
2916
2917/// Populate the vector of children node of the @ref diff base type
2918/// sub-object of this instance of @distinct_diff.
2919///
2920/// The children nodes can then later be retrieved using
2921/// diff::children_nodes().
2922void
2930
2931/// Constructor for @ref distinct_diff.
2932///
2933/// Note that the two entities considered for the diff (and passed in
2934/// parameter) must be of different kinds.
2935///
2936/// @param first the first entity to consider for the diff.
2937///
2938/// @param second the second entity to consider for the diff.
2939///
2940/// @param ctxt the context of the diff. Note that this context
2941/// object must stay alive at least during the life time of the
2942/// current instance of @ref distinct_diff. Otherwise memory
2943/// corruption issues occur.
2950
2951/// Getter for the first subject of the diff.
2952///
2953/// @return the first subject of the diff.
2956{return first_subject();}
2957
2958/// Getter for the second subject of the diff.
2959///
2960/// @return the second subject of the diff.
2964
2965/// Getter for the child diff of this distinct_diff instance.
2966///
2967/// When a distinct_diff has two subjects that are different but
2968/// compatible, then the distinct_diff instance has a child diff node
2969/// (named the compatible child diff) that is the diff between the two
2970/// subjects stripped from their typedefs. Otherwise, the compatible
2971/// child diff is nul.
2972///
2973/// Note that two diff subjects (that compare different) are
2974/// considered compatible if stripping typedefs out of them makes them
2975/// comparing equal.
2976///
2977/// @return the compatible child diff node, if any. Otherwise, null.
2978const diff_sptr
2980{
2981 if (!priv_->compatible_child_diff)
2982 {
2985 {
2986 type_base_sptr fs = peel_qualified_or_typedef_type(is_type(first())),
2988
2989 priv_->compatible_child_diff =
2992 context());
2993 }
2994 }
2995 return priv_->compatible_child_diff;
2996}
2997
2998/// Test if the two arguments are of different kind, or that are both
2999/// NULL.
3000///
3001/// @param first the first argument to test for similarity in kind.
3002///
3003/// @param second the second argument to test for similarity in kind.
3004///
3005/// @return true iff the two arguments are of different kind.
3006bool
3009{
3010 if (!!first != !!second)
3011 return true;
3012 if (!first && !second)
3013 // We do consider diffs of two empty decls as a diff of distinct
3014 // kinds, for now.
3015 return true;
3016 if (first == second)
3017 return false;
3018
3019 const type_or_decl_base &f = *first, &s = *second;
3020 return typeid(f) != typeid(s);
3021}
3022
3023/// @return true if the two subjects of the diff are different, false
3024/// otherwise.
3025bool
3027{return first() != second();}
3028
3029/// @return the kind of local change carried by the current diff node.
3030/// The value returned is zero if the current node carries no local
3031/// change.
3032enum change_kind
3034{
3035 // Changes on a distinct_diff are all local.
3036 if (has_changes())
3038 return NO_CHANGE_KIND;
3039}
3040
3041/// Emit a report about the current diff instance.
3042///
3043/// @param out the output stream to send the diff report to.
3044///
3045/// @param indent the indentation string to use in the report.
3046void
3047distinct_diff::report(ostream& out, const string& indent) const
3048{
3049 context()->get_reporter()->report(*this, out, indent);
3050}
3051
3052/// Try to diff entities that are of distinct kinds.
3053///
3054/// @param first the first entity to consider for the diff.
3055///
3056/// @param second the second entity to consider for the diff.
3057///
3058/// @param ctxt the context of the diff.
3059///
3060/// @return a non-null diff if a diff object could be built, null
3061/// otherwise.
3064 const type_or_decl_base_sptr second,
3065 diff_context_sptr ctxt)
3066{
3068 return distinct_diff_sptr();
3069
3070 distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
3071
3072 ctxt->initialize_canonical_diff(result);
3073
3074 return result;
3075}
3076
3077/// </distinct_diff stuff>
3078
3079/// Try to compute a diff on two instances of DiffType representation.
3080///
3081/// The function template performs the diff if and only if the decl
3082/// representations are of a DiffType.
3083///
3084/// @tparm DiffType the type of instances to diff.
3085///
3086/// @param first the first representation of decl to consider in the
3087/// diff computation.
3088///
3089/// @param second the second representation of decl to consider in the
3090/// diff computation.
3091///
3092/// @param ctxt the diff context to use.
3093///
3094///@return the diff of the two types @p first and @p second if and
3095///only if they represent the parametrized type DiffType. Otherwise,
3096///returns a NULL pointer value.
3097template<typename DiffType>
3100 const type_or_decl_base_sptr second,
3101 diff_context_sptr ctxt)
3102{
3103 if (shared_ptr<DiffType> f =
3104 dynamic_pointer_cast<DiffType>(first))
3105 {
3106 shared_ptr<DiffType> s =
3107 dynamic_pointer_cast<DiffType>(second);
3108 if (!s)
3109 return diff_sptr();
3110 return compute_diff(f, s, ctxt);
3111 }
3112 return diff_sptr();
3113}
3114
3115
3116/// This is a specialization of @ref try_to_diff() template to diff
3117/// instances of @ref class_decl.
3118///
3119/// @param first the first representation of decl to consider in the
3120/// diff computation.
3121///
3122/// @param second the second representation of decl to consider in the
3123/// diff computation.
3124///
3125/// @param ctxt the diff context to use.
3126template<>
3129 const type_or_decl_base_sptr second,
3130 diff_context_sptr ctxt)
3131{
3132 if (class_decl_sptr f =
3133 dynamic_pointer_cast<class_decl>(first))
3134 {
3135 class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
3136 if (!s)
3137 return diff_sptr();
3138
3139 if (f->get_is_declaration_only())
3140 {
3141 class_decl_sptr f2 =
3142 is_class_type (f->get_definition_of_declaration());
3143 if (f2)
3144 f = f2;
3145 }
3146 if (s->get_is_declaration_only())
3147 {
3148 class_decl_sptr s2 =
3149 is_class_type(s->get_definition_of_declaration());
3150 if (s2)
3151 s = s2;
3152 }
3153 return compute_diff(f, s, ctxt);
3154 }
3155 return diff_sptr();
3156}
3157
3158/// Try to diff entities that are of distinct kinds.
3159///
3160/// @param first the first entity to consider for the diff.
3161///
3162/// @param second the second entity to consider for the diff.
3163///
3164/// @param ctxt the context of the diff.
3165///
3166/// @return a non-null diff if a diff object could be built, null
3167/// otherwise.
3168static diff_sptr
3169try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3170 const type_or_decl_base_sptr second,
3171 diff_context_sptr ctxt)
3172{return compute_diff_for_distinct_kinds(first, second, ctxt);}
3173
3174/// Compute the difference between two types.
3175///
3176/// The function considers every possible types known to libabigail
3177/// and runs the appropriate diff function on them.
3178///
3179/// Whenever a new kind of type decl is supported by abigail, if we
3180/// want to be able to diff two instances of it, we need to update
3181/// this function to support it.
3182///
3183/// @param first the first type decl to consider for the diff
3184///
3185/// @param second the second type decl to consider for the diff.
3186///
3187/// @param ctxt the diff context to use.
3188///
3189/// @return the resulting diff. It's a pointer to a descendent of
3190/// abigail::comparison::diff.
3191static diff_sptr
3192compute_diff_for_types(const type_or_decl_base_sptr& first,
3193 const type_or_decl_base_sptr& second,
3194 const diff_context_sptr& ctxt)
3195{
3196 type_or_decl_base_sptr f = first;
3197 type_or_decl_base_sptr s = second;
3198
3199 diff_sptr d;
3200
3201 ((d = try_to_diff<type_decl>(f, s, ctxt))
3202 ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3203 ||(d = try_to_diff<union_decl>(f, s,ctxt))
3204 ||(d = try_to_diff<class_decl>(f, s,ctxt))
3205 ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3206 ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3207 ||(d = try_to_diff<ptr_to_mbr_type>(f, s, ctxt))
3208 ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3209 ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3210 ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3211 ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3212 ||(d = try_to_diff<function_type>(f, s, ctxt))
3213 ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3214
3215 ABG_ASSERT(d);
3216
3217 return d;
3218}
3219
3222{return static_cast<diff_category>(static_cast<unsigned>(c1)
3223 | static_cast<unsigned>(c2));}
3224
3226operator|=(diff_category& c1, diff_category c2)
3227{
3228 c1 = c1 | c2;
3229 return c1;
3230}
3231
3233operator&=(diff_category& c1, diff_category c2)
3234{
3235 c1 = c1 & c2;
3236 return c1;
3237}
3238
3240operator^(diff_category c1, diff_category c2)
3241{return static_cast<diff_category>(static_cast<unsigned>(c1)
3242 ^ static_cast<unsigned>(c2));}
3243
3246{return static_cast<diff_category>(static_cast<unsigned>(c1)
3247 & static_cast<unsigned>(c2));}
3248
3251{return static_cast<diff_category>(~static_cast<unsigned>(c));}
3252
3253
3254/// Getter of a bitmap made of the set of change categories that are
3255/// considered harmless.
3256///
3257/// @return the bitmap made of the set of change categories that are
3258/// considered harmless.
3279
3280/// Getter of a bitmap made of the set of change categories that are
3281/// considered harmful.
3282///
3283/// @return the bitmap made of the set of change categories that are
3284/// considered harmful.
3295
3296/// Test if an instance of @ref diff_category (a category bit-field)
3297/// is harmful or not.
3298///
3299/// A harmful change is a change that is not harmless. OK, that
3300/// smells bit like a tasteless tautology, but bear with me please.
3301///
3302/// A harmless change is a change that should be filtered out by
3303/// default to avoid unnecessarily cluttering the change report.
3304///
3305/// A harmful change is thus a change that SHOULD NOT be filtered out
3306/// by default because it CAN represent an incompatible ABI change.
3307///
3308/// An incompatbile ABI change is a harmful change that makes the new
3309/// ABI incompatible with the previous one.
3310///
3311/// @param c the instance of @ref diff_category to consider. It is a
3312/// bit-field of the categories of a given diff node.
3313///
3314/// @return true
3315bool
3321
3322/// Serialize an instance of @ref diff_category to an output stream.
3323///
3324/// @param o the output stream to serialize @p c to.
3325///
3326/// @param c the instance of diff_category to serialize.
3327///
3328/// @return the output stream to serialize @p c to.
3329ostream&
3330operator<<(ostream& o, diff_category c)
3331{
3332 bool emitted_a_category = false;
3333
3334 if (c == NO_CHANGE_CATEGORY)
3335 {
3336 o << "NO_CHANGE_CATEGORY";
3337 emitted_a_category = true;
3338 }
3339
3340 if (c & ACCESS_CHANGE_CATEGORY)
3341 {
3342 if (emitted_a_category)
3343 o << "|";
3344 o << "ACCESS_CHANGE_CATEGORY";
3345 emitted_a_category |= true;
3346 }
3347
3349 {
3350 if (emitted_a_category)
3351 o << "|";
3352 o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3353 emitted_a_category |= true;
3354 }
3355
3357 {
3358 if (emitted_a_category)
3359 o << "|";
3360 o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3361 emitted_a_category |= true;
3362 }
3363
3365 {
3366 if (emitted_a_category)
3367 o << "|";
3368 o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3369 emitted_a_category |= true;
3370 }
3371
3373 {
3374 if (emitted_a_category)
3375 o << "|";
3376 o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3377 emitted_a_category |= true;
3378 }
3379
3381 {
3382 if (emitted_a_category)
3383 o << "|";
3384 o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3385 emitted_a_category |= true;
3386 }
3387
3389 {
3390 if (emitted_a_category)
3391 o << "|";
3392 o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3393 emitted_a_category |= true;
3394 }
3395
3397 {
3398 if (emitted_a_category)
3399 o << "|";
3400 o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3401 emitted_a_category |= true;
3402 }
3403
3405 {
3406 if (emitted_a_category)
3407 o << "|";
3408 o << "HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY";
3409 emitted_a_category |= true;
3410 }
3411
3412 if (c & SUPPRESSED_CATEGORY)
3413 {
3414 if (emitted_a_category)
3415 o << "|";
3416 o << "SUPPRESSED_CATEGORY";
3417 emitted_a_category |= true;
3418 }
3419
3420 if (c & PRIVATE_TYPE_CATEGORY)
3421 {
3422 if (emitted_a_category)
3423 o << "|";
3424 o << "PRIVATE_TYPE_CATEGORY";
3425 emitted_a_category |= true;
3426 }
3427
3429 {
3430 if (emitted_a_category)
3431 o << "|";
3432 o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3433 emitted_a_category |= true;
3434 }
3435
3437 {
3438 if (emitted_a_category)
3439 o << "|";
3440 o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3441 emitted_a_category |= true;
3442 }
3443
3444 if (c & REFERENCE_LVALUENESS_CHANGE_CATEGORY)
3445 {
3446 if (emitted_a_category)
3447 o << "|";
3448 o << "REFERENCE_LVALUENESS_CHANGE_CATEGORY";
3449 emitted_a_category |= true;
3450 }
3451
3453 {
3454 if (emitted_a_category)
3455 o << "|";
3456 o << "NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY";
3457 emitted_a_category |= true;
3458 }
3459
3461 {
3462 if (emitted_a_category)
3463 o << "|";
3464 o << "NON_COMPATIBLE_NAME_CHANGE_CATEGORY";
3465 emitted_a_category |= true;
3466 }
3467
3468 if (c & REDUNDANT_CATEGORY)
3469 {
3470 if (emitted_a_category)
3471 o << "|";
3472 o << "REDUNDANT_CATEGORY";
3473 emitted_a_category |= true;
3474 }
3475
3477 {
3478 if (emitted_a_category)
3479 o << "|";
3480 o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3481 emitted_a_category |= true;
3482 }
3483
3485 {
3486 if (emitted_a_category)
3487 o << "|";
3488 o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3489 emitted_a_category |= true;
3490 }
3491
3493 {
3494 if (emitted_a_category)
3495 o << "|";
3496 o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3497 emitted_a_category |= true;
3498 }
3499
3501 {
3502 if (emitted_a_category)
3503 o << "|";
3504 o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3505 emitted_a_category |= true;
3506 }
3507
3509 {
3510 if (emitted_a_category)
3511 o << "|";
3512 o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3513 emitted_a_category |= true;
3514 }
3515
3517 {
3518 if (emitted_a_category)
3519 o << "|";
3520 o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3521 emitted_a_category |= true;
3522 }
3523
3525 {
3526 if (emitted_a_category)
3527 o << "|";
3528 o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3529 emitted_a_category |= true;
3530 }
3531
3533 {
3534 if (emitted_a_category)
3535 o << "|";
3536 o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3537 emitted_a_category |= true;
3538 }
3539
3541 {
3542 if (emitted_a_category)
3543 o << "|";
3544 o << "HAS_ALLOWED_CHANGE_CATEGORY";
3545 emitted_a_category |= true;
3546 }
3547
3549 {
3550 if (emitted_a_category)
3551 o << "|";
3552 o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3553 emitted_a_category |= true;
3554 }
3555
3557 {
3558 if (emitted_a_category)
3559 o << "|";
3560 o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3561 emitted_a_category |= true;
3562 }
3563
3564 return o;
3565}
3566
3567/// Compute the difference between two decls.
3568///
3569/// The function consider every possible decls known to libabigail and
3570/// runs the appropriate diff function on them.
3571///
3572/// Whenever a new kind of non-type decl is supported by abigail, if
3573/// we want to be able to diff two instances of it, we need to update
3574/// this function to support it.
3575///
3576/// @param first the first decl to consider for the diff
3577///
3578/// @param second the second decl to consider for the diff.
3579///
3580/// @param ctxt the diff context to use.
3581///
3582/// @return the resulting diff.
3583static diff_sptr
3584compute_diff_for_decls(const decl_base_sptr first,
3585 const decl_base_sptr second,
3586 diff_context_sptr ctxt)
3587{
3588
3589 diff_sptr d;
3590
3591 ((d = try_to_diff<function_decl>(first, second, ctxt))
3592 || (d = try_to_diff<var_decl>(first, second, ctxt))
3593 || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3594
3595 ABG_ASSERT(d);
3596
3597 return d;
3598}
3599
3600/// Compute the difference between two decls. The decls can represent
3601/// either type declarations, or non-type declaration.
3602///
3603/// Note that the two decls must have been created in the same @ref
3604/// environment, otherwise, this function aborts.
3605///
3606/// @param first the first decl to consider.
3607///
3608/// @param second the second decl to consider.
3609///
3610/// @param ctxt the diff context to use.
3611///
3612/// @return the resulting diff, or NULL if the diff could not be
3613/// computed.
3615compute_diff(const decl_base_sptr first,
3616 const decl_base_sptr second,
3617 diff_context_sptr ctxt)
3618{
3619 if (!first || !second)
3620 return diff_sptr();
3621
3622 diff_sptr d;
3623 if (is_type(first) && is_type(second))
3624 d = compute_diff_for_types(first, second, ctxt);
3625 else
3626 d = compute_diff_for_decls(first, second, ctxt);
3627 ABG_ASSERT(d);
3628 return d;
3629}
3630
3631/// Compute the difference between two types.
3632///
3633/// Note that the two types must have been created in the same @ref
3634/// environment, otherwise, this function aborts.
3635///
3636/// @param first the first type to consider.
3637///
3638/// @param second the second type to consider.
3639///
3640/// @param ctxt the diff context to use.
3641///
3642/// @return the resulting diff, or NULL if the diff couldn't be
3643/// computed.
3645compute_diff(const type_base_sptr first,
3646 const type_base_sptr second,
3647 diff_context_sptr ctxt)
3648{
3649 decl_base_sptr f = get_type_declaration(first),
3650 s = get_type_declaration(second);
3651
3652 diff_sptr d = compute_diff_for_types(f,s, ctxt);
3653 ABG_ASSERT(d);
3654 return d;
3655}
3656
3657/// Get a copy of the pretty representation of a diff node.
3658///
3659/// @param d the diff node to consider.
3660///
3661/// @return the pretty representation string.
3662string
3664{
3665 if (!d)
3666 return "";
3667 string prefix= "diff of ";
3668 return prefix + get_pretty_representation(d->first_subject());
3669}
3670
3671// <var_diff stuff>
3672
3673/// Populate the vector of children node of the @ref diff base type
3674/// sub-object of this instance of @ref var_diff.
3675///
3676/// The children node can then later be retrieved using
3677/// diff::children_node().
3678void
3681
3682/// @return the pretty representation for this current instance of
3683/// @ref var_diff.
3684const string&
3686{
3687 if (diff::priv_->pretty_representation_.empty())
3688 {
3689 std::ostringstream o;
3690 o << "var_diff["
3691 << first_subject()->get_pretty_representation()
3692 << ", "
3693 << second_subject()->get_pretty_representation()
3694 << "]";
3695 diff::priv_->pretty_representation_ = o.str();
3696 }
3697 return diff::priv_->pretty_representation_;
3698}
3699/// Constructor for @ref var_diff.
3700///
3701/// @param first the first instance of @ref var_decl to consider in
3702/// the diff.
3703///
3704/// @param second the second instance of @ref var_decl to consider in
3705/// the diff.
3706///
3707/// @param type_diff the diff between types of the instances of
3708/// var_decl.
3709///
3710/// @param ctxt the diff context to use.
3712 var_decl_sptr second,
3713 diff_sptr type_diff,
3714 diff_context_sptr ctxt)
3715 : decl_diff_base(first, second, ctxt),
3716 priv_(new priv)
3717{priv_->type_diff_ = type_diff;}
3718
3719/// Getter for the first @ref var_decl of the diff.
3720///
3721/// @return the first @ref var_decl of the diff.
3724{return dynamic_pointer_cast<var_decl>(first_subject());}
3725
3726/// Getter for the second @ref var_decl of the diff.
3727///
3728/// @return the second @ref var_decl of the diff.
3731{return dynamic_pointer_cast<var_decl>(second_subject());}
3732
3733/// Getter for the diff of the types of the instances of @ref
3734/// var_decl.
3735///
3736/// @return the diff of the types of the instances of @ref var_decl.
3739{
3740 if (diff_sptr result = priv_->type_diff_.lock())
3741 return result;
3742 else
3743 {
3744 result = compute_diff(first_var()->get_type(),
3745 second_var()->get_type(),
3746 context());
3747 context()->keep_diff_alive(result);
3748 priv_->type_diff_ = result;
3749 return result;
3750 }
3751}
3752
3753/// Return true iff the diff node has a change.
3754///
3755/// @return true iff the diff node has a change.
3756bool
3758{return *first_var() != *second_var();}
3759
3760/// @return the kind of local change carried by the current diff node.
3761/// The value returned is zero if the current node carries no local
3762/// change.
3763enum change_kind
3765{
3766 ir::change_kind k = ir::NO_CHANGE_KIND;
3767 if (!equals(*first_var(), *second_var(), &k))
3768 return k & ir::ALL_LOCAL_CHANGES_MASK;
3769 return ir::NO_CHANGE_KIND;
3770}
3771
3772/// Report the diff in a serialized form.
3773///
3774/// @param out the stream to serialize the diff to.
3775///
3776/// @param indent the prefix to use for the indentation of this
3777/// serialization.
3778void
3779var_diff::report(ostream& out, const string& indent) const
3780{
3781 context()->get_reporter()->report(*this, out, indent);
3782}
3783
3784/// Compute the diff between two instances of @ref var_decl.
3785///
3786/// Note that the two decls must have been created in the same @ref
3787/// environment, otherwise, this function aborts.
3788///
3789/// @param first the first @ref var_decl to consider for the diff.
3790///
3791/// @param second the second @ref var_decl to consider for the diff.
3792///
3793/// @param ctxt the diff context to use.
3794///
3795/// @return the resulting diff between the two @ref var_decl.
3798 const var_decl_sptr second,
3799 diff_context_sptr ctxt)
3800{
3801 var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3802 ctxt->initialize_canonical_diff(d);
3803
3804 return d;
3805}
3806
3807// </var_diff stuff>
3808
3809// <pointer_type_def stuff>
3810
3811/// Populate the vector of children node of the @ref diff base type
3812/// sub-object of this instance of @ref pointer_diff.
3813///
3814/// The children node can then later be retrieved using
3815/// diff::children_node().
3816void
3819
3820/// Constructor for a pointer_diff.
3821///
3822/// @param first the first pointer to consider for the diff.
3823///
3824/// @param second the secon pointer to consider for the diff.
3825///
3826/// @param ctxt the diff context to use.
3828 pointer_type_def_sptr second,
3829 diff_sptr underlying,
3830 diff_context_sptr ctxt)
3831 : type_diff_base(first, second, ctxt),
3832 priv_(new priv(underlying))
3833{}
3834
3835/// Getter for the first subject of a pointer diff
3836///
3837/// @return the first pointer considered in this pointer diff.
3840{return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3841
3842/// Getter for the second subject of a pointer diff
3843///
3844/// @return the second pointer considered in this pointer diff.
3847{return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3848
3849/// @return the pretty represenation for the current instance of @ref
3850/// pointer_diff.
3851const string&
3853{
3854 if (diff::priv_->pretty_representation_.empty())
3855 {
3856 std::ostringstream o;
3857 o << "pointer_diff["
3858 << first_subject()->get_pretty_representation()
3859 << ", "
3860 << second_subject()->get_pretty_representation()
3861 << "]";
3862 diff::priv_->pretty_representation_ = o.str();
3863 }
3864 return diff::priv_->pretty_representation_;
3865}
3866
3867/// Return true iff the current diff node carries a change.
3868///
3869/// @return true iff the current diff node carries a change.
3870bool
3873
3874/// @return the kind of local change carried by the current diff node.
3875/// The value returned is zero if the current node carries no local
3876/// change.
3877enum change_kind
3879{
3880 ir::change_kind k = ir::NO_CHANGE_KIND;
3881 if (!equals(*first_pointer(), *second_pointer(), &k))
3882 return k & ir::ALL_LOCAL_CHANGES_MASK;
3883 return ir::NO_CHANGE_KIND;
3884}
3885
3886/// Getter for the diff between the pointed-to types of the pointers
3887/// of this diff.
3888///
3889/// @return the diff between the pointed-to types.
3892{return priv_->underlying_type_diff_;}
3893
3894/// Setter for the diff between the pointed-to types of the pointers
3895/// of this diff.
3896///
3897/// @param d the new diff between the pointed-to types of the pointers
3898/// of this diff.
3899void
3901{priv_->underlying_type_diff_ = d;}
3902
3903/// Report the diff in a serialized form.
3904///
3905/// @param out the stream to serialize the diff to.
3906///
3907/// @param indent the prefix to use for the indentation of this
3908/// serialization.
3909void
3910pointer_diff::report(ostream& out, const string& indent) const
3911{
3912 context()->get_reporter()->report(*this, out, indent);
3913}
3914
3915/// Compute the diff between between two pointers.
3916///
3917/// Note that the two types must have been created in the same @ref
3918/// environment, otherwise, this function aborts.
3919///
3920/// @param first the pointer to consider for the diff.
3921///
3922/// @param second the pointer to consider for the diff.
3923///
3924/// @return the resulting diff between the two pointers.
3925///
3926/// @param ctxt the diff context to use.
3929 pointer_type_def_sptr second,
3930 diff_context_sptr ctxt)
3931{
3932 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3933 second->get_pointed_to_type(),
3934 ctxt);
3935 pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3936 ctxt->initialize_canonical_diff(result);
3937
3938 return result;
3939}
3940
3941// </pointer_type_def>
3942
3943// <subrange_diff >
3944
3945/// Constructor of the @ref subrange_diff diff node type.
3946///
3947/// @param first the first subrange type to consider for the diff.
3948///
3949/// @param second the second subrange type to consider for the diff.
3950///
3951/// @param underlying_type_diff the underlying type diff between @p
3952/// first and @p second.
3953///
3954/// @param ctxt the diff context to use.
3956(const array_type_def::subrange_sptr& first,
3957 const array_type_def::subrange_sptr& second,
3958 const diff_sptr& underlying_type_diff,
3959 const diff_context_sptr ctxt)
3960 : type_diff_base(first, second, ctxt),
3961 priv_(new priv(underlying_type_diff))
3962{}
3963
3964
3965/// Getter of the first subrange of the current instance @ref
3966/// subrange_diff.
3967///
3968/// @return The first subrange of the current instance @ref subrange_diff.
3972
3973/// Getter of the second subrange of the current instance @ref
3974/// subrange_diff.
3975///
3976/// @return The second subrange of the current instance @ref
3977/// subrange_diff.
3981
3982/// Getter of the diff node of the underlying types of the current
3983/// @ref subrange_diff diff node.
3984///
3985/// @return The diff node of the underlying types of the current @ref
3986/// subrange_diff diff node.
3987const diff_sptr
3989{return priv_->underlying_type_diff_;}
3990
3991/// Getter the pretty representation of the @ref subrange_diff diff
3992/// node.
3993///
3994/// @return The pretty representation of the @ref subrange_diff diff node.
3995const string&
3997{
3998 if (diff::priv_->pretty_representation_.empty())
3999 {
4000 std::ostringstream o;
4001 o << "subrange_diff["
4002 << first_subject()->get_pretty_representation()
4003 << ","
4004 << second_subject()->get_pretty_representation()
4005 << "]";
4006 diff::priv_->pretty_representation_ = o.str();
4007 }
4008 return diff::priv_->pretty_representation_;
4009}
4010
4011/// Test if the current @ref subrange_diff node carries any change.
4012///
4013/// @return true iff the current @ref subrange_diff node carries any
4014/// change.
4015bool
4018
4019/// Test if the current @ref subrange_diff node carries any local
4020/// change.
4021///
4022/// @return true iff the current @ref subrange_diff node carries any
4023/// local change.
4024enum change_kind
4026{
4027 ir::change_kind k = ir::NO_CHANGE_KIND;
4028 if (!equals(*first_subrange(), *second_subrange(), &k))
4029 return k & ir::ALL_LOCAL_CHANGES_MASK;
4030 return ir::NO_CHANGE_KIND;
4031}
4032
4033/// Report about the changes carried by this node.
4034///
4035/// @param out the output stream to send the report to.
4036///
4037/// @param indent the indentation string to use.
4038void
4039subrange_diff::report(ostream& out, const string& indent) const
4040{context()->get_reporter()->report(*this, out, indent);}
4041
4042/// Populate the vector of children node of the @ref diff base type
4043/// sub-object of this instance of @ref subrange_diff.
4044///
4045/// The children node can then later be retrieved using
4046/// diff::children_node().
4047void
4050
4051/// Compute the diff between two instances of @ref subrange_diff.
4052///
4053/// Note that the two decls must have been created in the same @ref
4054/// environment, otherwise, this function aborts.
4055///
4056/// @param first the first @ref subrange_diff to consider for the diff.
4057///
4058/// @param second the second @ref subrange_diff to consider for the diff.
4059///
4060/// @param ctxt the diff context to use.
4061///
4062/// @return the resulting diff between the two @ref subrange_diff.
4066 diff_context_sptr ctxt)
4067{
4068 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4069 second->get_underlying_type(),
4070 ctxt);
4071
4072 subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
4073 ctxt->initialize_canonical_diff(result);
4074 return result;
4075}
4076
4077//</subrange_diff >
4078
4079
4080// <array_type_def>
4081
4082/// Populate the vector of children node of the @ref diff base type
4083/// sub-object of this instance of @ref array_diff.
4084///
4085/// The children node can then later be retrieved using
4086/// diff::children_node().
4087void
4094
4095/// Constructor for array_diff
4096///
4097/// @param first the first array_type of the diff.
4098///
4099/// @param second the second array_type of the diff.
4100///
4101/// @param element_type_diff the diff between the two array element
4102/// types.
4103///
4104/// @param ctxt the diff context to use.
4106 const array_type_def_sptr second,
4107 diff_sptr element_type_diff,
4108 vector<subrange_diff_sptr>& subrange_diffs,
4109 diff_context_sptr ctxt)
4110 : type_diff_base(first, second, ctxt),
4111 priv_(new priv(element_type_diff, subrange_diffs))
4112{}
4113
4114/// Getter for the first array of the diff.
4115///
4116/// @return the first array of the diff.
4119{return dynamic_pointer_cast<array_type_def>(first_subject());}
4120
4121/// Getter for the second array of the diff.
4122///
4123/// @return for the second array of the diff.
4126{return dynamic_pointer_cast<array_type_def>(second_subject());}
4127
4128/// Getter for the diff between the two types of array elements.
4129///
4130/// @return the diff between the two types of array elements.
4131const diff_sptr&
4133{return priv_->element_type_diff_;}
4134
4135/// Getter for the diffs between the array subranges.
4136///
4137/// @return the diffs between the array subranges.
4138const vector<subrange_diff_sptr>&
4140{return priv_->subrange_diffs_;}
4141
4142/// Test if any subrange diff is to be reported.
4143///
4144/// @return true if any subrange diff is to be reported, false
4145/// otherwise.
4146bool
4148{
4149 for (const auto& diff: subrange_diffs())
4150 if (diff->to_be_reported())
4151 return true;
4152
4153 return false;
4154}
4155
4156/// Setter for the diff between the two array element types.
4157///
4158/// @param d the new diff between the two array element types.
4159void
4161{priv_->element_type_diff_ = d;}
4162
4163/// Setter for the diff between the two sets of array sub-ranges.
4164///
4165/// @param d the new diff between the two sets of array sub-ranges.
4166void
4167array_diff::subrange_diffs(const vector<subrange_diff_sptr>& d)
4168{priv_->subrange_diffs_ = d;}
4169
4170/// @return the pretty representation for the current instance of @ref
4171/// array_diff.
4172const string&
4174{
4175 if (diff::priv_->pretty_representation_.empty())
4176 {
4177 std::ostringstream o;
4178 o << "array_diff["
4179 << first_subject()->get_pretty_representation()
4180 << ", "
4181 << second_subject()->get_pretty_representation()
4182 << "]";
4183 diff::priv_->pretty_representation_ = o.str();
4184 }
4185 return diff::priv_->pretty_representation_;
4186}
4187
4188/// Return true iff the current diff node carries a change.
4189///
4190/// @return true iff the current diff node carries a change.
4191bool
4193{
4194 bool l = false;
4195
4196 // the array element types match check for differing dimensions
4197 // etc...
4199 f = dynamic_pointer_cast<array_type_def>(first_subject()),
4200 s = dynamic_pointer_cast<array_type_def>(second_subject());
4201
4202 if (f->get_name() != s->get_name())
4203 l |= true;
4204 if (f->get_size_in_bits() != s->get_size_in_bits())
4205 l |= true;
4206 if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
4207 l |= true;
4208
4209 l |= element_type_diff()
4210 ? element_type_diff()->has_changes()
4211 : false;
4212
4213 for (const auto& subrange_diff : subrange_diffs())
4214 l |= subrange_diff->has_changes();
4215
4216 return l;
4217}
4218
4219
4220/// @return the kind of local change carried by the current diff node.
4221/// The value returned is zero if the current node carries no local
4222/// change.
4223enum change_kind
4225{
4226 ir::change_kind k = ir::NO_CHANGE_KIND;
4227 if (!equals(*first_array(), *second_array(), &k))
4228 return k & ir::ALL_LOCAL_CHANGES_MASK;
4229 return ir::NO_CHANGE_KIND;
4230}
4231
4232/// Report the diff in a serialized form.
4233///
4234/// @param out the output stream to serialize the dif to.
4235///
4236/// @param indent the string to use for indenting the report.
4237void
4238array_diff::report(ostream& out, const string& indent) const
4239{
4240 context()->get_reporter()->report(*this, out, indent);
4241}
4242
4243/// Compute the diff between two arrays.
4244///
4245/// Note that the two types must have been created in the same @ref
4246/// environment, otherwise, this function aborts.
4247///
4248/// @param first the first array to consider for the diff.
4249///
4250/// @param second the second array to consider for the diff.
4251///
4252/// @param ctxt the diff context to use.
4255 array_type_def_sptr second,
4256 diff_context_sptr ctxt)
4257{
4258 diff_sptr element_diff = compute_diff_for_types(first->get_element_type(),
4259 second->get_element_type(),
4260 ctxt);
4261 vector<subrange_diff_sptr> subrange_diffs;
4262 if (first->get_subranges().size() == first->get_subranges().size())
4263 {
4264 for (unsigned i = 0; i < first->get_subranges().size(); ++i)
4265 {
4267 compute_diff(first->get_subranges()[i],
4268 second->get_subranges()[i],
4269 ctxt);
4270 subrange_diffs.push_back(subrange_diff);
4271 }
4272 }
4273 array_diff_sptr result(new array_diff(first, second,
4274 element_diff,
4275 subrange_diffs,
4276 ctxt));
4277 ctxt->initialize_canonical_diff(result);
4278 return result;
4279}
4280// </array_type_def>
4281
4282// <reference_type_def>
4283
4284/// Populate the vector of children node of the @ref diff base type
4285/// sub-object of this instance of @ref reference_diff.
4286///
4287/// The children node can then later be retrieved using
4288/// diff::children_node().
4289void
4292
4293/// Constructor for reference_diff
4294///
4295/// @param first the first reference_type of the diff.
4296///
4297/// @param second the second reference_type of the diff.
4298///
4299/// @param ctxt the diff context to use.
4301 const reference_type_def_sptr second,
4302 diff_sptr underlying,
4303 diff_context_sptr ctxt)
4304 : type_diff_base(first, second, ctxt),
4305 priv_(new priv(underlying))
4306{}
4307
4308/// Getter for the first reference of the diff.
4309///
4310/// @return the first reference of the diff.
4313{return dynamic_pointer_cast<reference_type_def>(first_subject());}
4314
4315/// Getter for the second reference of the diff.
4316///
4317/// @return for the second reference of the diff.
4320{return dynamic_pointer_cast<reference_type_def>(second_subject());}
4321
4322
4323/// Getter for the diff between the two referred-to types.
4324///
4325/// @return the diff between the two referred-to types.
4326const diff_sptr&
4328{return priv_->underlying_type_diff_;}
4329
4330/// Setter for the diff between the two referred-to types.
4331///
4332/// @param d the new diff betweend the two referred-to types.
4333diff_sptr&
4335{
4336 priv_->underlying_type_diff_ = d;
4337 return priv_->underlying_type_diff_;
4338}
4339
4340/// @return the pretty representation for the current instance of @ref
4341/// reference_diff.
4342const string&
4344{
4345 if (diff::priv_->pretty_representation_.empty())
4346 {
4347 std::ostringstream o;
4348 o << "reference_diff["
4349 << first_subject()->get_pretty_representation()
4350 << ", "
4351 << second_subject()->get_pretty_representation()
4352 << "]";
4353 diff::priv_->pretty_representation_ = o.str();
4354 }
4355 return diff::priv_->pretty_representation_;
4356}
4357
4358/// Return true iff the current diff node carries a change.
4359///
4360/// @return true iff the current diff node carries a change.
4361bool
4363{
4364 return first_reference() != second_reference();
4365}
4366
4367/// @return the kind of local change carried by the current diff node.
4368/// The value returned is zero if the current node carries no local
4369/// change.
4370enum change_kind
4372{
4373 ir::change_kind k = ir::NO_CHANGE_KIND;
4374 if (!equals(*first_reference(), *second_reference(), &k))
4375 return k & ir::ALL_LOCAL_CHANGES_MASK;
4376 return ir::NO_CHANGE_KIND;
4377}
4378
4379/// Report the diff in a serialized form.
4380///
4381/// @param out the output stream to serialize the dif to.
4382///
4383/// @param indent the string to use for indenting the report.
4384void
4385reference_diff::report(ostream& out, const string& indent) const
4386{
4387 context()->get_reporter()->report(*this, out, indent);
4388}
4389
4390/// Compute the diff between two references.
4391///
4392/// Note that the two types must have been created in the same @ref
4393/// environment, otherwise, this function aborts.
4394///
4395/// @param first the first reference to consider for the diff.
4396///
4397/// @param second the second reference to consider for the diff.
4398///
4399/// @param ctxt the diff context to use.
4403 diff_context_sptr ctxt)
4404{
4405 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4406 second->get_pointed_to_type(),
4407 ctxt);
4408 reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4409 ctxt->initialize_canonical_diff(result);
4410 return result;
4411}
4412// </reference_type_def>
4413
4414// <ptr_to_mbr_diff stuff>
4415
4416
4417/// Constructor of @ref ptr_to_mbr_diff.
4418///
4419/// @param first the first pointer-to-member subject of the diff.
4420///
4421/// @param second the second pointer-to-member subject of the diff.
4422///
4423/// @param member_type_diff the diff node carrying changes to the
4424/// member type of the pointer-to-member we are considering.
4425///
4426/// @param containing_type_diff the diff node carrying changes to the
4427/// containing type of the pointer-to-member we are considering.
4428///
4429/// @param ctxt the context of the diff we are considering.
4430ptr_to_mbr_diff::ptr_to_mbr_diff(const ptr_to_mbr_type_sptr& first,
4431 const ptr_to_mbr_type_sptr& second,
4432 const diff_sptr& member_type_diff,
4433 const diff_sptr& containing_type_diff,
4434 diff_context_sptr ctxt)
4435 : type_diff_base(first, second, ctxt),
4436 priv_(new priv(member_type_diff, containing_type_diff))
4437{}
4438
4439/// Getter of the first pointer-to-member subject of the current diff
4440/// node.
4441///
4442/// @return the first pointer-to-member subject of the current diff
4443/// node.
4446{return dynamic_pointer_cast<ptr_to_mbr_type>(first_subject());}
4447
4448/// Getter of the second pointer-to-member subject of the current diff
4449/// node.
4450///
4451/// @return the second pointer-to-member subject of the current diff
4452/// node.
4455{return dynamic_pointer_cast<ptr_to_mbr_type>(second_subject());}
4456
4457/// Getter of the diff node carrying changes to the member type of
4458/// first subject of the current diff node.
4459///
4460/// @return The diff node carrying changes to the member type of first
4461/// subject of the current diff node.
4462const diff_sptr
4464{return priv_->member_type_diff_;}
4465
4466/// Getter of the diff node carrying changes to the containing type of
4467/// first subject of the current diff node.
4468///
4469/// @return The diff node carrying changes to the containing type of
4470/// first subject of the current diff node.
4471const diff_sptr
4473{return priv_->containing_type_diff_;}
4474
4475/// Test whether the current diff node carries any change.
4476///
4477/// @return true iff the current diff node carries any change.
4478bool
4483
4484/// Test whether the current diff node carries any local change.
4485///
4486/// @return true iff the current diff node carries any local change.
4487enum change_kind
4489{
4490 ir::change_kind k = ir::NO_CHANGE_KIND;
4492 return k & ir::ALL_LOCAL_CHANGES_MASK;
4493 return ir::NO_CHANGE_KIND;
4494}
4495
4496/// Get the pretty representation of the current @ref ptr_to_mbr_diff
4497/// node.
4498///
4499/// @return the pretty representation of the current diff node.
4500const string&
4502{
4503 if (diff::priv_->pretty_representation_.empty())
4504 {
4505 std::ostringstream o;
4506 o << "ptr_to_mbr_diff["
4507 << first_subject()->get_pretty_representation()
4508 << ", "
4509 << second_subject()->get_pretty_representation()
4510 << "]";
4511 diff::priv_->pretty_representation_ = o.str();
4512 }
4513 return diff::priv_->pretty_representation_;
4514}
4515
4516void
4517ptr_to_mbr_diff::report(ostream& out, const string& indent) const
4518{
4519 context()->get_reporter()->report(*this, out, indent);
4520}
4521
4522/// Populate the vector of children node of the @ref diff base type
4523/// sub-object of this instance of @ref ptr_to_mbr_diff.
4524///
4525/// The children node can then later be retrieved using
4526/// diff::children_node().
4527void
4533
4534/// Destructor of @ref ptr_to_mbr_diff.
4538
4539/// Compute the diff between two @ref ptr_to_mbr_type types.
4540///
4541/// Note that the two types must have been created in the same @ref
4542/// environment, otherwise, this function aborts.
4543///
4544/// @param first the first pointer-to-member type to consider for the diff.
4545///
4546/// @param second the second pointer-to-member type to consider for the diff.
4547///
4548/// @param ctxt the diff context to use.
4551 const ptr_to_mbr_type_sptr& second,
4552 diff_context_sptr& ctxt)
4553{
4554 diff_sptr member_type_diff =
4555 compute_diff(is_type(first->get_member_type()),
4556 is_type(second->get_member_type()),
4557 ctxt);
4558
4559 diff_sptr containing_type_diff =
4560 compute_diff(is_type(first->get_containing_type()),
4561 is_type(second->get_containing_type()),
4562 ctxt);
4563
4564 ptr_to_mbr_diff_sptr result(new ptr_to_mbr_diff(first, second,
4565 member_type_diff,
4566 containing_type_diff,
4567 ctxt));
4568 ctxt->initialize_canonical_diff(result);
4569 return result;
4570}
4571
4572// </ptr_to_mbr_diff stuff>
4573
4574// <qualified_type_diff stuff>
4575
4576/// Populate the vector of children node of the @ref diff base type
4577/// sub-object of this instance of @ref qualified_type_diff.
4578///
4579/// The children node can then later be retrieved using
4580/// diff::children_node().
4581void
4584
4585/// Constructor for qualified_type_diff.
4586///
4587/// @param first the first qualified type of the diff.
4588///
4589/// @param second the second qualified type of the diff.
4590///
4591/// @param ctxt the diff context to use.
4592qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4593 qualified_type_def_sptr second,
4594 diff_sptr under,
4595 diff_context_sptr ctxt)
4596 : type_diff_base(first, second, ctxt),
4597 priv_(new priv(under))
4598{}
4599
4600/// Getter for the first qualified type of the diff.
4601///
4602/// @return the first qualified type of the diff.
4603const qualified_type_def_sptr
4605{return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4606
4607/// Getter for the second qualified type of the diff.
4608///
4609/// @return the second qualified type of the diff.
4610const qualified_type_def_sptr
4612{return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4613
4614/// Getter for the diff between the underlying types of the two
4615/// qualified types.
4616///
4617/// @return the diff between the underlying types of the two qualified
4618/// types.
4621{return priv_->underlying_type_diff;}
4622
4623/// Getter for the diff between the most underlying non-qualified
4624/// types of two qualified types.
4625///
4626/// @return the diff between the most underlying non-qualified types
4627/// of two qualified types.
4630{
4631 if (!priv_->leaf_underlying_type_diff)
4632 priv_->leaf_underlying_type_diff
4633 = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4635 context());
4636
4637 return priv_->leaf_underlying_type_diff;
4638}
4639
4640/// Setter for the diff between the underlying types of the two
4641/// qualified types.
4642///
4643/// @return the diff between the underlying types of the two qualified
4644/// types.
4645void
4647{priv_->underlying_type_diff = d;}
4648
4649/// @return the pretty representation of the current instance of @ref
4650/// qualified_type_diff.
4651const string&
4653{
4654 if (diff::priv_->pretty_representation_.empty())
4655 {
4656 std::ostringstream o;
4657 o << "qualified_type_diff["
4658 << first_subject()->get_pretty_representation()
4659 << ", "
4660 << second_subject()->get_pretty_representation()
4661 << "]";
4662 diff::priv_->pretty_representation_ = o.str();
4663 }
4664 return diff::priv_->pretty_representation_;
4665}
4666
4667/// Return true iff the current diff node carries a change.
4668///
4669/// @return true iff the current diff node carries a change.
4670bool
4673
4674/// @return the kind of local change carried by the current diff node.
4675/// The value returned is zero if the current node carries no local
4676/// change.
4677enum change_kind
4679{
4680 ir::change_kind k = ir::NO_CHANGE_KIND;
4682 return k & ir::ALL_LOCAL_CHANGES_MASK;
4683 return ir::NO_CHANGE_KIND;
4684}
4685
4686/// Report the diff in a serialized form.
4687///
4688/// @param out the output stream to serialize to.
4689///
4690/// @param indent the string to use to indent the lines of the report.
4691void
4692qualified_type_diff::report(ostream& out, const string& indent) const
4693{
4694 context()->get_reporter()->report(*this, out, indent);
4695}
4696
4697/// Compute the diff between two qualified types.
4698///
4699/// Note that the two types must have been created in the same @ref
4700/// environment, otherwise, this function aborts.
4701///
4702/// @param first the first qualified type to consider for the diff.
4703///
4704/// @param second the second qualified type to consider for the diff.
4705///
4706/// @param ctxt the diff context to use.
4707qualified_type_diff_sptr
4708compute_diff(const qualified_type_def_sptr first,
4709 const qualified_type_def_sptr second,
4710 diff_context_sptr ctxt)
4711{
4712 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4713 second->get_underlying_type(),
4714 ctxt);
4715 qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4716 d, ctxt));
4717 ctxt->initialize_canonical_diff(result);
4718 return result;
4719}
4720
4721// </qualified_type_diff stuff>
4722
4723// <enum_diff stuff>
4724
4725/// Clear the lookup tables useful for reporting an enum_diff.
4726///
4727/// This function must be updated each time a lookup table is added or
4728/// removed from the class_diff::priv.
4729void
4730enum_diff::clear_lookup_tables()
4731{
4732 priv_->deleted_enumerators_.clear();
4733 priv_->inserted_enumerators_.clear();
4734 priv_->changed_enumerators_.clear();
4735}
4736
4737/// Tests if the lookup tables are empty.
4738///
4739/// @return true if the lookup tables are empty, false otherwise.
4740bool
4741enum_diff::lookup_tables_empty() const
4742{
4743 return (priv_->deleted_enumerators_.empty()
4744 && priv_->inserted_enumerators_.empty()
4745 && priv_->changed_enumerators_.empty());
4746}
4747
4748/// If the lookup tables are not yet built, walk the differences and
4749/// fill the lookup tables.
4750void
4751enum_diff::ensure_lookup_tables_populated()
4752{
4753 if (!lookup_tables_empty())
4754 return;
4755
4756 {
4757 edit_script e = priv_->enumerators_changes_;
4758
4759 for (vector<deletion>::const_iterator it = e.deletions().begin();
4760 it != e.deletions().end();
4761 ++it)
4762 {
4763 unsigned i = it->index();
4764 const enum_type_decl::enumerator& n =
4765 first_enum()->get_enumerators()[i];
4766 const string& name = n.get_name();
4767 ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4768 == priv_->deleted_enumerators_.end());
4769 priv_->deleted_enumerators_[name] = n;
4770 }
4771
4772 for (vector<insertion>::const_iterator it = e.insertions().begin();
4773 it != e.insertions().end();
4774 ++it)
4775 {
4776 for (vector<unsigned>::const_iterator iit =
4777 it->inserted_indexes().begin();
4778 iit != it->inserted_indexes().end();
4779 ++iit)
4780 {
4781 unsigned i = *iit;
4782 const enum_type_decl::enumerator& n =
4783 second_enum()->get_enumerators()[i];
4784 const string& name = n.get_name();
4785 ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4786 == priv_->inserted_enumerators_.end());
4787 string_enumerator_map::const_iterator j =
4788 priv_->deleted_enumerators_.find(name);
4789 if (j == priv_->deleted_enumerators_.end())
4790 priv_->inserted_enumerators_[name] = n;
4791 else
4792 {
4793 if (j->second != n)
4794 priv_->changed_enumerators_[j->first] =
4795 std::make_pair(j->second, n);
4796 priv_->deleted_enumerators_.erase(j);
4797 }
4798 }
4799 }
4800
4801 // If a new enumerator is added with a value that already existed
4802 // in the old enum but with a new name, then populate the
4803 // enum_diff::priv_::changed_enumerators_ data member with a
4804 // change that represents a change to an enumerator name. The
4805 // enum_diff::priv_::inserted_enumerators_ is adjusted accordingly
4806 // an the 'new' enumerator is removed in this case.
4807
4808 enum_type_decl::enumerators enums_to_erase;
4809 for (auto& entry : priv_->inserted_enumerators_)
4810 {
4811 enum_type_decl::enumerator& final_enumerator = entry.second;
4812 enum_type_decl::enumerator initial_enumerator;
4813 if (first_enum()->find_enumerator_by_value(entry.second.get_value(),
4814 initial_enumerator))
4815 {
4816 enum_type_decl::enumerator foo;
4817 if (!second_enum()->
4818 find_enumerator_by_name(initial_enumerator.get_name(),
4819 foo))
4820 {
4821 priv_->changed_enumerators_[initial_enumerator.get_name()] =
4822 std::make_pair(initial_enumerator, final_enumerator);
4823 enums_to_erase.push_back(final_enumerator);
4824 }
4825 }
4826 }
4827
4828 for (auto& enomerator : enums_to_erase)
4829 priv_->inserted_enumerators_.erase(enomerator.get_name());
4830
4831 // If an enumerator is deleted yet its value (with a new name) is
4832 // still present among enumerators of the newer enum then populate
4833 // the enum_diff::priv_::changed_enumerators_ data member with a
4834 // change that represents a change to an enumerator name. The
4835 // enum_diff::priv_::deleted_enumerators_ is adjusted accordingly
4836 // an the 'new' enumerator is removed in this case.
4837
4838 enums_to_erase.clear();
4839 for (auto& entry : priv_->deleted_enumerators_)
4840 {
4841 enum_type_decl::enumerator& initial_enumerator = entry.second;
4842 enum_type_decl::enumerator final_enumerator;
4843 if (second_enum()->find_enumerator_by_value(entry.second.get_value(),
4844 final_enumerator))
4845 {
4846 enum_type_decl::enumerator foo;
4847 if (!first_enum()->
4848 find_enumerator_by_name(final_enumerator.get_name(),
4849 foo))
4850 {
4851 priv_->changed_enumerators_[initial_enumerator.get_name()] =
4852 std::make_pair(initial_enumerator, final_enumerator);
4853 enums_to_erase.push_back(initial_enumerator);
4854 }
4855 }
4856 }
4857
4858 for (auto& enomerator : enums_to_erase)
4859 priv_->deleted_enumerators_.erase(enomerator.get_name());
4860 }
4861}
4862
4863/// Populate the vector of children node of the @ref diff base type
4864/// sub-object of this instance of @ref enum_diff.
4865///
4866/// The children node can then later be retrieved using
4867/// diff::children_node().
4868void
4871
4872/// Constructor for enum_diff.
4873///
4874/// @param first the first enum type of the diff.
4875///
4876/// @param second the second enum type of the diff.
4877///
4878/// @param underlying_type_diff the diff of the two underlying types
4879/// of the two enum types.
4880///
4881/// @param ctxt the diff context to use.
4883 const enum_type_decl_sptr second,
4884 const diff_sptr underlying_type_diff,
4885 const diff_context_sptr ctxt)
4886 : type_diff_base(first, second, ctxt),
4887 priv_(new priv(underlying_type_diff))
4888{}
4889
4890/// @return the first enum of the diff.
4893{return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4894
4895/// @return the second enum of the diff.
4898{return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4899
4900/// @return the diff of the two underlying enum types.
4903{return priv_->underlying_type_diff_;}
4904
4905/// @return a map of the enumerators that were deleted.
4908{return priv_->deleted_enumerators_;}
4909
4910/// @return a map of the enumerators that were inserted
4913{return priv_->inserted_enumerators_;}
4914
4915/// @return a map of the enumerators that were changed
4918{return priv_->changed_enumerators_;}
4919
4920/// @return the pretty representation of the current instance of @ref
4921/// enum_diff.
4922const string&
4924{
4925 if (diff::priv_->pretty_representation_.empty())
4926 {
4927 std::ostringstream o;
4928 o << "enum_diff["
4929 << first_subject()->get_pretty_representation()
4930 << ", "
4931 << second_subject()->get_pretty_representation()
4932 << "]";
4933 diff::priv_->pretty_representation_ = o.str();
4934 }
4935 return diff::priv_->pretty_representation_;
4936}
4937
4938/// Return true iff the current diff node carries a change.
4939///
4940/// @return true iff the current diff node carries a change.
4941bool
4943{return first_enum() != second_enum();}
4944
4945/// @return the kind of local change carried by the current diff node.
4946/// The value returned is zero if the current node carries no local
4947/// change.
4948enum change_kind
4950{
4951 ir::change_kind k = ir::NO_CHANGE_KIND;
4952 if (!equals(*first_enum(), *second_enum(), &k))
4953 return k & ir::ALL_LOCAL_CHANGES_MASK;
4954 return ir::NO_CHANGE_KIND;
4955}
4956
4957/// Report the differences between the two enums.
4958///
4959/// @param out the output stream to send the report to.
4960///
4961/// @param indent the string to use for indentation.
4962void
4963enum_diff::report(ostream& out, const string& indent) const
4964{
4965 context()->get_reporter()->report(*this, out, indent);
4966}
4967
4968/// Compute the set of changes between two instances of @ref
4969/// enum_type_decl.
4970///
4971/// Note that the two types must have been created in the same @ref
4972/// environment, otherwise, this function aborts.
4973///
4974/// @param first a pointer to the first enum_type_decl to consider.
4975///
4976/// @param second a pointer to the second enum_type_decl to consider.
4977///
4978/// @return the resulting diff of the two enums @p first and @p
4979/// second.
4980///
4981/// @param ctxt the diff context to use.
4982enum_diff_sptr
4984 const enum_type_decl_sptr second,
4985 diff_context_sptr ctxt)
4986{
4987 diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4988 second->get_underlying_type(),
4989 ctxt);
4990 enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4991 if (first != second)
4992 {
4993 compute_diff(first->get_enumerators().begin(),
4994 first->get_enumerators().end(),
4995 second->get_enumerators().begin(),
4996 second->get_enumerators().end(),
4997 d->priv_->enumerators_changes_);
4998 d->ensure_lookup_tables_populated();
4999 }
5000 ctxt->initialize_canonical_diff(d);
5001
5002 return d;
5003}
5004// </enum_diff stuff>
5005
5006// <class_or_union_diff stuff>
5007
5008/// Test if the current diff node carries a member type change for a
5009/// member type which name is the same as the name of a given type
5010/// declaration.
5011///
5012/// @param d the type declaration which name should be equal to the
5013/// name of the member type that might have changed.
5014///
5015/// @return the member type that has changed, iff there were a member
5016/// type (which name is the same as the name of @p d) that changed.
5017/// Note that the member type that is returned is the new value of the
5018/// member type that changed.
5021{
5022 string qname = d->get_qualified_name();
5023 string_diff_sptr_map::const_iterator it =
5024 changed_member_types_.find(qname);
5025
5026 return ((it == changed_member_types_.end())
5028 : it->second->second_subject());
5029}
5030
5031/// Test if the current diff node carries a data member change for a
5032/// data member which name is the same as the name of a given type
5033/// declaration.
5034///
5035/// @param d the type declaration which name should be equal to the
5036/// name of the data member that might have changed.
5037///
5038/// @return the data member that has changed, iff there were a data
5039/// member type (which name is the same as the name of @p d) that
5040/// changed. Note that the data member that is returned is the new
5041/// value of the data member that changed.
5042decl_base_sptr
5044{
5045 string qname = d->get_qualified_name();
5046 string_var_diff_sptr_map::const_iterator it =
5047 subtype_changed_dm_.find(qname);
5048
5049 if (it == subtype_changed_dm_.end())
5050 return decl_base_sptr();
5051 return it->second->second_var();
5052}
5053
5054/// Test if the current diff node carries a member class template
5055/// change for a member class template which name is the same as the
5056/// name of a given type declaration.
5057///
5058/// @param d the type declaration which name should be equal to the
5059/// name of the member class template that might have changed.
5060///
5061/// @return the member class template that has changed, iff there were
5062/// a member class template (which name is the same as the name of @p
5063/// d) that changed. Note that the member class template that is
5064/// returned is the new value of the member class template that
5065/// changed.
5066decl_base_sptr
5068{
5069 string qname = d->get_qualified_name();
5070 string_diff_sptr_map::const_iterator it =
5071 changed_member_class_tmpls_.find(qname);
5072
5073 return ((it == changed_member_class_tmpls_.end())
5074 ? decl_base_sptr()
5075 : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
5076}
5077
5078/// Get the number of non static data members that were deleted.
5079///
5080/// @return the number of non static data members that were deleted.
5081size_t
5083{
5084 size_t result = 0;
5085
5086 for (string_decl_base_sptr_map::const_iterator i =
5087 deleted_data_members_.begin();
5088 i != deleted_data_members_.end();
5089 ++i)
5090 if (is_member_decl(i->second)
5091 && !get_member_is_static(i->second))
5092 ++result;
5093
5094 return result;
5095}
5096
5097/// Get the number of non static data members that were inserted.
5098///
5099/// @return the number of non static data members that were inserted.
5100size_t
5102{
5103 size_t result = 0;
5104
5105 for (string_decl_base_sptr_map::const_iterator i =
5106 inserted_data_members_.begin();
5107 i != inserted_data_members_.end();
5108 ++i)
5109 if (is_member_decl(i->second)
5110 && !get_member_is_static(i->second))
5111 ++result;
5112
5113 return result;
5114}
5115
5116/// Get the number of data member sub-type changes carried by the
5117/// current diff node that were filtered out.
5118///
5119/// @param local_only if true, it means that only (filtered) local
5120/// changes are considered.
5121///
5122/// @return the number of data member sub-type changes carried by the
5123/// current diff node that were filtered out.
5124size_t
5126{
5127 size_t num_filtered= 0;
5128 for (var_diff_sptrs_type::const_iterator i =
5129 sorted_subtype_changed_dm_.begin();
5130 i != sorted_subtype_changed_dm_.end();
5131 ++i)
5132 {
5133 if (local_only)
5134 {
5135 if ((*i)->has_local_changes() && (*i)->is_filtered_out())
5136 ++num_filtered;
5137 }
5138 else
5139 {
5140 if ((*i)->is_filtered_out())
5141 ++num_filtered;
5142 }
5143 }
5144 return num_filtered;
5145}
5146
5147/// Get the number of data member changes carried by the current diff
5148/// node that were filtered out.
5149///
5150/// @param local_only if true, it means that only (filtered) local
5151/// changes are considered.
5152///
5153/// @return the number of data member changes carried by the current
5154/// diff node that were filtered out.
5155size_t
5157{
5158 size_t num_filtered= 0;
5159
5160 for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
5161 i != changed_dm_.end();
5162 ++i)
5163 {
5164 diff_sptr diff = i->second;
5165 if (local_only)
5166 {
5167 if (diff->has_changes() && diff->is_filtered_out())
5168 ++num_filtered;
5169 }
5170 else
5171 {
5172 if (diff->is_filtered_out())
5173 ++num_filtered;
5174 }
5175 }
5176 return num_filtered;
5177}
5178
5179/// Skip the processing of the current member function if its
5180/// virtual-ness is disallowed by the user.
5181///
5182/// This is to be used in the member functions below that are used to
5183/// count the number of filtered inserted, deleted and changed member
5184/// functions.
5185#define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
5186 do { \
5187 if (get_member_function_is_virtual(f) \
5188 || get_member_function_is_virtual(s)) \
5189 { \
5190 if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
5191 continue; \
5192 } \
5193 else \
5194 { \
5195 if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
5196 continue; \
5197 } \
5198 } while (false)
5199
5200/// Get the number of member functions changes carried by the current
5201/// diff node that were filtered out.
5202///
5203/// @return the number of member functions changes carried by the
5204/// current diff node that were filtered out.
5205size_t
5207(const diff_context_sptr& ctxt)
5208{
5209 size_t count = 0;
5210 diff_category allowed_category = ctxt->get_allowed_category();
5211
5212 for (function_decl_diff_sptrs_type::const_iterator i =
5213 sorted_changed_member_functions_.begin();
5214 i != sorted_changed_member_functions_.end();
5215 ++i)
5216 {
5217 method_decl_sptr f =
5218 dynamic_pointer_cast<method_decl>
5219 ((*i)->first_function_decl());
5220 ABG_ASSERT(f);
5221
5222 method_decl_sptr s =
5223 dynamic_pointer_cast<method_decl>
5224 ((*i)->second_function_decl());
5225 ABG_ASSERT(s);
5226
5228
5229 diff_sptr diff = *i;
5230 ctxt->maybe_apply_filters(diff);
5231
5232 if (diff->is_filtered_out())
5233 ++count;
5234 }
5235
5236 return count;
5237}
5238
5239/// Get the number of member functions insertions carried by the current
5240/// diff node that were filtered out.
5241///
5242/// @return the number of member functions insertions carried by the
5243/// current diff node that were filtered out.
5244size_t
5246(const diff_context_sptr& ctxt)
5247{
5248 size_t count = 0;
5249 diff_category allowed_category = ctxt->get_allowed_category();
5250
5251 for (string_member_function_sptr_map::const_iterator i =
5252 inserted_member_functions_.begin();
5253 i != inserted_member_functions_.end();
5254 ++i)
5255 {
5256 method_decl_sptr f = i->second,
5257 s = i->second;
5258
5260
5261 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5262 ctxt->maybe_apply_filters(diff);
5263
5265 && diff->is_filtered_out())
5266 ++count;
5267 }
5268
5269 return count;
5270}
5271
5272/// Get the number of member functions deletions carried by the current
5273/// diff node that were filtered out.
5274///
5275/// @return the number of member functions deletions carried by the
5276/// current diff node that were filtered out.
5277size_t
5279(const diff_context_sptr& ctxt)
5280{
5281 size_t count = 0;
5282 diff_category allowed_category = ctxt->get_allowed_category();
5283
5284 for (string_member_function_sptr_map::const_iterator i =
5285 deleted_member_functions_.begin();
5286 i != deleted_member_functions_.end();
5287 ++i)
5288 {
5289 method_decl_sptr f = i->second,
5290 s = i->second;
5291
5293
5294 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5295 ctxt->maybe_apply_filters(diff);
5296
5298 && diff->is_filtered_out())
5299 ++count;
5300 }
5301
5302 return count;
5303}
5304
5305/// Clear the lookup tables useful for reporting.
5306///
5307/// This function must be updated each time a lookup table is added or
5308/// removed from the class_or_union_diff::priv.
5309void
5311{
5312 priv_->deleted_member_types_.clear();
5313 priv_->inserted_member_types_.clear();
5314 priv_->changed_member_types_.clear();
5315 priv_->deleted_data_members_.clear();
5316 priv_->inserted_data_members_.clear();
5317 priv_->subtype_changed_dm_.clear();
5318 priv_->deleted_member_functions_.clear();
5319 priv_->inserted_member_functions_.clear();
5320 priv_->changed_member_functions_.clear();
5321 priv_->deleted_member_class_tmpls_.clear();
5322 priv_->inserted_member_class_tmpls_.clear();
5323 priv_->changed_member_class_tmpls_.clear();
5324}
5325
5326/// Tests if the lookup tables are empty.
5327///
5328/// @return true if the lookup tables are empty, false otherwise.
5329bool
5331{
5332 return (priv_->deleted_member_types_.empty()
5333 && priv_->inserted_member_types_.empty()
5334 && priv_->changed_member_types_.empty()
5335 && priv_->deleted_data_members_.empty()
5336 && priv_->inserted_data_members_.empty()
5337 && priv_->subtype_changed_dm_.empty()
5338 && priv_->inserted_member_functions_.empty()
5339 && priv_->deleted_member_functions_.empty()
5340 && priv_->changed_member_functions_.empty()
5341 && priv_->deleted_member_class_tmpls_.empty()
5342 && priv_->inserted_member_class_tmpls_.empty()
5343 && priv_->changed_member_class_tmpls_.empty());
5344}
5345
5346/// If the lookup tables are not yet built, walk the differences and
5347/// fill them.
5348void
5350{
5351 {
5352 edit_script& e = priv_->member_types_changes_;
5353
5354 for (vector<deletion>::const_iterator it = e.deletions().begin();
5355 it != e.deletions().end();
5356 ++it)
5357 {
5358 unsigned i = it->index();
5359 decl_base_sptr d =
5360 get_type_declaration(first_class_or_union()->get_member_types()[i]);
5361 class_or_union_sptr record_type = is_class_or_union_type(d);
5362 if (record_type && record_type->get_is_declaration_only())
5363 continue;
5364 string name = d->get_name();
5365 priv_->deleted_member_types_[name] = d;
5366 }
5367
5368 for (vector<insertion>::const_iterator it = e.insertions().begin();
5369 it != e.insertions().end();
5370 ++it)
5371 {
5372 for (vector<unsigned>::const_iterator iit =
5373 it->inserted_indexes().begin();
5374 iit != it->inserted_indexes().end();
5375 ++iit)
5376 {
5377 unsigned i = *iit;
5378 decl_base_sptr d =
5379 get_type_declaration(second_class_or_union()->get_member_types()[i]);
5380 class_or_union_sptr record_type = is_class_or_union_type(d);
5381 if (record_type && record_type->get_is_declaration_only())
5382 continue;
5383 string name = d->get_name();
5384 string_decl_base_sptr_map::const_iterator j =
5385 priv_->deleted_member_types_.find(name);
5386 if (j != priv_->deleted_member_types_.end())
5387 {
5388 if (*j->second != *d)
5389 priv_->changed_member_types_[name] =
5390 compute_diff(j->second, d, context());
5391
5392 priv_->deleted_member_types_.erase(j);
5393 }
5394 else
5395 priv_->inserted_member_types_[name] = d;
5396 }
5397 }
5398 }
5399
5400 {
5401 edit_script& e = priv_->data_members_changes_;
5402
5403 for (vector<deletion>::const_iterator it = e.deletions().begin();
5404 it != e.deletions().end();
5405 ++it)
5406 {
5407 unsigned i = it->index();
5408 var_decl_sptr data_member =
5409 is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
5410 string name = data_member->get_anon_dm_reliable_name();
5411 priv_->deleted_data_members_[name] = data_member;
5412 }
5413
5414 for (vector<insertion>::const_iterator it = e.insertions().begin();
5415 it != e.insertions().end();
5416 ++it)
5417 {
5418 for (vector<unsigned>::const_iterator iit =
5419 it->inserted_indexes().begin();
5420 iit != it->inserted_indexes().end();
5421 ++iit)
5422 {
5423 unsigned i = *iit;
5424 decl_base_sptr d =
5425 second_class_or_union()->get_non_static_data_members()[i];
5426 var_decl_sptr added_dm = is_var_decl(d);
5427 string name = added_dm->get_anon_dm_reliable_name();
5428 ABG_ASSERT(priv_->inserted_data_members_.find(name)
5429 == priv_->inserted_data_members_.end());
5430
5431 bool ignore_added_anonymous_data_member = false;
5432 if (is_anonymous_data_member(added_dm))
5433 {
5434 //
5435 // Handle insertion of anonymous data member to
5436 // replace existing data members.
5437 //
5438 // For instance consider this:
5439 // struct S
5440 // {
5441 // int a;
5442 // int b;
5443 // int c;
5444 // };// end struct S
5445 //
5446 // Where the data members 'a' and 'b' are replaced
5447 // by an anonymous data member without changing the
5448 // effective bit layout of the structure:
5449 //
5450 // struct S
5451 // {
5452 // struct
5453 // {
5454 // union
5455 // {
5456 // int a;
5457 // char a_1;
5458 // };
5459 // union
5460 // {
5461 // int b;
5462 // char b_1;
5463 // };
5464 // };
5465 // int c;
5466 // }; // end struct S
5467 //
5468 var_decl_sptr replaced_dm, replacing_dm;
5469 bool added_anon_dm_changes_dm = false;
5470 // The vector of data members replaced by anonymous
5471 // data members.
5472 vector<var_decl_sptr> dms_replaced_by_anon_dm;
5473
5474 //
5475 // Let's start collecting the set of data members
5476 // which have been replaced by anonymous types in a
5477 // harmless way. These are going to be collected into
5478 // dms_replaced_by_anon_dm and, ultimately, into
5479 // priv_->dms_replaced_by_adms_
5480 //
5481 for (string_decl_base_sptr_map::const_iterator it =
5482 priv_->deleted_data_members_.begin();
5483 it != priv_->deleted_data_members_.end();
5484 ++it)
5485 {
5486 // We don't support this pattern for anonymous
5487 // data members themselves being replaced. If
5488 // that occurs then we'll just report it verbatim.
5489 if (is_anonymous_data_member(it->second))
5490 continue;
5491
5492 string deleted_dm_name = it->second->get_name();
5493 if ((replacing_dm =
5495 deleted_dm_name)))
5496 {
5497 // So it looks like replacing_dm might have
5498 // replaced the data member which name is
5499 // 'deleted_dm_name'. Let's look deeper to be
5500 // sure.
5501 //
5502 // Note that replacing_dm is part (member) of
5503 // an anonymous data member that might replace
5504 // replaced_dm.
5505
5506 // So let's get that replaced data member.
5507 replaced_dm = is_var_decl(it->second);
5508 size_t replaced_dm_offset =
5509 get_data_member_offset(replaced_dm),
5510 replacing_dm_offset =
5511 get_absolute_data_member_offset(replacing_dm);
5512
5513 if (replaced_dm_offset != replacing_dm_offset)
5514 {
5515 // So the replacing data member and the
5516 // replaced data member don't have the
5517 // same offset. This is not the pattern we
5518 // are looking for. Rather, it looks like
5519 // the anonymous data member has *changed*
5520 // the data member.
5521 added_anon_dm_changes_dm = true;
5522 break;
5523 }
5524
5525 if (replaced_dm->get_type()->get_size_in_bits()
5526 == replaced_dm->get_type()->get_size_in_bits())
5527 dms_replaced_by_anon_dm.push_back(replaced_dm);
5528 else
5529 {
5530 added_anon_dm_changes_dm = true;
5531 break;
5532 }
5533 }
5534 }
5535
5536 // Now walk dms_replaced_by_anon_dm to fill up
5537 // priv_->dms_replaced_by_adms_ with the set of data
5538 // members replaced by anonymous data members.
5539 if (!added_anon_dm_changes_dm
5540 && !dms_replaced_by_anon_dm.empty())
5541 {
5542 // See if the added data member isn't too big.
5543 type_base_sptr added_dm_type = added_dm->get_type();
5544 ABG_ASSERT(added_dm_type);
5545 var_decl_sptr new_next_dm =
5547 added_dm);
5548 var_decl_sptr old_next_dm =
5549 first_class_or_union()->find_data_member(new_next_dm);
5550
5551 if (!old_next_dm
5552 || (old_next_dm
5553 && (get_absolute_data_member_offset(old_next_dm)
5554 == get_absolute_data_member_offset(new_next_dm))))
5555 {
5556 // None of the data members that are replaced
5557 // by the added union should be considered as
5558 // having been deleted.
5559 ignore_added_anonymous_data_member = true;
5560 for (vector<var_decl_sptr>::const_iterator i =
5561 dms_replaced_by_anon_dm.begin();
5562 i != dms_replaced_by_anon_dm.end();
5563 ++i)
5564 {
5565 string n = (*i)->get_name();
5566 priv_->dms_replaced_by_adms_[n] =
5567 added_dm;
5568 priv_->deleted_data_members_.erase(n);
5569 }
5570 }
5571 }
5572 }
5573
5574 if (!ignore_added_anonymous_data_member)
5575 {
5576 // Detect changed data members.
5577 //
5578 // A changed data member (that we shall name D) is a data
5579 // member that satisfies the conditions below:
5580 //
5581 // 1/ It must have been added.
5582 //
5583 // 2/ It must have been deleted as well.
5584 //
5585 // 3/ There must be a non-empty difference between the
5586 // deleted D and the added D.
5587 string_decl_base_sptr_map::const_iterator j =
5588 priv_->deleted_data_members_.find(name);
5589 if (j != priv_->deleted_data_members_.end())
5590 {
5591 if (*j->second != *d)
5592 {
5593 var_decl_sptr old_dm = is_var_decl(j->second);
5594 priv_->subtype_changed_dm_[name]=
5595 compute_diff(old_dm, added_dm, context());
5596 }
5597 priv_->deleted_data_members_.erase(j);
5598 }
5599 else
5600 priv_->inserted_data_members_[name] = d;
5601 }
5602 }
5603 }
5604
5605 // Now detect when a data member is deleted from offset N and
5606 // another one is added to offset N. In that case, we want to be
5607 // able to say that the data member at offset N changed.
5608 for (string_decl_base_sptr_map::const_iterator i =
5609 priv_->deleted_data_members_.begin();
5610 i != priv_->deleted_data_members_.end();
5611 ++i)
5612 {
5613 unsigned offset = get_data_member_offset(i->second);
5614 priv_->deleted_dm_by_offset_[offset] = i->second;
5615 }
5616
5617 for (string_decl_base_sptr_map::const_iterator i =
5618 priv_->inserted_data_members_.begin();
5619 i != priv_->inserted_data_members_.end();
5620 ++i)
5621 {
5622 unsigned offset = get_data_member_offset(i->second);
5623 priv_->inserted_dm_by_offset_[offset] = i->second;
5624 }
5625
5626 for (unsigned_decl_base_sptr_map::const_iterator i =
5627 priv_->inserted_dm_by_offset_.begin();
5628 i != priv_->inserted_dm_by_offset_.end();
5629 ++i)
5630 {
5631 unsigned_decl_base_sptr_map::const_iterator j =
5632 priv_->deleted_dm_by_offset_.find(i->first);
5633 if (j != priv_->deleted_dm_by_offset_.end())
5634 {
5635 var_decl_sptr old_dm = is_var_decl(j->second);
5636 var_decl_sptr new_dm = is_var_decl(i->second);
5637 priv_->changed_dm_[i->first] =
5638 compute_diff(old_dm, new_dm, context());
5639 }
5640 }
5641
5642 for (unsigned_var_diff_sptr_map::const_iterator i =
5643 priv_->changed_dm_.begin();
5644 i != priv_->changed_dm_.end();
5645 ++i)
5646 {
5647 priv_->deleted_dm_by_offset_.erase(i->first);
5648 priv_->inserted_dm_by_offset_.erase(i->first);
5649 priv_->deleted_data_members_.erase
5650 (i->second->first_var()->get_anon_dm_reliable_name());
5651 priv_->inserted_data_members_.erase
5652 (i->second->second_var()->get_anon_dm_reliable_name());
5653 }
5654
5655 // Now detect anonymous data members that might appear as deleted
5656 // even though all their data members are still present. Consider
5657 // these as being non-deleted.
5658 string_decl_base_sptr_map non_anonymous_dms_in_second_class;
5660 non_anonymous_dms_in_second_class);
5661 vector<string> deleted_data_members_to_delete;
5662 // Walk data members considered deleted ...
5663 for (auto& entry : priv_->deleted_data_members_)
5664 {
5665 var_decl_sptr data_member = is_var_decl(entry.second);
5666 ABG_ASSERT(data_member);
5667 if (is_anonymous_data_member(data_member))
5668 {
5669 // Let's look at this anonymous data member that is
5670 // considered deleted because it's moved from where it was
5671 // initially, at very least. If its leaf data members are
5672 // still present in the second class then, we won't
5673 // consider it as deleted.
5674 class_or_union_sptr cou = anonymous_data_member_to_class_or_union(data_member);
5675 ABG_ASSERT(cou);
5676 string_decl_base_sptr_map non_anonymous_data_members;
5677 // Lets collect the leaf data members of the anonymous
5678 // data member.
5679 collect_non_anonymous_data_members(cou, non_anonymous_data_members);
5680 bool anonymous_dm_members_present = true;
5681 // Let's see if at least one of the leaf members of the
5682 // anonymous data member is NOT present in the second
5683 // version of the class.
5684 for (auto& e : non_anonymous_data_members)
5685 {
5686 if (non_anonymous_dms_in_second_class.find(e.first)
5687 == non_anonymous_dms_in_second_class.end())
5688 // Grrr, OK, it looks like at least one leaf data
5689 // member of the original anonymous data member was
5690 // removed from the class, so yeah, the anonymous
5691 // data member might have been removed after all.
5692 anonymous_dm_members_present = false;
5693 }
5694 if (anonymous_dm_members_present)
5695 // All leaf data members of the anonymous data member
5696 // are still present in the second version of the class.
5697 // So let's mark that anonymous data member as NOT being
5698 // deleted.
5699 deleted_data_members_to_delete.push_back(data_member->get_anon_dm_reliable_name());
5700 }
5701 }
5702 // All anonymous data members that were recognized as being NOT
5703 // deleted should be removed from the set of deleted data members
5704 // now.
5705 for (string& name_of_dm_to_delete: deleted_data_members_to_delete)
5706 priv_->deleted_data_members_.erase(name_of_dm_to_delete);
5707 }
5708 sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5709 priv_->sorted_subtype_changed_dm_);
5710 sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5711 priv_->sorted_changed_dm_);
5712
5713 {
5714 edit_script& e = priv_->member_class_tmpls_changes_;
5715
5716 for (vector<deletion>::const_iterator it = e.deletions().begin();
5717 it != e.deletions().end();
5718 ++it)
5719 {
5720 unsigned i = it->index();
5721 decl_base_sptr d =
5722 first_class_or_union()->get_member_class_templates()[i]->
5723 as_class_tdecl();
5724 string name = d->get_name();
5725 ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5726 == priv_->deleted_member_class_tmpls_.end());
5727 priv_->deleted_member_class_tmpls_[name] = d;
5728 }
5729
5730 for (vector<insertion>::const_iterator it = e.insertions().begin();
5731 it != e.insertions().end();
5732 ++it)
5733 {
5734 for (vector<unsigned>::const_iterator iit =
5735 it->inserted_indexes().begin();
5736 iit != it->inserted_indexes().end();
5737 ++iit)
5738 {
5739 unsigned i = *iit;
5740 decl_base_sptr d =
5741 second_class_or_union()->get_member_class_templates()[i]->
5742 as_class_tdecl();
5743 string name = d->get_name();
5744 ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5745 == priv_->inserted_member_class_tmpls_.end());
5746 string_decl_base_sptr_map::const_iterator j =
5747 priv_->deleted_member_class_tmpls_.find(name);
5748 if (j != priv_->deleted_member_class_tmpls_.end())
5749 {
5750 if (*j->second != *d)
5751 priv_->changed_member_types_[name]=
5752 compute_diff(j->second, d, context());
5753 priv_->deleted_member_class_tmpls_.erase(j);
5754 }
5755 else
5756 priv_->inserted_member_class_tmpls_[name] = d;
5757 }
5758 }
5759 }
5760 sort_string_diff_sptr_map(priv_->changed_member_types_,
5761 priv_->sorted_changed_member_types_);
5762}
5763
5764/// Allocate the memory for the priv_ pimpl data member of the @ref
5765/// class_or_union_diff class.
5766void
5768{
5769 if (!priv_)
5770 priv_.reset(new priv);
5771}
5772
5773/// Constructor for the @ref class_or_union_diff class.
5774///
5775/// @param first_scope the first @ref class_or_union of the diff node.
5776///
5777/// @param second_scope the second @ref class_or_union of the diff node.
5778///
5779/// @param ctxt the context of the diff.
5780class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5781 class_or_union_sptr second_scope,
5782 diff_context_sptr ctxt)
5783 : type_diff_base(first_scope, second_scope, ctxt)
5784 //priv_(new priv)
5785{}
5786
5787/// Getter of the private data of the @ref class_or_union_diff type.
5788///
5789/// Note that due to an optimization, the private data of @ref
5790/// class_or_union_diff can be shared among several instances of
5791/// class_or_union_diff, so you should never try to access
5792/// class_or_union_diff::priv directly.
5793///
5794/// When class_or_union_diff::priv is shared, this function returns
5795/// the correct shared one.
5796///
5797/// @return the (possibly) shared private data of the current instance
5798/// of @ref class_or_union_diff.
5799const class_or_union_diff::priv_ptr&
5801{
5802 if (priv_)
5803 return priv_;
5804
5805 // If the current class_or_union_diff::priv member is empty, then look for
5806 // the shared one, from the canonical type.
5807 class_or_union_diff *canonical =
5808 dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5809 ABG_ASSERT(canonical);
5810 ABG_ASSERT(canonical->priv_);
5811
5812 return canonical->priv_;
5813}
5814
5815/// Destructor of class_or_union_diff.
5819
5820/// @return the first @ref class_or_union involved in the diff.
5821class_or_union_sptr
5824
5825/// @return the second @ref class_or_union involved in the diff.
5826class_or_union_sptr
5829
5830/// @return the edit script of the member types of the two @ref
5831/// class_or_union.
5832const edit_script&
5834{return get_priv()->member_types_changes_;}
5835
5836/// @return the edit script of the member types of the two @ref
5837/// class_or_union.
5840{return get_priv()->member_types_changes_;}
5841
5842/// @return the edit script of the data members of the two @ref
5843/// class_or_union.
5844const edit_script&
5846{return get_priv()->data_members_changes_;}
5847
5848/// @return the edit script of the data members of the two @ref
5849/// class_or_union.
5852{return get_priv()->data_members_changes_;}
5853
5854/// Getter for the data members that got inserted.
5855///
5856/// @return a map of data members that got inserted.
5859{return get_priv()->inserted_data_members_;}
5860
5861/// Getter for the data members that got deleted.
5862///
5863/// @return a map of data members that got deleted.
5866{return get_priv()->deleted_data_members_;}
5867
5868/// @return the edit script of the member functions of the two @ref
5869/// class_or_union.
5870const edit_script&
5872{return get_priv()->member_fns_changes_;}
5873
5874/// Getter for the virtual members functions that have had a change in
5875/// a sub-type, without having a change in their symbol name.
5876///
5877/// @return a sorted vector of virtual member functions that have a
5878/// sub-type change.
5881{return get_priv()->sorted_changed_member_functions_;}
5882
5883/// @return the edit script of the member functions of the two
5884/// classes.
5887{return get_priv()->member_fns_changes_;}
5888
5889/// @return a map of member functions that got deleted.
5892{return get_priv()->deleted_member_functions_;}
5893
5894/// @return a map of member functions that got inserted.
5897{return get_priv()->inserted_member_functions_;}
5898
5899/// Getter of the map of data members that got replaced by another
5900/// data member. The key of the map is the offset at which the
5901/// element got replaced and the value is a pointer to the @ref
5902/// var_diff representing the replacement of the data member.
5903///
5904/// @return sorted vector of changed data member.
5907{return get_priv()->changed_dm_;}
5908
5909/// Getter of the sorted vector of data members that got replaced by
5910/// another data member.
5911///
5912/// @return sorted vector of changed data member.
5915{return get_priv()->sorted_changed_dm_;}
5916
5917/// Count the number of /filtered/ data members that got replaced by
5918/// another data member.
5919///
5920/// @return the number of changed data member that got filtered out.
5921size_t
5923{return get_priv()->count_filtered_changed_dm(local);}
5924
5925/// Getter of the sorted vector of data members with a (sub-)type change.
5926///
5927/// @return sorted vector of changed data member.
5930{return get_priv()->sorted_subtype_changed_dm_;}
5931
5932/// Count the number of /filtered/ data members with a sub-type change.
5933///
5934/// @return the number of changed data member that got filtered out.
5935size_t
5937{return get_priv()->count_filtered_subtype_changed_dm(local);}
5938
5939/// Get the map of data members that got replaced by anonymous data
5940/// members.
5941///
5942/// The key of a map entry is the name of the replaced data member and
5943/// the value is the anonymous data member that replaces it.
5944///
5945/// @return the map of data members replaced by anonymous data
5946/// members.
5949{return get_priv()->dms_replaced_by_adms_;}
5950
5951/// Get an ordered vector of of data members that got replaced by
5952/// anonymous data members.
5953///
5954/// This returns a vector of pair of two data members: the one that
5955/// was replaced, and the anonymous data member that replaced it.
5956///
5957/// @return the sorted vector data members replaced by anonymous data members.
5960{
5961 if (priv_->dms_replaced_by_adms_ordered_.empty())
5962 {
5963 for (string_decl_base_sptr_map::const_iterator it =
5964 priv_->dms_replaced_by_adms_.begin();
5965 it != priv_->dms_replaced_by_adms_.end();
5966 ++it)
5967 {
5968 const var_decl_sptr dm =
5969 first_class_or_union()->find_data_member(it->first);
5970 ABG_ASSERT(dm);
5971 changed_var_sptr changed_dm(dm, is_data_member(it->second));
5972 priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5973 }
5974 sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5975 }
5976
5977 return priv_->dms_replaced_by_adms_ordered_;
5978}
5979
5980/// @return the edit script of the member function templates of the two
5981/// @ref class_or_union.
5982const edit_script&
5984{return get_priv()->member_fn_tmpls_changes_;}
5985
5986/// @return the edit script of the member function templates of the
5987/// two @ref class_or_union.
5990{return get_priv()->member_fn_tmpls_changes_;}
5991
5992/// @return the edit script of the member class templates of the two
5993/// @ref class_or_union.
5994const edit_script&
5996{return get_priv()->member_class_tmpls_changes_;}
5997
5998/// @return the edit script of the member class templates of the two
5999/// @ref class_or_union.
6002{return get_priv()->member_class_tmpls_changes_;}
6003
6004/// Test if the current diff node carries a change.
6005bool
6008
6009/// @return the kind of local change carried by the current diff node.
6010/// The value returned is zero if the current node carries no local
6011/// change.
6012enum change_kind
6014{
6015 ir::change_kind k = ir::NO_CHANGE_KIND;
6017 return k & ir::ALL_LOCAL_CHANGES_MASK;
6018 return ir::NO_CHANGE_KIND;
6019}
6020
6021
6022/// Report the changes carried by the current @ref class_or_union_diff
6023/// node in a textual format.
6024///
6025/// @param out the output stream to write the textual report to.
6026///
6027/// @param indent the number of white space to use as indentation.
6028void
6029class_or_union_diff::report(ostream& out, const string& indent) const
6030{
6031 context()->get_reporter()->report(*this, out, indent);
6032}
6033
6034/// Populate the vector of children node of the @ref diff base type
6035/// sub-object of this instance of @ref class_or_union_diff.
6036///
6037/// The children node can then later be retrieved using
6038/// diff::children_node().
6039void
6041{
6042 // data member changes
6043 for (var_diff_sptrs_type::const_iterator i =
6044 get_priv()->sorted_subtype_changed_dm_.begin();
6045 i != get_priv()->sorted_subtype_changed_dm_.end();
6046 ++i)
6047 if (diff_sptr d = *i)
6049
6050 for (var_diff_sptrs_type::const_iterator i =
6051 get_priv()->sorted_changed_dm_.begin();
6052 i != get_priv()->sorted_changed_dm_.end();
6053 ++i)
6054 if (diff_sptr d = *i)
6056
6057 // member function changes
6058 for (function_decl_diff_sptrs_type::const_iterator i =
6059 get_priv()->sorted_changed_member_functions_.begin();
6060 i != get_priv()->sorted_changed_member_functions_.end();
6061 ++i)
6062 if (diff_sptr d = *i)
6064}
6065
6066// </class_or_union_diff stuff>
6067
6068//<class_diff stuff>
6069
6070/// Clear the lookup tables useful for reporting.
6071///
6072/// This function must be updated each time a lookup table is added or
6073/// removed from the class_diff::priv.
6074void
6075class_diff::clear_lookup_tables(void)
6076{
6077 priv_->deleted_bases_.clear();
6078 priv_->inserted_bases_.clear();
6079 priv_->changed_bases_.clear();
6080}
6081
6082/// Tests if the lookup tables are empty.
6083///
6084/// @return true if the lookup tables are empty, false otherwise.
6085bool
6086class_diff::lookup_tables_empty(void) const
6087{
6088 return (priv_->deleted_bases_.empty()
6089 && priv_->inserted_bases_.empty()
6090 && priv_->changed_bases_.empty());
6091}
6092
6093/// Find a virtual destructor in a map of member functions
6094///
6095/// @param map the map of member functions. Note that the key of the
6096/// map is the member function name. The key is the member function.
6097///
6098/// @return an iterator to the destructor found or, if no virtual destructor
6099/// was found, return map.end()
6100static string_member_function_sptr_map::const_iterator
6101find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
6102{
6103 for (string_member_function_sptr_map::const_iterator i = map.begin();
6104 i !=map.end();
6105 ++i)
6106 {
6107 if (get_member_function_is_dtor(i->second)
6108 && get_member_function_is_virtual(i->second))
6109 return i;
6110 }
6111 return map.end();
6112}
6113
6114/// If the lookup tables are not yet built, walk the differences and
6115/// fill them.
6116///
6117/// Please note that the virtual destructors are not taken into
6118/// account when comparing the classes. The set of virtual methods
6119/// used for the comparison is passed to this method.
6120///
6121/// @param f_virt_methods the set of virtual methods of the first
6122/// class of the diff that were used for the comparison.
6123///
6124/// @param s_virt_methods the set of virtual methods of the second
6125/// class of the diff that were used for the comparison.
6126void
6127class_diff::ensure_lookup_tables_populated(const vector<method_decl_sptr>& f_virt_methods,
6128 const vector<method_decl_sptr>& s_virt_methods) const
6129{
6131
6132 if (!lookup_tables_empty())
6133 return;
6134
6135 {
6136 edit_script& e = get_priv()->base_changes_;
6137
6138 for (vector<deletion>::const_iterator it = e.deletions().begin();
6139 it != e.deletions().end();
6140 ++it)
6141 {
6142 unsigned i = it->index();
6144 first_class_decl()->get_base_specifiers()[i];
6145 string name = b->get_base_class()->get_qualified_name();
6146 ABG_ASSERT(get_priv()->deleted_bases_.find(name)
6147 == get_priv()->deleted_bases_.end());
6148 get_priv()->deleted_bases_[name] = b;
6149 }
6150
6151 for (vector<insertion>::const_iterator it = e.insertions().begin();
6152 it != e.insertions().end();
6153 ++it)
6154 {
6155 for (vector<unsigned>::const_iterator iit =
6156 it->inserted_indexes().begin();
6157 iit != it->inserted_indexes().end();
6158 ++iit)
6159 {
6160 unsigned i = *iit;
6162 second_class_decl()->get_base_specifiers()[i];
6163 string name = b->get_base_class()->get_qualified_name();
6164 ABG_ASSERT(get_priv()->inserted_bases_.find(name)
6165 == get_priv()->inserted_bases_.end());
6166 string_base_sptr_map::const_iterator j =
6167 get_priv()->deleted_bases_.find(name);
6168 if (j != get_priv()->deleted_bases_.end())
6169 {
6170 if (j->second != b)
6171 get_priv()->changed_bases_[name] =
6172 compute_diff(j->second, b, context());
6173 else
6174 // The base class changed place. IOW, the base
6175 // classes got re-arranged. Let's keep track of the
6176 // base classes that moved.
6177 get_priv()->moved_bases_.push_back(b);
6178 get_priv()->deleted_bases_.erase(j);
6179 }
6180 else
6181 get_priv()->inserted_bases_[name] = b;
6182 }
6183 }
6184
6185 // ===============================================================
6186 // Detect when a data member is deleted from the class but is now
6187 // present in one of the bases at the same offset. In that case,
6188 // the data member should not be considered as removed.
6189 // ===============================================================
6191 class_or_union_diff::priv_->deleted_data_members_;
6192
6193 vector<var_decl_sptr> deleted_data_members_present_in_bases;
6194 for (auto entry : deleted_data_members)
6195 {
6196 var_decl_sptr deleted_member = is_var_decl(entry.second);
6197 ABG_ASSERT(deleted_member);
6198 for (class_decl::base_spec_sptr base : second_class_decl()->get_base_specifiers())
6199 {
6200 class_decl_sptr klass = base->get_base_class();
6201 var_decl_sptr member = klass->find_data_member(deleted_member->get_name());
6202 if (member)
6203 deleted_data_members_present_in_bases.push_back(member);
6204 }
6205 }
6206 // Walk the deleted data members that are now in one of the bases,
6207 // of the new type, at the same offset, and let's see if they have
6208 // sub-type changes. In any cases, these should not be considered
6209 // as being deleted.
6210 for (var_decl_sptr m : deleted_data_members_present_in_bases)
6211 {
6212 string name = m->get_name();
6213 auto it = deleted_data_members.find(name);
6214 ABG_ASSERT(it != deleted_data_members.end());
6215 var_decl_sptr deleted_member = is_var_decl(it->second);
6216 if (*deleted_member != *m)
6217 {
6218 var_diff_sptr dif = compute_diff(deleted_member, m, context());
6219 ABG_ASSERT(dif);
6220 class_or_union_diff::priv_->subtype_changed_dm_[name]= dif;
6221 }
6222 deleted_data_members.erase(name);
6223 }
6224 }
6225
6226 sort_string_base_sptr_map(get_priv()->deleted_bases_,
6227 get_priv()->sorted_deleted_bases_);
6228 sort_string_base_sptr_map(get_priv()->inserted_bases_,
6229 get_priv()->sorted_inserted_bases_);
6230 sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
6231 get_priv()->sorted_changed_bases_);
6232
6233 {
6234 const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
6235
6236 edit_script& e = p->member_fns_changes_;
6237
6238 for (vector<deletion>::const_iterator it = e.deletions().begin();
6239 it != e.deletions().end();
6240 ++it)
6241 {
6242 unsigned i = it->index();
6243 method_decl_sptr mem_fn = f_virt_methods[i];
6244 string name = mem_fn->get_symbol()
6245 ? mem_fn->get_symbol()->get_name()
6246 : mem_fn->get_linkage_name();
6247 if (name.empty())
6248 name = mem_fn->get_pretty_representation();
6249 ABG_ASSERT(!name.empty());
6250 if (p->deleted_member_functions_.find(name)
6251 != p->deleted_member_functions_.end())
6252 continue;
6253 p->deleted_member_functions_[name] = mem_fn;
6254 }
6255
6256 for (vector<insertion>::const_iterator it = e.insertions().begin();
6257 it != e.insertions().end();
6258 ++it)
6259 {
6260 for (vector<unsigned>::const_iterator iit =
6261 it->inserted_indexes().begin();
6262 iit != it->inserted_indexes().end();
6263 ++iit)
6264 {
6265 unsigned i = *iit;
6266
6267 method_decl_sptr mem_fn = s_virt_methods[i];
6268 string name = mem_fn->get_symbol()
6269 ? mem_fn->get_symbol()->get_name()
6270 : mem_fn->get_linkage_name();
6271 if (name.empty())
6272 name = mem_fn->get_pretty_representation();
6273 ABG_ASSERT(!name.empty());
6274 if (p->inserted_member_functions_.find(name)
6275 != p->inserted_member_functions_.end())
6276 continue;
6277 string_member_function_sptr_map::const_iterator j =
6278 p->deleted_member_functions_.find(name);
6279
6280 if (j != p->deleted_member_functions_.end())
6281 {
6282 if (*j->second != *mem_fn)
6283 p->changed_member_functions_[name] =
6284 compute_diff(static_pointer_cast<function_decl>(j->second),
6285 static_pointer_cast<function_decl>(mem_fn),
6286 context());
6287 p->deleted_member_functions_.erase(j);
6288 }
6289 else
6290 p->inserted_member_functions_[name] = mem_fn;
6291 }
6292 }
6293
6294 // Now walk the allegedly deleted member functions; check if their
6295 // underlying symbols are deleted as well; otherwise, consider
6296 // that the member function in question hasn't been deleted.
6297
6298 // Also, while walking the deleted member functions, we attend at
6299 // a particular cleanup business related to (virtual) C++
6300 // destructors:
6301 //
6302 // In the binary, there can be at least three types of
6303 // destructors, defined in the document
6304 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
6305 //
6306 // 1/ Base object destructor (aka D2 destructor):
6307 //
6308 // "A function that runs the destructors for non-static data
6309 // members of T and non-virtual direct base classes of T. "
6310 //
6311 // 2/ Complete object destructor (aka D1 destructor):
6312 //
6313 // "A function that, in addition to the actions required of a
6314 // base object destructor, runs the destructors for the
6315 // virtual base classes of T."
6316 //
6317 // 3/ Deleting destructor (aka D0 destructor):
6318 //
6319 // "A function that, in addition to the actions required of a
6320 // complete object destructor, calls the appropriate
6321 // deallocation function (i.e,. operator delete) for T."
6322 //
6323 // With binaries generated by GCC, these destructors might be ELF
6324 // clones of each others, meaning, their ELF symbols can be
6325 // aliases.
6326 //
6327 // Also, note that because the actual destructor invoked by user
6328 // code is virtual, it's invoked through the vtable. So the
6329 // presence of the underlying D0, D1, D2 in the binary might vary
6330 // without that variation being an ABI issue, provided that the
6331 // destructor invoked through the vtable is present.
6332 //
6333 // So, a particular virtual destructor implementation for a class
6334 // might disapear and be replaced by another one in a subsequent
6335 // version of the binary. If all versions of the binary have an
6336 // actual virtual destructor, things might be considered fine.
6337 vector<string> to_delete;
6338 corpus_sptr f = context()->get_first_corpus(),
6339 s = context()->get_second_corpus();
6340 if (s)
6341 for (string_member_function_sptr_map::const_iterator i =
6342 deleted_member_fns().begin();
6343 i != deleted_member_fns().end();
6344 ++i)
6345 {
6346 if (get_member_function_is_virtual(i->second))
6347 {
6348 if (get_member_function_is_dtor(i->second))
6349 {
6350 // If a particular virtual destructor is deleted,
6351 // but the new binary still have a virtual
6352 // destructor for that class we consider that things
6353 // are fine. For instance, in the
6354 // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
6355 // test, a new D4 destructor replaces the old ones.
6356 // But because the virtual destructor is still
6357 // there, this is not an ABI issue. So let's detect
6358 // this case.
6359 auto it =
6360 find_virtual_dtor_in_map(p->inserted_member_functions_);
6361 if (it != p->inserted_member_functions_.end())
6362 {
6363 // So the deleted virtual destructor is not
6364 // really deleted, because a proper virtual
6365 // destructor was added to the new version.
6366 // Let's remove the deleted/added virtual
6367 // destructor then.
6368 string name =
6369 (!i->second->get_linkage_name().empty())
6370 ? i->second->get_linkage_name()
6371 : i->second->get_pretty_representation();
6372 to_delete.push_back(name);
6373 p->inserted_member_functions_.erase(it);
6374 }
6375 }
6376 continue;
6377 }
6378 // We assume that all non-virtual member functions functions
6379 // we look at here have ELF symbols.
6380 if (!i->second->get_symbol()
6381 || s->lookup_function_symbol(*i->second->get_symbol()))
6382 to_delete.push_back(i->first);
6383 }
6384
6385
6386 for (vector<string>::const_iterator i = to_delete.begin();
6387 i != to_delete.end();
6388 ++i)
6389 p->deleted_member_functions_.erase(*i);
6390
6391 // Do something similar for added functions.
6392 to_delete.clear();
6393 if (f)
6394 for (string_member_function_sptr_map::const_iterator i =
6395 inserted_member_fns().begin();
6396 i != inserted_member_fns().end();
6397 ++i)
6398 {
6399 if (get_member_function_is_virtual(i->second))
6400 continue;
6401 // We assume that all non-virtual member functions functions
6402 // we look at here have ELF symbols.
6403 if (!i->second->get_symbol()
6404 || f->lookup_function_symbol(*i->second->get_symbol()))
6405 to_delete.push_back(i->first);
6406 }
6407
6408 for (vector<string>::const_iterator i = to_delete.begin();
6409 i != to_delete.end();
6410 ++i)
6411 p->inserted_member_functions_.erase(*i);
6412
6413 sort_string_member_function_sptr_map(p->deleted_member_functions_,
6414 p->sorted_deleted_member_functions_);
6415
6416 sort_string_member_function_sptr_map(p->inserted_member_functions_,
6417 p->sorted_inserted_member_functions_);
6418
6420 (p->changed_member_functions_,
6421 p->sorted_changed_member_functions_);
6422 }
6423}
6424
6425/// Allocate the memory for the priv_ pimpl data member of the @ref
6426/// class_diff class.
6427void
6428class_diff::allocate_priv_data()
6429{
6431 if (!priv_)
6432 priv_.reset(new priv);
6433}
6434
6435/// Test whether a given base class has changed. A base class has
6436/// changed if it's in both in deleted *and* inserted bases.
6437///
6438///@param d the declaration for the base class to consider.
6439///
6440/// @return the new base class if the given base class has changed, or
6441/// NULL if it hasn't.
6444{
6445 string qname = d->get_base_class()->get_qualified_name();
6446 string_base_diff_sptr_map::const_iterator it =
6447 changed_bases_.find(qname);
6448
6449 return (it == changed_bases_.end())
6451 : it->second->second_base();
6452
6453}
6454
6455/// Count the number of bases classes whose changes got filtered out.
6456///
6457/// @return the number of bases classes whose changes got filtered
6458/// out.
6459size_t
6461{
6462 size_t num_filtered = 0;
6463 for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
6464 i != sorted_changed_bases_.end();
6465 ++i)
6466 {
6467 diff_sptr diff = *i;
6468 if (diff && diff->is_filtered_out())
6469 ++num_filtered;
6470 }
6471 return num_filtered;
6472}
6473
6474/// Populate the vector of children node of the @ref diff base type
6475/// sub-object of this instance of @ref class_diff.
6476///
6477/// The children node can then later be retrieved using
6478/// diff::children_node().
6479void
6481{
6483
6484 // base class changes.
6485 for (base_diff_sptrs_type::const_iterator i =
6486 get_priv()->sorted_changed_bases_.begin();
6487 i != get_priv()->sorted_changed_bases_.end();
6488 ++i)
6489 if (diff_sptr d = *i)
6491}
6492
6493/// Constructor of class_diff
6494///
6495/// @param first_scope the first class of the diff.
6496///
6497/// @param second_scope the second class of the diff.
6498///
6499/// @param ctxt the diff context to use.
6501 class_decl_sptr second_scope,
6502 diff_context_sptr ctxt)
6503 : class_or_union_diff(first_scope, second_scope, ctxt)
6504 // We don't initialize the priv_ data member here. This is an
6505 // optimization to reduce memory consumption (and also execution
6506 // time) for cases where there are a lot of instances of
6507 // class_diff in the same equivalence class. In compute_diff(),
6508 // the priv_ is set to the priv_ of the canonical diff node.
6509 // See PR libabigail/17948.
6510{}
6511
6512class_diff::~class_diff()
6513{}
6514
6515/// Getter of the private data of the @ref class_diff type.
6516///
6517/// Note that due to an optimization, the private data of @ref
6518/// class_diff can be shared among several instances of class_diff, so
6519/// you should never try to access class_diff::priv directly.
6520///
6521/// When class_diff::priv is shared, this function returns the correct
6522/// shared one.
6523///
6524/// @return the (possibly) shared private data of the current instance
6525/// of class_diff.
6526const class_diff::priv_ptr&
6527class_diff::get_priv() const
6528{
6529 if (priv_)
6530 return priv_;
6531
6532 // If the current class_diff::priv member is empty, then look for
6533 // the shared one, from the canonical type.
6534 class_diff *canonical =
6535 dynamic_cast<class_diff*>(get_canonical_diff());
6536 ABG_ASSERT(canonical);
6537 ABG_ASSERT(canonical->priv_);
6538
6539 return canonical->priv_;
6540}
6541
6542/// @return the pretty representation of the current instance of @ref
6543/// class_diff.
6544const string&
6546{
6547 if (diff::priv_->pretty_representation_.empty())
6548 {
6549 std::ostringstream o;
6550 o << "class_diff["
6551 << first_subject()->get_pretty_representation()
6552 << ", "
6553 << second_subject()->get_pretty_representation()
6554 << "]";
6555 diff::priv_->pretty_representation_ = o.str();
6556 }
6557 return diff::priv_->pretty_representation_;
6558}
6559
6560/// Return true iff the current diff node carries a change.
6561///
6562/// @return true iff the current diff node carries a change.
6563bool
6566
6567/// @return the kind of local change carried by the current diff node.
6568/// The value returned is zero if the current node carries no local
6569/// change.
6570enum change_kind
6572{
6573 ir::change_kind k = ir::NO_CHANGE_KIND;
6574 if (!equals(*first_class_decl(), *second_class_decl(), &k))
6575 return k & ir::ALL_LOCAL_CHANGES_MASK;
6576 return ir::NO_CHANGE_KIND;
6577}
6578
6579/// @return the first class invoveld in the diff.
6580shared_ptr<class_decl>
6582{return dynamic_pointer_cast<class_decl>(first_subject());}
6583
6584/// Getter of the second class involved in the diff.
6585///
6586/// @return the second class invoveld in the diff
6587shared_ptr<class_decl>
6589{return dynamic_pointer_cast<class_decl>(second_subject());}
6590
6591/// @return the edit script of the bases of the two classes.
6592const edit_script&
6594{return get_priv()->base_changes_;}
6595
6596/// Getter for the deleted base classes of the diff.
6597///
6598/// @return a map containing the deleted base classes, keyed with
6599/// their pretty representation.
6602{return get_priv()->deleted_bases_;}
6603
6604/// Getter for the inserted base classes of the diff.
6605///
6606/// @return a map containing the inserted base classes, keyed with
6607/// their pretty representation.
6610{return get_priv()->inserted_bases_;}
6611
6612/// Getter for the changed base classes of the diff.
6613///
6614/// @return a sorted vector containing the changed base classes
6617{return get_priv()->sorted_changed_bases_;}
6618
6619/// Getter for the vector of bases that "moved".
6620/// That is, the vector of base types which position changed. If this
6621/// vector is not empty, it means the bases of the underlying class
6622/// type got re-ordered.
6623///
6624/// @return the vector of bases that moved.
6625const vector<class_decl::base_spec_sptr>&
6627{return get_priv()->moved_bases_;}
6628
6629/// @return the edit script of the bases of the two classes.
6632{return get_priv()->base_changes_;}
6633
6634/// Produce a basic report about the changes between two class_decl.
6635///
6636/// @param out the output stream to report the changes to.
6637///
6638/// @param indent the string to use as an indentation prefix in the
6639/// report.
6640void
6641class_diff::report(ostream& out, const string& indent) const
6642{
6643 context()->get_reporter()->report(*this, out, indent);
6644}
6645
6646/// Compute the set of changes between two instances of class_decl.
6647///
6648/// Note that the two types must have been created in the same @ref
6649/// environment, otherwise, this function aborts.
6650///
6651/// @param first the first class_decl to consider.
6652///
6653/// @param second the second class_decl to consider.
6654///
6655/// @return changes the resulting changes.
6656///
6657/// @param ctxt the diff context to use.
6660 const class_decl_sptr second,
6661 diff_context_sptr ctxt)
6662{
6665
6666 class_diff_sptr changes(new class_diff(f, s, ctxt));
6667
6668 ctxt->initialize_canonical_diff(changes);
6669 ABG_ASSERT(changes->get_canonical_diff());
6670
6671 if (!ctxt->get_canonical_diff_for(first, second))
6672 {
6673 // Either first or second is a decl-only class; let's set the
6674 // canonical diff here in that case.
6675 diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6676 ABG_ASSERT(canonical_diff);
6677 ctxt->set_canonical_diff_for(first, second, canonical_diff);
6678 }
6679
6680 // Ok, so this is an optimization. Do not freak out if it looks
6681 // weird, because, well, it does look weird. This speeds up
6682 // greatly, for instance, the test case given at PR
6683 // libabigail/17948.
6684 //
6685 // We are setting the private data of the new instance of class_diff
6686 // (which is 'changes') to the private data of its canonical
6687 // instance. That is, we are sharing the private data of 'changes'
6688 // with the private data of its canonical instance to consume less
6689 // memory in cases where the equivalence class of 'changes' is huge.
6690 //
6691 // But if changes is its own canonical instance, then we initialize
6692 // its private data properly
6693 if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6694 // changes is its own canonical instance, so it gets a brand new
6695 // private data.
6696 changes->allocate_priv_data();
6697 else
6698 {
6699 // changes has a non-empty equivalence class so it's going to
6700 // share its private data with its canonical instance. Next
6701 // time class_diff::get_priv() is invoked, it's going to return
6702 // the shared private data of the canonical instance.
6703 return changes;
6704 }
6705
6706 // Compare base specs
6707 compute_diff(f->get_base_specifiers().begin(),
6708 f->get_base_specifiers().end(),
6709 s->get_base_specifiers().begin(),
6710 s->get_base_specifiers().end(),
6711 changes->base_changes());
6712
6713 // Do *not* compare member types because it generates lots of noise
6714 // and I doubt it's really useful.
6715#if 0
6716 compute_diff(f->get_member_types().begin(),
6717 f->get_member_types().end(),
6718 s->get_member_types().begin(),
6719 s->get_member_types().end(),
6720 changes->member_types_changes());
6721#endif
6722
6723 // Compare data member
6724 compute_diff(f->get_non_static_data_members().begin(),
6725 f->get_non_static_data_members().end(),
6726 s->get_non_static_data_members().begin(),
6727 s->get_non_static_data_members().end(),
6728 changes->data_members_changes());
6729
6730 // Compare virtual member functions, but skip virtual destructors.
6731 //
6732 // We skip virtual destructors because DWARF doesn't necessarily
6733 // emit them in all TUs, for a given class.
6734 //
6735 // All the virtual destructors are collected in the canonical
6736 // classes (by maybe_adjust_canonical_type), yes, but then when
6737 // naively comparing a class coming from DWARF and its canonical
6738 // type, we might get spurious errors due to the fact that the
6739 // canonical type might have virtual dtors not found on the
6740 // particular type.
6741 //
6742 // Note that we do something similar in the equal overload for
6743 // class_decl.
6744 //
6745 // If the dtor is part of ABI, however, it's going to be taken into
6746 // account when comparing the interfaces of an ABI corpus. So we
6747 // are not loosing any information by not comparing these virtual
6748 // dtors here.
6749
6750 vector<method_decl_sptr> first_virt_mems;
6751 vector<method_decl_sptr> second_virt_mems;
6752 first_virt_mems.reserve(f->get_virtual_mem_fns().size());
6753 second_virt_mems.reserve(s->get_virtual_mem_fns().size());
6754
6755 for (auto virt_method : f->get_virtual_mem_fns())
6756 {
6757 if (get_member_function_is_dtor(virt_method))
6758 continue;
6759 first_virt_mems.push_back(virt_method);
6760 }
6761
6762 for (auto virt_method : s->get_virtual_mem_fns())
6763 {
6764 if (get_member_function_is_dtor(virt_method))
6765 continue;
6766 second_virt_mems.push_back(virt_method);
6767 }
6768
6769 compute_diff(first_virt_mems.begin(), first_virt_mems.end(),
6770 second_virt_mems.begin(), second_virt_mems.end(),
6771 changes->member_fns_changes());
6772
6773 // Compare member function templates
6774 compute_diff(f->get_member_function_templates().begin(),
6775 f->get_member_function_templates().end(),
6776 s->get_member_function_templates().begin(),
6777 s->get_member_function_templates().end(),
6778 changes->member_fn_tmpls_changes());
6779
6780 // Likewise, do not compare member class templates
6781#if 0
6782 compute_diff(f->get_member_class_templates().begin(),
6783 f->get_member_class_templates().end(),
6784 s->get_member_class_templates().begin(),
6785 s->get_member_class_templates().end(),
6786 changes->member_class_tmpls_changes());
6787#endif
6788
6789 changes->ensure_lookup_tables_populated(first_virt_mems, second_virt_mems);
6790
6791 return changes;
6792}
6793
6794//</class_diff stuff>
6795
6796// <base_diff stuff>
6797
6798/// Populate the vector of children node of the @ref diff base type
6799/// sub-object of this instance of @ref base_diff.
6800///
6801/// The children node can then later be retrieved using
6802/// diff::children_node().
6803void
6806
6807/// @param first the first base spec to consider.
6808///
6809/// @param second the second base spec to consider.
6810///
6811/// @param ctxt the context of the diff. Note that this context
6812/// object must stay alive at least during the life time of the
6813/// current instance of @ref base_diff. Otherwise memory corruption
6814/// issues occur.
6817 class_diff_sptr underlying,
6818 diff_context_sptr ctxt)
6819 : diff(first, second, ctxt),
6820 priv_(new priv(underlying))
6821{}
6822
6823/// Getter for the first base spec of the diff object.
6824///
6825/// @return the first base specifier for the diff object.
6828{return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6829
6830/// Getter for the second base spec of the diff object.
6831///
6832/// @return the second base specifier for the diff object.
6835{return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6836
6837/// Getter for the diff object for the diff of the underlying base
6838/// classes.
6839///
6840/// @return the diff object for the diff of the underlying base
6841/// classes.
6842const class_diff_sptr
6844{return priv_->underlying_class_diff_;}
6845
6846/// Setter for the diff object for the diff of the underlyng base
6847/// classes.
6848///
6849/// @param d the new diff object for the diff of the underlying base
6850/// classes.
6851void
6853{priv_->underlying_class_diff_ = d;}
6854
6855/// @return the pretty representation for the current instance of @ref
6856/// base_diff.
6857const string&
6859{
6860 if (diff::priv_->pretty_representation_.empty())
6861 {
6862 std::ostringstream o;
6863 o << "base_diff["
6864 << first_subject()->get_pretty_representation()
6865 << ", "
6866 << second_subject()->get_pretty_representation()
6867 << "]";
6868 diff::priv_->pretty_representation_ = o.str();
6869 }
6870 return diff::priv_->pretty_representation_;
6871}
6872
6873/// Return true iff the current diff node carries a change.
6874///
6875/// Return true iff the current diff node carries a change.
6876bool
6878{return first_base() != second_base();}
6879
6880/// @return the kind of local change carried by the current diff node.
6881/// The value returned is zero if the current node carries no local
6882/// change.
6883enum change_kind
6885{
6886 ir::change_kind k = ir::NO_CHANGE_KIND;
6887 if (!equals(*first_base(), *second_base(), &k))
6888 return k & ir::ALL_LOCAL_CHANGES_MASK;
6889 return ir::NO_CHANGE_KIND;
6890}
6891
6892/// Generates a report for the current instance of base_diff.
6893///
6894/// @param out the output stream to send the report to.
6895///
6896/// @param indent the string to use for indentation.
6897void
6898base_diff::report(ostream& out, const string& indent) const
6899{
6900 context()->get_reporter()->report(*this, out, indent);
6901}
6902
6903/// Constructs the diff object representing a diff between two base
6904/// class specifications.
6905///
6906/// Note that the two artifacts must have been created in the same
6907/// @ref environment, otherwise, this function aborts.
6908///
6909/// @param first the first base class specification.
6910///
6911/// @param second the second base class specification.
6912///
6913/// @param ctxt the content of the diff.
6914///
6915/// @return the resulting diff object.
6918 const class_decl::base_spec_sptr second,
6919 diff_context_sptr ctxt)
6920{
6921 class_diff_sptr cl = compute_diff(first->get_base_class(),
6922 second->get_base_class(),
6923 ctxt);
6924 base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6925
6926 ctxt->initialize_canonical_diff(changes);
6927
6928 return changes;
6929}
6930
6931// </base_diff stuff>
6932
6933
6934// <union_diff stuff>
6935
6936/// Clear the lookup tables useful for reporting.
6937///
6938/// This function must be updated each time a lookup table is added or
6939/// removed from the union_diff::priv.
6940void
6941union_diff::clear_lookup_tables(void)
6943
6944/// Tests if the lookup tables are empty.
6945///
6946/// @return true if the lookup tables are empty, false otherwise.
6947bool
6948union_diff::lookup_tables_empty(void) const
6950
6951/// If the lookup tables are not yet built, walk the differences and
6952/// fill them.
6953void
6954union_diff::ensure_lookup_tables_populated(void) const
6956
6957/// Allocate the memory for the priv_ pimpl data member of the @ref
6958/// union_diff class.
6959void
6960union_diff::allocate_priv_data()
6961{
6963}
6964
6965/// Constructor for the @ref union_diff type.
6966///
6967/// @param first_union the first object of the comparison.
6968///
6969/// @param second_union the second object of the comparison.
6970///
6971/// @param ctxt the context of the comparison.
6972union_diff::union_diff(union_decl_sptr first_union,
6973 union_decl_sptr second_union,
6974 diff_context_sptr ctxt)
6975 : class_or_union_diff(first_union, second_union, ctxt)
6976{}
6977
6978/// Destructor of the union_diff node.
6981
6982/// @return the first object of the comparison.
6983union_decl_sptr
6986
6987/// @return the second object of the comparison.
6988union_decl_sptr
6991
6992/// @return the pretty representation of the current diff node.
6993const string&
6995{
6996 if (diff::priv_->pretty_representation_.empty())
6997 {
6998 std::ostringstream o;
6999 o << "union_diff["
7000 << first_subject()->get_pretty_representation()
7001 << ", "
7002 << second_subject()->get_pretty_representation()
7003 << "]";
7004 diff::priv_->pretty_representation_ = o.str();
7005 }
7006 return diff::priv_->pretty_representation_;
7007}
7008
7009/// Report the changes carried by the current @ref union_diff node in
7010/// a textual format.
7011///
7012/// @param out the output stream to write the textual report to.
7013///
7014/// @param indent the number of white space to use as indentation.
7015void
7016union_diff::report(ostream& out, const string& indent) const
7017{
7018 context()->get_reporter()->report(*this, out, indent);
7019}
7020
7021/// Compute the difference between two @ref union_decl types.
7022///
7023/// Note that the two types must hav been created in the same
7024/// environment, otherwise, this function aborts.
7025///
7026/// @param first the first @ref union_decl to consider.
7027///
7028/// @param second the second @ref union_decl to consider.
7029///
7030/// @param ctxt the context of the diff to use.
7031union_diff_sptr
7032compute_diff(const union_decl_sptr first,
7033 const union_decl_sptr second,
7034 diff_context_sptr ctxt)
7035{
7036 union_diff_sptr changes(new union_diff(first, second, ctxt));
7037
7038 ctxt->initialize_canonical_diff(changes);
7039 ABG_ASSERT(changes->get_canonical_diff());
7040
7041 // Ok, so this is an optimization. Do not freak out if it looks
7042 // weird, because, well, it does look weird. This speeds up
7043 // greatly, for instance, the test case given at PR
7044 // libabigail/17948.
7045 //
7046 // We are setting the private data of the new instance of class_diff
7047 // (which is 'changes') to the private data of its canonical
7048 // instance. That is, we are sharing the private data of 'changes'
7049 // with the private data of its canonical instance to consume less
7050 // memory in cases where the equivalence class of 'changes' is huge.
7051 //
7052 // But if changes is its own canonical instance, then we initialize
7053 // its private data properly.
7054 if (is_union_diff(changes->get_canonical_diff()) == changes.get())
7055 // changes is its own canonical instance, so it gets a brand new
7056 // private data.
7057 changes->allocate_priv_data();
7058 else
7059 {
7060 // changes has a non-empty equivalence class so it's going to
7061 // share its private data with its canonical instance. Next
7062 // time class_diff::get_priv() is invoked, it's going to return
7063 // the shared private data of the canonical instance.
7064 return changes;
7065 }
7066
7067 // Compare data member
7068 compute_diff(first->get_non_static_data_members().begin(),
7069 first->get_non_static_data_members().end(),
7070 second->get_non_static_data_members().begin(),
7071 second->get_non_static_data_members().end(),
7072 changes->data_members_changes());
7073
7074#if 0
7075 // Compare member functions
7076 compute_diff(first->get_mem_fns().begin(),
7077 first->get_mem_fns().end(),
7078 second->get_mem_fns().begin(),
7079 second->get_mem_fns().end(),
7080 changes->member_fns_changes());
7081
7082 // Compare member function templates
7083 compute_diff(first->get_member_function_templates().begin(),
7084 first->get_member_function_templates().end(),
7085 second->get_member_function_templates().begin(),
7086 second->get_member_function_templates().end(),
7087 changes->member_fn_tmpls_changes());
7088#endif
7089
7090 changes->ensure_lookup_tables_populated();
7091
7092 return changes;
7093}
7094
7095// </union_diff stuff>
7096
7097//<scope_diff stuff>
7098
7099/// Clear the lookup tables that are useful for reporting.
7100///
7101/// This function must be updated each time a lookup table is added or
7102/// removed.
7103void
7104scope_diff::clear_lookup_tables()
7105{
7106 priv_->deleted_types_.clear();
7107 priv_->deleted_decls_.clear();
7108 priv_->inserted_types_.clear();
7109 priv_->inserted_decls_.clear();
7110 priv_->changed_types_.clear();
7111 priv_->changed_decls_.clear();
7112 priv_->removed_types_.clear();
7113 priv_->removed_decls_.clear();
7114 priv_->added_types_.clear();
7115 priv_->added_decls_.clear();
7116}
7117
7118/// Tests if the lookup tables are empty.
7119///
7120/// This function must be updated each time a lookup table is added or
7121/// removed.
7122///
7123/// @return true iff all the lookup tables are empty.
7124bool
7125scope_diff::lookup_tables_empty() const
7126{
7127 return (priv_->deleted_types_.empty()
7128 && priv_->deleted_decls_.empty()
7129 && priv_->inserted_types_.empty()
7130 && priv_->inserted_decls_.empty()
7131 && priv_->changed_types_.empty()
7132 && priv_->changed_decls_.empty()
7133 && priv_->removed_types_.empty()
7134 && priv_->removed_decls_.empty()
7135 && priv_->added_types_.empty()
7136 && priv_->added_decls_.empty());
7137}
7138
7139/// If the lookup tables are not yet built, walk the member_changes_
7140/// member and fill the lookup tables.
7141void
7142scope_diff::ensure_lookup_tables_populated()
7143{
7144 if (!lookup_tables_empty())
7145 return;
7146
7147 edit_script& e = priv_->member_changes_;
7148
7149 // Populate deleted types & decls lookup tables.
7150 for (const auto& deletion : e.deletions())
7151 {
7152 unsigned i = deletion.index();
7153 decl_base_sptr decl = deleted_member_at(i);
7154 string qname = decl->get_qualified_name();
7155 if (is_type(decl))
7156 {
7157 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
7158 if (klass_decl && klass_decl->get_is_declaration_only())
7159 continue;
7160
7161 // Unique types are artifically put in a scope because they
7162 // have to belong somewhere, but they should not be
7163 // considered added/removed from any scope because they are
7164 // artificial and always present in the system.
7165 if (is_unique_type(is_type(decl)))
7166 continue;
7167
7168 ABG_ASSERT(priv_->deleted_types_.find(qname)
7169 == priv_->deleted_types_.end());
7170 priv_->deleted_types_[qname] = decl;
7171 }
7172 else
7173 {
7174 ABG_ASSERT(priv_->deleted_decls_.find(qname)
7175 == priv_->deleted_decls_.end());
7176 priv_->deleted_decls_[qname] = decl;
7177 }
7178 }
7179
7180 // Populate inserted types & decls as well as chagned types & decls
7181 // lookup tables.
7182 for (vector<insertion>::const_iterator it = e.insertions().begin();
7183 it != e.insertions().end();
7184 ++it)
7185 {
7186 for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
7187 i != it->inserted_indexes().end();
7188 ++i)
7189 {
7190 decl_base_sptr decl = inserted_member_at(i);
7191 string qname = decl->get_qualified_name();
7192 if (is_type(decl))
7193 {
7194 class_decl_sptr klass_decl =
7195 dynamic_pointer_cast<class_decl>(decl);
7196 if (klass_decl && klass_decl->get_is_declaration_only())
7197 continue;
7198
7199 // Unique types are artifically put in a scope because they
7200 // have to belong somewhere, but they should not be
7201 // considered added/removed from any scope because they are
7202 // artificial and always present in the system.
7203 if (is_unique_type(is_type(decl)))
7204 continue;
7205
7206 ABG_ASSERT(priv_->inserted_types_.find(qname)
7207 == priv_->inserted_types_.end());
7208 string_decl_base_sptr_map::const_iterator j =
7209 priv_->deleted_types_.find(qname);
7210 if (j != priv_->deleted_types_.end())
7211 {
7212 if (*j->second != *decl)
7213 priv_->changed_types_[qname] =
7214 compute_diff(j->second, decl, context());
7215 priv_->deleted_types_.erase(j);
7216 }
7217 else
7218 priv_->inserted_types_[qname] = decl;
7219 }
7220 else
7221 {
7222 ABG_ASSERT(priv_->inserted_decls_.find(qname)
7223 == priv_->inserted_decls_.end());
7224 string_decl_base_sptr_map::const_iterator j =
7225 priv_->deleted_decls_.find(qname);
7226 if (j != priv_->deleted_decls_.end())
7227 {
7228 if (*j->second != *decl)
7229 priv_->changed_decls_[qname] =
7230 compute_diff(j->second, decl, context());
7231 priv_->deleted_decls_.erase(j);
7232 }
7233 else
7234 priv_->inserted_decls_[qname] = decl;
7235 }
7236 }
7237 }
7238
7239 sort_string_diff_sptr_map(priv_->changed_decls_,
7240 priv_->sorted_changed_decls_);
7241 sort_string_diff_sptr_map(priv_->changed_types_,
7242 priv_->sorted_changed_types_);
7243
7244 // Populate removed types/decls lookup tables
7245 for (string_decl_base_sptr_map::const_iterator i =
7246 priv_->deleted_types_.begin();
7247 i != priv_->deleted_types_.end();
7248 ++i)
7249 {
7250 string_decl_base_sptr_map::const_iterator r =
7251 priv_->inserted_types_.find(i->first);
7252 if (r == priv_->inserted_types_.end())
7253 priv_->removed_types_[i->first] = i->second;
7254 }
7255 for (string_decl_base_sptr_map::const_iterator i =
7256 priv_->deleted_decls_.begin();
7257 i != priv_->deleted_decls_.end();
7258 ++i)
7259 {
7260 string_decl_base_sptr_map::const_iterator r =
7261 priv_->inserted_decls_.find(i->first);
7262 if (r == priv_->inserted_decls_.end())
7263 priv_->removed_decls_[i->first] = i->second;
7264 }
7265
7266 // Populate added types/decls.
7267 for (string_decl_base_sptr_map::const_iterator i =
7268 priv_->inserted_types_.begin();
7269 i != priv_->inserted_types_.end();
7270 ++i)
7271 {
7272 string_decl_base_sptr_map::const_iterator r =
7273 priv_->deleted_types_.find(i->first);
7274 if (r == priv_->deleted_types_.end())
7275 priv_->added_types_[i->first] = i->second;
7276 }
7277 for (string_decl_base_sptr_map::const_iterator i =
7278 priv_->inserted_decls_.begin();
7279 i != priv_->inserted_decls_.end();
7280 ++i)
7281 {
7282 string_decl_base_sptr_map::const_iterator r =
7283 priv_->deleted_decls_.find(i->first);
7284 if (r == priv_->deleted_decls_.end())
7285 priv_->added_decls_[i->first] = i->second;
7286 }
7287}
7288
7289/// Populate the vector of children node of the @ref diff base type
7290/// sub-object of this instance of @ref scope_diff.
7291///
7292/// The children node can then later be retrieved using
7293/// diff::children_node().
7294void
7296{
7297 for (diff_sptrs_type::const_iterator i = changed_types().begin();
7298 i != changed_types().end();
7299 ++i)
7300 if (*i)
7302
7303 for (diff_sptrs_type::const_iterator i = changed_decls().begin();
7304 i != changed_decls().end();
7305 ++i)
7306 if (*i)
7308}
7309
7310/// Constructor for scope_diff
7311///
7312/// @param first_scope the first scope to consider for the diff.
7313///
7314/// @param second_scope the second scope to consider for the diff.
7315///
7316/// @param ctxt the diff context to use. Note that this context
7317/// object must stay alive at least during the life time of the
7318/// current instance of @ref scope_diff. Otherwise memory corruption
7319/// issues occur.
7321 scope_decl_sptr second_scope,
7322 diff_context_sptr ctxt)
7323 : diff(first_scope, second_scope, ctxt),
7324 priv_(new priv)
7325{}
7326
7327/// Getter for the first scope of the diff.
7328///
7329/// @return the first scope of the diff.
7330const scope_decl_sptr
7332{return dynamic_pointer_cast<scope_decl>(first_subject());}
7333
7334/// Getter for the second scope of the diff.
7335///
7336/// @return the second scope of the diff.
7337const scope_decl_sptr
7339{return dynamic_pointer_cast<scope_decl>(second_subject());}
7340
7341/// Accessor of the edit script of the members of a scope.
7342///
7343/// This edit script is computed using the equality operator that
7344/// applies to shared_ptr<decl_base>.
7345///
7346/// That has interesting consequences. For instance, consider two
7347/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7348/// S0'. C0 and C0' have the same qualified name, but have different
7349/// members. The edit script will consider that C0 has been deleted
7350/// from S0 and that S0' has been inserted. This is a low level
7351/// canonical representation of the changes; a higher level
7352/// representation would give us a simpler way to say "the class C0
7353/// has been modified into C0'". But worry not. We do have such
7354/// higher representation as well; that is what changed_types() and
7355/// changed_decls() is for.
7356///
7357/// @return the edit script of the changes encapsulatd in this
7358/// instance of scope_diff.
7359const edit_script&
7361{return priv_->member_changes_;}
7362
7363/// Accessor of the edit script of the members of a scope.
7364///
7365/// This edit script is computed using the equality operator that
7366/// applies to shared_ptr<decl_base>.
7367///
7368/// That has interesting consequences. For instance, consider two
7369/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7370/// S0'. C0 and C0' have the same qualified name, but have different
7371/// members. The edit script will consider that C0 has been deleted
7372/// from S0 and that S0' has been inserted. This is a low level
7373/// canonical representation of the changes; a higher level
7374/// representation would give us a simpler way to say "the class C0
7375/// has been modified into C0'". But worry not. We do have such
7376/// higher representation as well; that is what changed_types() and
7377/// changed_decls() is for.
7378///
7379/// @return the edit script of the changes encapsulatd in this
7380/// instance of scope_diff.
7383{return priv_->member_changes_;}
7384
7385/// Accessor that eases the manipulation of the edit script associated
7386/// to this instance. It returns the scope member that is reported
7387/// (in the edit script) as deleted at a given index.
7388///
7389/// @param i the index (in the edit script) of an element of the first
7390/// scope that has been reported as being delete.
7391///
7392/// @return the scope member that has been reported by the edit script
7393/// as being deleted at index i.
7394const decl_base_sptr
7396{
7397 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
7398 return scope->get_member_decls()[i];
7399}
7400
7401/// Accessor that eases the manipulation of the edit script associated
7402/// to this instance. It returns the scope member (of the first scope
7403/// of this diff instance) that is reported (in the edit script) as
7404/// deleted at a given iterator.
7405///
7406/// @param i the iterator of an element of the first scope that has
7407/// been reported as being delete.
7408///
7409/// @return the scope member of the first scope of this diff that has
7410/// been reported by the edit script as being deleted at iterator i.
7411const decl_base_sptr
7412scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
7413{return deleted_member_at(i->index());}
7414
7415/// Accessor that eases the manipulation of the edit script associated
7416/// to this instance. It returns the scope member (of the second
7417/// scope of this diff instance) that is reported as being inserted
7418/// from a given index.
7419///
7420/// @param i the index of an element of the second scope this diff
7421/// that has been reported by the edit script as being inserted.
7422///
7423/// @return the scope member of the second scope of this diff that has
7424/// been reported as being inserted from index i.
7425const decl_base_sptr
7427{
7428 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
7429 return scope->get_member_decls()[i];
7430}
7431
7432/// Accessor that eases the manipulation of the edit script associated
7433/// to this instance. It returns the scope member (of the second
7434/// scope of this diff instance) that is reported as being inserted
7435/// from a given iterator.
7436///
7437/// @param i the iterator of an element of the second scope this diff
7438/// that has been reported by the edit script as being inserted.
7439///
7440/// @return the scope member of the second scope of this diff that has
7441/// been reported as being inserted from iterator i.
7442const decl_base_sptr
7443scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
7444{return inserted_member_at(*i);}
7445
7446/// @return a sorted vector of the types which content has changed
7447/// from the first scope to the other.
7448const diff_sptrs_type&
7450{return priv_->sorted_changed_types_;}
7451
7452/// @return a sorted vector of the decls which content has changed
7453/// from the first scope to the other.
7454const diff_sptrs_type&
7456{return priv_->sorted_changed_decls_;}
7457
7459scope_diff::removed_types() const
7460{return priv_->removed_types_;}
7461
7463scope_diff::removed_decls() const
7464{return priv_->removed_decls_;}
7465
7467scope_diff::added_types() const
7468{return priv_->added_types_;}
7469
7471scope_diff::added_decls() const
7472{return priv_->added_decls_;}
7473
7474/// @return the pretty representation for the current instance of @ref
7475/// scope_diff.
7476const string&
7478{
7479 if (diff::priv_->pretty_representation_.empty())
7480 {
7481 std::ostringstream o;
7482 o << "scope_diff["
7483 << first_subject()->get_pretty_representation()
7484 << ", "
7485 << second_subject()->get_pretty_representation()
7486 << "]";
7487 diff::priv_->pretty_representation_ = o.str();
7488 }
7489 return diff::priv_->pretty_representation_;
7490}
7491
7492/// Return true iff the current diff node carries a change.
7493///
7494/// Return true iff the current diff node carries a change.
7495bool
7497{
7498 // TODO: add the number of really removed/added stuff.
7499 return changed_types().size() + changed_decls().size();
7500}
7501
7502/// @return the kind of local change carried by the current diff node.
7503/// The value returned is zero if the current node carries no local
7504/// change.
7505enum change_kind
7507{
7508 ir::change_kind k = ir::NO_CHANGE_KIND;
7509 if (!equals(*first_scope(), *second_scope(), &k))
7510 return k & ir::ALL_LOCAL_CHANGES_MASK;
7511 return ir::NO_CHANGE_KIND;
7512}
7513
7514/// Report the changes of one scope against another.
7515///
7516/// @param out the out stream to report the changes to.
7517///
7518/// @param indent the string to use for indentation.
7519void
7520scope_diff::report(ostream& out, const string& indent) const
7521{
7522 context()->get_reporter()->report(*this, out, indent);
7523}
7524
7525/// Compute the diff between two scopes.
7526///
7527/// Note that the two decls must have been created in the same @ref
7528/// environment, otherwise, this function aborts.
7529///
7530/// @param first the first scope to consider in computing the diff.
7531///
7532/// @param second the second scope to consider in the diff
7533/// computation. The second scope is diffed against the first scope.
7534///
7535/// @param d a pointer to the diff object to populate with the
7536/// computed diff.
7537///
7538/// @return return the populated \a d parameter passed to this
7539/// function.
7540///
7541/// @param ctxt the diff context to use.
7544 const scope_decl_sptr second,
7546 diff_context_sptr ctxt)
7547{
7548 ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
7549
7550 compute_diff(first->get_member_decls().begin(),
7551 first->get_member_decls().end(),
7552 second->get_member_decls().begin(),
7553 second->get_member_decls().end(),
7554 d->member_changes());
7555
7556 d->ensure_lookup_tables_populated();
7557 d->context(ctxt);
7558
7559 return d;
7560}
7561
7562/// Compute the diff between two scopes.
7563///
7564/// Note that the two decls must have been created in the same @ref
7565/// environment, otherwise, this function aborts.
7566///
7567/// @param first_scope the first scope to consider in computing the diff.
7568///
7569/// @param second_scope the second scope to consider in the diff
7570/// computation. The second scope is diffed against the first scope.
7571///
7572/// @param ctxt the diff context to use.
7573///
7574/// @return return the resulting diff
7577 const scope_decl_sptr second_scope,
7578 diff_context_sptr ctxt)
7579{
7580 scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
7581 d = compute_diff(first_scope, second_scope, d, ctxt);
7582 ctxt->initialize_canonical_diff(d);
7583 return d;
7584}
7585
7586//</scope_diff stuff>
7587
7588// <fn_parm_diff stuff>
7589
7590/// Constructor for the fn_parm_diff type.
7591///
7592/// @param first the first subject of the diff.
7593///
7594/// @param second the second subject of the diff.
7595///
7596/// @param ctxt the context of the diff. Note that this context
7597/// object must stay alive at least during the life time of the
7598/// current instance of @ref fn_parm_diff. Otherwise memory
7599/// corruption issues occur.
7600fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
7601 const function_decl::parameter_sptr second,
7602 diff_context_sptr ctxt)
7603 : decl_diff_base(first, second, ctxt),
7604 priv_(new priv)
7605{
7606 ABG_ASSERT(first->get_index() == second->get_index());
7607 priv_->type_diff = compute_diff(first->get_type(),
7608 second->get_type(),
7609 ctxt);
7610 ABG_ASSERT(priv_->type_diff);
7611}
7612
7613/// Getter for the first subject of this diff node.
7614///
7615/// @return the first function_decl::parameter_sptr subject of this
7616/// diff node.
7619{return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
7620
7621/// Getter for the second subject of this diff node.
7622///
7623/// @return the second function_decl::parameter_sptr subject of this
7624/// diff node.
7627{return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7628
7629/// Getter for the diff representing the changes on the type of the
7630/// function parameter involved in the current instance of @ref
7631/// fn_parm_diff.
7632///
7633/// @return a diff_sptr representing the changes on the type of the
7634/// function parameter we are interested in.
7637{return priv_->type_diff;}
7638
7639/// Build and return a textual representation of the current instance
7640/// of @ref fn_parm_diff.
7641///
7642/// @return the string representing the current instance of
7643/// fn_parm_diff.
7644const string&
7646{
7647 if (diff::priv_->pretty_representation_.empty())
7648 {
7649 std::ostringstream o;
7650 o << "function_parameter_diff["
7651 << first_subject()->get_pretty_representation()
7652 << ", "
7653 << second_subject()->get_pretty_representation()
7654 << "]";
7655 diff::priv_->pretty_representation_ = o.str();
7656 }
7657 return diff::priv_->pretty_representation_;
7658}
7659
7660/// Return true iff the current diff node carries a change.
7661///
7662/// @return true iff the current diff node carries a change.
7663bool
7666
7667/// Check if the current diff node carries a local change.
7668///
7669/// @return the kind of local change carried by the current diff node.
7670/// The value returned is zero if the current node carries no local
7671/// change.
7672enum change_kind
7674{
7675 ir::change_kind k = ir::NO_CHANGE_KIND;
7676 if (!equals(*first_parameter(), *second_parameter(), &k))
7677 return k & ir::ALL_LOCAL_CHANGES_MASK;
7678 return ir::NO_CHANGE_KIND;
7679}
7680
7681/// Emit a textual report about the current fn_parm_diff instance.
7682///
7683/// @param out the output stream to emit the textual report to.
7684///
7685/// @param indent the indentation string to use in the report.
7686void
7687fn_parm_diff::report(ostream& out, const string& indent) const
7688{
7689 context()->get_reporter()->report(*this, out, indent);
7690}
7691
7692/// Populate the vector of children nodes of the @ref diff base type
7693/// sub-object of this instance of @ref fn_parm_diff.
7694///
7695/// The children nodes can then later be retrieved using
7696/// diff::children_nodes()
7697void
7703
7704/// Compute the difference between two function_decl::parameter_sptr;
7705/// that is, between two function parameters. Return a resulting
7706/// fn_parm_diff_sptr that represents the changes.
7707///
7708/// Note that the two decls must have been created in the same @ref
7709/// environment, otherwise, this function aborts.
7710///
7711/// @param first the first subject of the diff.
7712///
7713/// @param second the second subject of the diff.
7714///
7715/// @param ctxt the context of the diff.
7716///
7717/// @return fn_parm_diff_sptr the resulting diff node.
7720 const function_decl::parameter_sptr second,
7721 diff_context_sptr ctxt)
7722{
7723 if (!first || !second)
7724 return fn_parm_diff_sptr();
7725
7726 fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7727 ctxt->initialize_canonical_diff(result);
7728
7729 return result;
7730}
7731// </fn_parm_diff stuff>
7732
7733// <function_type_diff stuff>
7734
7735void
7736function_type_diff::ensure_lookup_tables_populated()
7737{
7738 priv_->return_type_diff_ =
7739 compute_diff(first_function_type()->get_return_type(),
7740 second_function_type()->get_return_type(),
7741 context());
7742
7743 string parm_name;
7745 for (vector<deletion>::const_iterator i =
7746 priv_->parm_changes_.deletions().begin();
7747 i != priv_->parm_changes_.deletions().end();
7748 ++i)
7749 {
7750 parm = *(first_function_type()->get_first_parm()
7751 + i->index());
7752 parm_name = parm->get_name_id();
7753 // If for a reason the type name is empty we want to know and
7754 // fix that.
7755 ABG_ASSERT(!parm_name.empty());
7756 priv_->deleted_parms_[parm_name] = parm;
7757 priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7758 }
7759
7760 for (vector<insertion>::const_iterator i =
7761 priv_->parm_changes_.insertions().begin();
7762 i != priv_->parm_changes_.insertions().end();
7763 ++i)
7764 {
7765 for (vector<unsigned>::const_iterator j =
7766 i->inserted_indexes().begin();
7767 j != i->inserted_indexes().end();
7768 ++j)
7769 {
7770 parm = *(second_function_type()->get_first_parm() + *j);
7771 parm_name = parm->get_name_id();
7772 // If for a reason the type name is empty we want to know and
7773 // fix that.
7774 ABG_ASSERT(!parm_name.empty());
7775 {
7776 string_parm_map::const_iterator k =
7777 priv_->deleted_parms_.find(parm_name);
7778 if (k != priv_->deleted_parms_.end())
7779 {
7780 if (*k->second != *parm)
7781 priv_->subtype_changed_parms_[parm_name] =
7782 compute_diff(k->second, parm, context());
7783 priv_->deleted_parms_.erase(parm_name);
7784 }
7785 else
7786 priv_->added_parms_[parm_name] = parm;
7787 }
7788 {
7789 unsigned_parm_map::const_iterator k =
7790 priv_->deleted_parms_by_id_.find(parm->get_index());
7791 if (k != priv_->deleted_parms_by_id_.end())
7792 {
7793 if (*k->second != *parm
7794 && (k->second->get_name_id() != parm_name))
7795 priv_->changed_parms_by_id_[parm->get_index()] =
7796 compute_diff(k->second, parm, context());
7797 priv_->added_parms_.erase(parm_name);
7798 priv_->deleted_parms_.erase(k->second->get_name_id());
7799 priv_->deleted_parms_by_id_.erase(parm->get_index());
7800 }
7801 else
7802 priv_->added_parms_by_id_[parm->get_index()] = parm;
7803 }
7804 }
7805 }
7806
7807 sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7808 priv_->sorted_subtype_changed_parms_);
7809 sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7810 priv_->sorted_changed_parms_by_id_);
7811 sort_string_parm_map(priv_->deleted_parms_,
7812 priv_->sorted_deleted_parms_);
7813
7814 sort_string_parm_map(priv_->added_parms_,
7815 priv_->sorted_added_parms_);
7816}
7817
7818/// In the vector of deleted parameters, get the one that is at a given
7819/// index.
7820///
7821/// @param i the index of the deleted parameter to get.
7822///
7823/// @return the parameter returned.
7825function_type_diff::deleted_parameter_at(int i) const
7826{return first_function_type()->get_parameters()[i];}
7827
7828/// Getter for the sorted vector of deleted parameters.
7829///
7830/// @return the sorted vector of deleted parameters.
7831const vector<function_decl::parameter_sptr>&
7833{return priv_->sorted_deleted_parms_;}
7834
7835/// Getter for the sorted vector of added parameters .
7836///
7837/// @return the sorted vector of added parameters.
7838const vector<function_decl::parameter_sptr>&
7840{return priv_->sorted_added_parms_;}
7841
7842/// In the vector of inserted parameters, get the one that is at a
7843/// given index.
7844///
7845/// @param i the index of the inserted parameter to get.
7846///
7847/// @return the parameter returned.
7849function_type_diff::inserted_parameter_at(int i) const
7850{return second_function_type()->get_parameters()[i];}
7851
7852/// Consutrctor of the @ref function_type type.
7853///
7854/// @param first the first @ref function_type subject of the diff to
7855/// create.
7856///
7857/// @param second the second @ref function_type subject of the diff to
7858/// create.
7859///
7860/// @param ctxt the diff context to be used by the newly created
7861/// instance of function_type_diff. Note that this context object
7862/// must stay alive at least during the life time of the current
7863/// instance of @ref function_type_diff. Otherwise memory corruption
7864/// issues occur.
7866 const function_type_sptr second,
7867 diff_context_sptr ctxt)
7868 : type_diff_base(first, second, ctxt),
7869 priv_(new priv)
7870{}
7871
7872/// Getter for the first subject of the diff.
7873///
7874/// @return the first function type involved in the diff.
7877{return dynamic_pointer_cast<function_type>(first_subject());}
7878
7879/// Getter for the second subject of the diff.
7880///
7881/// @return the second function type involved in the diff.
7884{return dynamic_pointer_cast<function_type>(second_subject());}
7885
7886/// Getter for the diff of the return types of the two function types
7887/// of the current diff.
7888///
7889/// @return the diff of the return types of the two function types of
7890/// the current diff.
7891const diff_sptr
7893{return priv_->return_type_diff_;}
7894
7895/// Getter for the map of function parameter changes of the current diff.
7896///
7897/// @return a map of function parameter changes of the current diff.
7900{return priv_->subtype_changed_parms_;}
7901
7902/// Getter for the map of parameters that got removed.
7903///
7904/// @return the map of parameters that got removed.
7905const string_parm_map&
7907{return priv_->deleted_parms_;}
7908
7909/// Getter for the map of parameters that got added.
7910///
7911/// @return the map of parameters that got added.
7912const string_parm_map&
7914{return priv_->added_parms_;}
7915
7916/// Build and return a copy of a pretty representation of the current
7917/// instance of @ref function_type_diff.
7918///
7919/// @return a copy of the pretty representation of the current
7920/// instance of @ref function_type_diff.
7921const string&
7923{
7924 if (diff::priv_->pretty_representation_.empty())
7925 {
7926 std::ostringstream o;
7927 o << "function_type_diff["
7929 << ", "
7931 << "]";
7932 diff::priv_->pretty_representation_ = o.str();
7933 }
7934 return diff::priv_->pretty_representation_;
7935}
7936
7937/// Test if the current diff node carries changes.
7938///
7939/// @return true iff the current diff node carries changes.
7940bool
7943
7944/// Test if the current diff node carries local changes.
7945///
7946/// A local change is a change that is carried by this diff node, not
7947/// by any of its children nodes.
7948///
7949/// @return the kind of local change carried by the current diff node.
7950/// The value returned is zero if the current node carries no local
7951/// change.
7952enum change_kind
7954{
7955 ir::change_kind k = ir::NO_CHANGE_KIND;
7957 return k & ir::ALL_LOCAL_CHANGES_MASK;
7958 return ir::NO_CHANGE_KIND;
7959}
7960
7961/// Build and emit a textual report about the current @ref
7962/// function_type_diff instance.
7963///
7964/// @param out the output stream.
7965///
7966/// @param indent the indentation string to use.
7967void
7968function_type_diff::report(ostream& out, const string& indent) const
7969{
7970 context()->get_reporter()->report(*this, out, indent);
7971}
7972
7973/// Populate the vector of children node of the @ref diff base type
7974/// sub-object of this instance of @ref function_type_diff.
7975///
7976/// The children node can then later be retrieved using
7977/// diff::children_node().
7978void
7980{
7981 if (diff_sptr d = return_type_diff())
7983
7984 for (vector<fn_parm_diff_sptr>::const_iterator i =
7985 priv_->sorted_subtype_changed_parms_.begin();
7986 i != priv_->sorted_subtype_changed_parms_.end();
7987 ++i)
7988 if (diff_sptr d = *i)
7990
7991 for (vector<fn_parm_diff_sptr>::const_iterator i =
7992 priv_->sorted_changed_parms_by_id_.begin();
7993 i != priv_->sorted_changed_parms_by_id_.end();
7994 ++i)
7995 if (diff_sptr d = *i)
7997}
7998
7999/// Compute the diff between two instances of @ref function_type.
8000///
8001/// Note that the two types must have been created in the same @ref
8002/// environment, otherwise, this function aborts.
8003///
8004/// @param first the first @ref function_type to consider for the diff.
8005///
8006/// @param second the second @ref function_type to consider for the diff.
8007///
8008/// @param ctxt the diff context to use.
8009///
8010/// @return the resulting diff between the two @ref function_type.
8013 const function_type_sptr second,
8014 diff_context_sptr ctxt)
8015{
8016 if (!first || !second)
8017 {
8018 // TODO: implement this for either first or second being NULL.
8019 return function_type_diff_sptr();
8020 }
8021
8022 function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
8023
8024 diff_utils::compute_diff(first->get_first_parm(),
8025 first->get_parameters().end(),
8026 second->get_first_parm(),
8027 second->get_parameters().end(),
8028 result->priv_->parm_changes_);
8029
8030 result->ensure_lookup_tables_populated();
8031
8032 ctxt->initialize_canonical_diff(result);
8033
8034 return result;
8035}
8036// </function_type_diff stuff>
8037
8038// <function_decl_diff stuff>
8039
8040/// Build the lookup tables of the diff, if necessary.
8041void
8042function_decl_diff::ensure_lookup_tables_populated()
8043{
8044}
8045
8046/// Populate the vector of children node of the @ref diff base type
8047/// sub-object of this instance of @ref function_decl_diff.
8048///
8049/// The children node can then later be retrieved using
8050/// diff::children_node().
8051void
8053{
8054 if (diff_sptr d = type_diff())
8056}
8057
8058/// Constructor for function_decl_diff
8059///
8060/// @param first the first function considered by the diff.
8061///
8062/// @param second the second function considered by the diff.
8063///
8064/// @param ctxt the context of the diff. Note that this context
8065/// object must stay alive at least during the life time of the
8066/// current instance of @ref function_decl_diff. Otherwise memory
8067/// corruption issues occur.
8069 const function_decl_sptr second,
8070 diff_context_sptr ctxt)
8071 : decl_diff_base(first, second, ctxt),
8072 priv_(new priv)
8073{
8074}
8075
8076/// @return the first function considered by the diff.
8079{return dynamic_pointer_cast<function_decl>(first_subject());}
8080
8081/// @return the second function considered by the diff.
8084{return dynamic_pointer_cast<function_decl>(second_subject());}
8085
8087function_decl_diff::type_diff() const
8088{return priv_->type_diff_;}
8089
8090/// @return the pretty representation for the current instance of @ref
8091/// function_decl_diff.
8092const string&
8094{
8095 if (diff::priv_->pretty_representation_.empty())
8096 {
8097 std::ostringstream o;
8098 o << "function_diff["
8099 << first_subject()->get_pretty_representation()
8100 << ", "
8101 << second_subject()->get_pretty_representation()
8102 << "]";
8103 diff::priv_->pretty_representation_ = o.str();
8104 }
8105 return diff::priv_->pretty_representation_;
8106}
8107
8108/// Return true iff the current diff node carries a change.
8109///
8110/// @return true iff the current diff node carries a change.
8111bool
8114
8115/// @return the kind of local change carried by the current diff node.
8116/// The value returned is zero if the current node carries no local
8117/// change.
8118enum change_kind
8120{
8121 ir::change_kind k = ir::NO_CHANGE_KIND;
8123 return k & ir::ALL_LOCAL_CHANGES_MASK;
8124 return ir::NO_CHANGE_KIND;
8125}
8126
8127/// Serialize a report of the changes encapsulated in the current
8128/// instance of @ref function_decl_diff over to an output stream.
8129///
8130/// @param out the output stream to serialize the report to.
8131///
8132/// @param indent the string to use an an indentation prefix.
8133void
8134function_decl_diff::report(ostream& out, const string& indent) const
8135{
8136 context()->get_reporter()->report(*this, out, indent);
8137}
8138
8139/// Compute the diff between two function_decl.
8140///
8141/// Note that the two decls must have been created in the same @ref
8142/// environment, otherwise, this function aborts.
8143///
8144/// @param first the first function_decl to consider for the diff
8145///
8146/// @param second the second function_decl to consider for the diff
8147///
8148/// @param ctxt the diff context to use.
8149///
8150/// @return the computed diff
8153 const function_decl_sptr second,
8154 diff_context_sptr ctxt)
8155{
8156 if (!first || !second)
8157 {
8158 // TODO: implement this for either first or second being NULL.
8159 return function_decl_diff_sptr();
8160 }
8161
8162 function_type_diff_sptr type_diff = compute_diff(first->get_type(),
8163 second->get_type(),
8164 ctxt);
8165
8166 function_decl_diff_sptr result(new function_decl_diff(first, second,
8167 ctxt));
8168 result->priv_->type_diff_ = type_diff;
8169
8170 result->ensure_lookup_tables_populated();
8171
8172 ctxt->initialize_canonical_diff(result);
8173
8174 return result;
8175}
8176
8177// </function_decl_diff stuff>
8178
8179// <type_decl_diff stuff>
8180
8181/// Constructor for type_decl_diff.
8182///
8183/// @param first the first subject of the diff.
8184///
8185/// @param second the second subject of the diff.
8186///
8187/// @param ctxt the context of the diff. Note that this context
8188/// object must stay alive at least during the life time of the
8189/// current instance of @ref type_decl_diff. Otherwise memory
8190/// corruption issues occur.
8191type_decl_diff::type_decl_diff(const type_decl_sptr first,
8192 const type_decl_sptr second,
8193 diff_context_sptr ctxt)
8194 : type_diff_base(first, second, ctxt)
8195{}
8196
8197/// Getter for the first subject of the type_decl_diff.
8198///
8199/// @return the first type_decl involved in the diff.
8200const type_decl_sptr
8202{return dynamic_pointer_cast<type_decl>(first_subject());}
8203
8204/// Getter for the second subject of the type_decl_diff.
8205///
8206/// @return the second type_decl involved in the diff.
8207const type_decl_sptr
8209{return dynamic_pointer_cast<type_decl>(second_subject());}
8210
8211/// @return the pretty representation for the current instance of @ref
8212/// type_decl_diff.
8213const string&
8215{
8216 if (diff::priv_->pretty_representation_.empty())
8217 {
8218 std::ostringstream o;
8219 o << "type_decl_diff["
8220 << first_subject()->get_pretty_representation()
8221 << ", "
8222 << second_subject()->get_pretty_representation()
8223 << "]";
8224 diff::priv_->pretty_representation_ = o.str();
8225 }
8226 return diff::priv_->pretty_representation_;
8227}
8228/// Return true iff the current diff node carries a change.
8229///
8230/// @return true iff the current diff node carries a change.
8231bool
8234
8235/// @return the kind of local change carried by the current diff node.
8236/// The value returned is zero if the current node carries no local
8237/// change.
8238enum change_kind
8240{
8241 ir::change_kind k = ir::NO_CHANGE_KIND;
8242 if (!equals(*first_type_decl(), *second_type_decl(), &k))
8243 return k & ir::ALL_LOCAL_CHANGES_MASK;
8244 return ir::NO_CHANGE_KIND;
8245}
8246/// Ouputs a report of the differences between of the two type_decl
8247/// involved in the type_decl_diff.
8248///
8249/// @param out the output stream to emit the report to.
8250///
8251/// @param indent the string to use for indentatino indent.
8252void
8253type_decl_diff::report(ostream& out, const string& indent) const
8254{
8255 context()->get_reporter()->report(*this, out, indent);
8256}
8257
8258/// Compute a diff between two type_decl.
8259///
8260/// Note that the two types must have been created in the same @ref
8261/// environment, otherwise, this function aborts.
8262///
8263/// This function doesn't actually compute a diff. As a type_decl is
8264/// very simple (unlike compound constructs like function_decl or
8265/// class_decl) it's easy to just compare the components of the
8266/// type_decl to know what has changed. Thus this function just
8267/// builds and return a type_decl_diff object. The
8268/// type_decl_diff::report function will just compare the components
8269/// of the the two type_decl and display where and how they differ.
8270///
8271/// @param first a pointer to the first type_decl to
8272/// consider.
8273///
8274/// @param second a pointer to the second type_decl to consider.
8275///
8276/// @param ctxt the diff context to use.
8277///
8278/// @return a pointer to the resulting type_decl_diff.
8281 const type_decl_sptr second,
8282 diff_context_sptr ctxt)
8283{
8284 type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
8285
8286 // We don't need to actually compute a diff here as a type_decl
8287 // doesn't have complicated sub-components. type_decl_diff::report
8288 // just walks the members of the type_decls and display information
8289 // about the ones that have changed. On a similar note,
8290 // type_decl_diff::length returns 0 if the two type_decls are equal,
8291 // and 1 otherwise.
8292
8293 ctxt->initialize_canonical_diff(result);
8294
8295 return result;
8296}
8297
8298// </type_decl_diff stuff>
8299
8300// <typedef_diff stuff>
8301
8302/// Populate the vector of children node of the @ref diff base type
8303/// sub-object of this instance of @ref typedef_diff.
8304///
8305/// The children node can then later be retrieved using
8306/// diff::children_node().
8307void
8310
8311/// Constructor for typedef_diff.
8312///
8313/// @param first the first subject of the diff.
8314///
8315/// @param second the second subject of the diff.
8316///
8317/// @param underlying the underlying diff of the @ref typedef_diff.
8318/// That is the diff between the underlying types of @p first and @p
8319/// second.
8320///
8321/// @param ctxt the context of the diff. Note that this context
8322/// object must stay alive at least during the life time of the
8323/// current instance of @ref typedef_diff. Otherwise memory
8324/// corruption issues occur.
8325typedef_diff::typedef_diff(const typedef_decl_sptr first,
8326 const typedef_decl_sptr second,
8327 const diff_sptr underlying,
8328 diff_context_sptr ctxt)
8329 : type_diff_base(first, second, ctxt),
8330 priv_(new priv(underlying))
8331{}
8332
8333/// Getter for the firt typedef_decl involved in the diff.
8334///
8335/// @return the first subject of the diff.
8338{return dynamic_pointer_cast<typedef_decl>(first_subject());}
8339
8340/// Getter for the second typedef_decl involved in the diff.
8341///
8342/// @return the second subject of the diff.
8345{return dynamic_pointer_cast<typedef_decl>(second_subject());}
8346
8347/// Getter for the diff between the two underlying types of the
8348/// typedefs.
8349///
8350/// @return the diff object reprensenting the difference between the
8351/// two underlying types of the typedefs.
8352const diff_sptr
8354{return priv_->underlying_type_diff_;}
8355
8356/// Setter for the diff between the two underlying types of the
8357/// typedefs.
8358///
8359/// @param d the new diff object reprensenting the difference between
8360/// the two underlying types of the typedefs.
8361void
8363{priv_->underlying_type_diff_ = d;}
8364
8365/// @return the pretty representation for the current instance of @ref
8366/// typedef_diff.
8367const string&
8369{
8370 if (diff::priv_->pretty_representation_.empty())
8371 {
8372 std::ostringstream o;
8373 o << "typedef_diff["
8374 << first_subject()->get_pretty_representation()
8375 << ", "
8376 << second_subject()->get_pretty_representation()
8377 << "]";
8378 diff::priv_->pretty_representation_ = o.str();
8379 }
8380 return diff::priv_->pretty_representation_;
8381}
8382
8383/// Return true iff the current diff node carries a change.
8384///
8385/// @return true iff the current diff node carries a change.
8386bool
8388{
8389 decl_base_sptr second = second_typedef_decl();
8390 return !(*first_typedef_decl() == *second);
8391}
8392
8393/// @return the kind of local change carried by the current diff node.
8394/// The value returned is zero if the current node carries no local
8395/// change.
8396enum change_kind
8398{
8399 ir::change_kind k = ir::NO_CHANGE_KIND;
8401 return k & ir::ALL_LOCAL_CHANGES_MASK;
8402 return ir::NO_CHANGE_KIND;
8403}
8404
8405/// Reports the difference between the two subjects of the diff in a
8406/// serialized form.
8407///
8408/// @param out the output stream to emit the report to.
8409///
8410/// @param indent the indentation string to use.
8411void
8412typedef_diff::report(ostream& out, const string& indent) const
8413{
8414 context()->get_reporter()->report(*this, out, indent);
8415}
8416
8417/// Compute a diff between two typedef_decl.
8418///
8419/// Note that the two types must have been created in the same @ref
8420/// environment, otherwise, this function aborts.
8421///
8422/// @param first a pointer to the first typedef_decl to consider.
8423///
8424/// @param second a pointer to the second typedef_decl to consider.
8425///
8426/// @param ctxt the diff context to use.
8427///
8428/// @return a pointer to the the resulting typedef_diff.
8431 const typedef_decl_sptr second,
8432 diff_context_sptr ctxt)
8433{
8434 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
8435 second->get_underlying_type(),
8436 ctxt);
8437 typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
8438
8439 ctxt->initialize_canonical_diff(result);
8440
8441 return result;
8442}
8443
8444/// Return the leaf underlying diff node of a @ref typedef_diff node.
8445///
8446/// If the underlying diff node of a @ref typedef_diff node is itself
8447/// a @ref typedef_diff node, then recursively look at the underlying
8448/// diff nodes to get the first one that is not a a @ref typedef_diff
8449/// node. This is what a leaf underlying diff node means.
8450///
8451/// Otherwise, if the underlying diff node of @ref typedef_diff is
8452/// *NOT* a @ref typedef_diff node, then just return the underlying
8453/// diff node.
8454///
8455/// And if the diff node considered is not a @ref typedef_diff node,
8456/// then just return it.
8457///
8458/// @return the leaf underlying diff node of a @p diff.
8459const diff*
8461{
8462 const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
8463 if (!d)
8464 return diff;
8465
8466 if (const typedef_diff* deef =
8467 dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
8469
8470 return d->underlying_type_diff().get();
8471}
8472
8473// </typedef_diff stuff>
8474
8475// <translation_unit_diff stuff>
8476
8477/// Constructor for translation_unit_diff.
8478///
8479/// @param first the first translation unit to consider for this diff.
8480///
8481/// @param second the second translation unit to consider for this diff.
8482///
8483/// @param ctxt the context of the diff. Note that this context
8484/// object must stay alive at least during the life time of the
8485/// current instance of @ref translation_unit_diff. Otherwise memory
8486/// corruption issues occur.
8488 translation_unit_sptr second,
8489 diff_context_sptr ctxt)
8490 : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
8491 priv_(new priv(first, second))
8492{
8493}
8494
8495/// Getter for the first translation unit of this diff.
8496///
8497/// @return the first translation unit of this diff.
8500{return priv_->first_;}
8501
8502/// Getter for the second translation unit of this diff.
8503///
8504/// @return the second translation unit of this diff.
8507{return priv_->second_;}
8508
8509/// Return true iff the current diff node carries a change.
8510///
8511/// @return true iff the current diff node carries a change.
8512bool
8515
8516/// @return the kind of local change carried by the current diff node.
8517/// The value returned is zero if the current node carries no local
8518/// change.
8519enum change_kind
8521{return ir::NO_CHANGE_KIND;}
8522
8523/// Report the diff in a serialized form.
8524///
8525/// @param out the output stream to serialize the report to.
8526///
8527/// @param indent the prefix to use as indentation for the report.
8528void
8529translation_unit_diff::report(ostream& out, const string& indent) const
8530{scope_diff::report(out, indent);}
8531
8532/// Compute the diff between two translation_units.
8533///
8534/// Note that the two translation units must have been created in the
8535/// same @ref environment, otherwise, this function aborts.
8536///
8537/// @param first the first translation_unit to consider.
8538///
8539/// @param second the second translation_unit to consider.
8540///
8541/// @param ctxt the diff context to use. If null, this function will
8542/// create a new context and set to the diff object returned.
8543///
8544/// @return the newly created diff object.
8547 const translation_unit_sptr second,
8548 diff_context_sptr ctxt)
8549{
8550 ABG_ASSERT(first && second);
8551
8552 if (!ctxt)
8553 ctxt.reset(new diff_context);
8554
8555 // TODO: handle first or second having empty contents.
8556 translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
8557 ctxt));
8558 scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
8559
8560 compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
8561 static_pointer_cast<scope_decl>(second->get_global_scope()),
8562 sc_diff,
8563 ctxt);
8564
8565 ctxt->initialize_canonical_diff(tu_diff);
8566
8567 return tu_diff;
8568}
8569
8570// </translation_unit_diff stuff>
8571
8572// <diff_maps stuff>
8573
8574/// The private data of the @ref diff_maps type.
8575struct diff_maps::priv
8576{
8577 string_diff_ptr_map type_decl_diff_map_;
8578 string_diff_ptr_map enum_diff_map_;
8579 string_diff_ptr_map class_diff_map_;
8580 string_diff_ptr_map union_diff_map_;
8581 string_diff_ptr_map typedef_diff_map_;
8582 string_diff_ptr_map subrange_diff_map_;
8583 string_diff_ptr_map array_diff_map_;
8584 string_diff_ptr_map reference_diff_map_;
8585 string_diff_ptr_map function_type_diff_map_;
8586 string_diff_ptr_map function_decl_diff_map_;
8587 string_diff_ptr_map var_decl_diff_map_;
8588 string_diff_ptr_map distinct_diff_map_;
8589 string_diff_ptr_map fn_parm_diff_map_;
8590 diff_artifact_set_map_type impacted_artifacts_map_;
8591}; // end struct diff_maps::priv
8592
8593/// Default constructor of the @ref diff_maps type.
8595 : priv_(new diff_maps::priv())
8596{}
8597
8598diff_maps::~diff_maps() = default;
8599
8600/// Getter of the map that contains basic type diffs.
8601///
8602/// @return the map that contains basic type diffs.
8605{return priv_->type_decl_diff_map_;}
8606
8607/// Getter of the map that contains basic type diffs.
8608///
8609/// @return the map that contains basic type diffs.
8612{return priv_->type_decl_diff_map_;}
8613
8614/// Getter of the map that contains enum type diffs.
8615///
8616/// @return the map that contains enum type diffs.
8619{return priv_->enum_diff_map_;}
8620
8621/// Getter of the map that contains enum type diffs.
8622///
8623/// @return the map that contains enum type diffs.
8626{return priv_->enum_diff_map_;}
8627
8628/// Getter of the map that contains class type diffs.
8629///
8630/// @return the map that contains class type diffs.
8633{return priv_->class_diff_map_;}
8634
8635/// Getter of the map that contains class type diffs.
8636///
8637/// @return the map that contains class type diffs.
8640{return priv_->class_diff_map_;}
8641
8642/// Getter of the map that contains union type diffs.
8643///
8644/// @return the map that contains union type diffs.
8647{return priv_->union_diff_map_;}
8648
8649/// Getter of the map that contains union type diffs.
8650///
8651/// @return the map that contains union type diffs.
8654{return priv_->union_diff_map_;}
8655
8656/// Getter of the map that contains typedef type diffs.
8657///
8658/// @return the map that contains typedef type diffs.
8661{return priv_->typedef_diff_map_;}
8662
8663/// Getter of the map that contains typedef type diffs.
8664///
8665/// @return the map that contains typedef type diffs.
8668{return priv_->typedef_diff_map_;}
8669
8670/// Getter of the map that contains subrange type diffs.
8671///
8672/// @return the map that contains subrange type diffs.
8675{return priv_->subrange_diff_map_;}
8676
8677/// Getter of the map that contains subrange type diffs.
8678///
8679/// @return the map that contains subrange type diffs.
8682{return priv_->subrange_diff_map_;}
8683
8684/// Getter of the map that contains array type diffs.
8685///
8686/// @return the map that contains array type diffs.
8689{return priv_->array_diff_map_;}
8690
8691/// Getter of the map that contains array type diffs.
8692///
8693/// @return the map that contains array type diffs.
8696{return priv_->array_diff_map_;}
8697
8698/// Getter of the map that contains reference type diffs.
8699///
8700/// @return the map that contains reference type diffs.
8703{return priv_->reference_diff_map_;}
8704
8705/// Getter of the map that contains reference type diffs.
8706///
8707/// @return the map that contains reference type diffs.
8710{{return priv_->reference_diff_map_;}}
8711
8712/// Getter of the map that contains function parameter diffs.
8713///
8714/// @return the map that contains function parameter diffs.
8717{return priv_->fn_parm_diff_map_;}
8718
8719/// Getter of the map that contains function parameter diffs.
8720///
8721/// @return the map that contains function parameter diffs.
8724{return priv_->fn_parm_diff_map_;}
8725
8726/// Getter of the map that contains function type diffs.
8727///
8728/// @return the map that contains function type diffs.
8731{return priv_->function_type_diff_map_;}
8732
8733/// Getter of the map that contains function type diffs.
8734///
8735/// @return the map that contains function type diffs.
8738{return priv_->function_type_diff_map_;}
8739
8740/// Getter of the map that contains function decl diffs.
8741///
8742/// @return the map that contains function decl diffs.
8745{return priv_->function_decl_diff_map_;}
8746
8747/// Getter of the map that contains function decl diffs.
8748///
8749/// @return the map that contains function decl diffs.
8752{return priv_->function_decl_diff_map_;}
8753
8754/// Getter of the map that contains var decl diffs.
8755///
8756/// @return the map that contains var decl diffs.
8759{return priv_->var_decl_diff_map_;}
8760
8761/// Getter of the map that contains var decl diffs.
8762///
8763/// @return the map that contains var decl diffs.
8766{return priv_->var_decl_diff_map_;}
8767
8768/// Getter of the map that contains distinct diffs.
8769///
8770/// @return the map that contains distinct diffs.
8773{return priv_->distinct_diff_map_;}
8774
8775/// Getter of the map that contains distinct diffs.
8776///
8777/// @return the map that contains distinct diffs.
8780{return priv_->distinct_diff_map_;}
8781
8782/// Insert a new diff node into the current instance of @ref diff_maps.
8783///
8784/// @param dif the new diff node to insert into the @ref diff_maps.
8785///
8786/// @param impacted_iface the interface (global function or variable)
8787/// currently being analysed that led to analysing the diff node @p
8788/// dif. In other words, this is the interface impacted by the diff
8789/// node @p dif. Note that this can be nil in cases where we are
8790/// directly analysing changes to a type that is not reachable from
8791/// any global function or variable.
8792///
8793/// @return true iff the diff node could be added to the current
8794/// instance of @ref diff_maps.
8795bool
8797 const type_or_decl_base_sptr& impacted_iface)
8798{
8799 string n = get_pretty_representation(dif->first_subject(),
8800 /*internal=*/true);
8801 if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8802 get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8803 else if (const enum_diff *d = is_enum_diff(dif))
8804 get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8805 else if (const class_diff *d = is_class_diff(dif))
8806 get_class_diff_map()[n] = const_cast<class_diff*>(d);
8807 else if (const union_diff *d = is_union_diff(dif))
8808 get_union_diff_map()[n] = const_cast<union_diff*>(d);
8809 else if (const typedef_diff *d = is_typedef_diff(dif))
8810 get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8811 else if (const subrange_diff *d = is_subrange_diff(dif))
8812 get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8813 else if (const array_diff *d = is_array_diff(dif))
8814 get_array_diff_map()[n] = const_cast<array_diff*>(d);
8815 else if (const reference_diff *d = is_reference_diff(dif))
8816 get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8817 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8818 get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8819 else if (const function_type_diff *d = is_function_type_diff(dif))
8820 get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8821 else if (const var_diff *d = is_var_diff(dif))
8822 get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8823 else if (const function_decl_diff *d = is_function_decl_diff(dif))
8824 get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8825 else if (const distinct_diff *d = is_distinct_diff(dif))
8826 get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8827 else if (is_base_diff(dif))
8828 // we silently drop this case.
8829 return true;
8830 else
8832
8833 // Update the map that associates this diff node to the set of
8834 // interfaces it impacts.
8835
8836 if (impacted_iface)
8837 {
8838 diff_artifact_set_map_type::iterator i =
8839 priv_->impacted_artifacts_map_.find(dif);
8840
8841 if (i == priv_->impacted_artifacts_map_.end())
8842 {
8844 set.insert(impacted_iface);
8845 priv_->impacted_artifacts_map_[dif] = set;
8846 }
8847 else
8848 i->second.insert(impacted_iface);
8849 }
8850
8851 return true;
8852}
8853
8854/// Lookup the interfaces that are impacted by a given leaf diff node.
8855///
8856/// @param d the diff node to consider.
8857///
8858/// @return the set of artifacts impacted by @p d.
8861{
8862 diff_artifact_set_map_type::iterator i =
8863 priv_->impacted_artifacts_map_.find(d);
8864
8865 if (i == priv_->impacted_artifacts_map_.end())
8866 return 0;
8867
8868 return &i->second;
8869}
8870
8871//
8872// </diff_maps stuff>
8873
8874/// Constructor for the @ref diff_stat type.
8875///
8876/// @param ctxt the context of the corpus diff. Note that this
8877/// context object must stay alive at least during the life time of
8878/// the current instance of @ref corpus_diff::diff_stats. Otherwise
8879/// memory corruption issues occur.
8880corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8881 : priv_(new priv(ctxt))
8882{}
8883
8884/// Getter for the number of functions removed.
8885///
8886/// @return the number of functions removed.
8887size_t
8889{return priv_->num_func_removed;}
8890
8891/// Setter for the number of functions removed.
8892///
8893/// @param n the new number of functions removed.
8894void
8896{priv_->num_func_removed = n;}
8897
8898/// Getter for the number of removed functions that have been filtered
8899/// out.
8900///
8901/// @return the number of removed functions that have been filtered
8902/// out.
8903size_t
8905{
8906 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8907 return num_func_removed();
8908 return priv_->num_removed_func_filtered_out;
8909}
8910
8911/// Setter for the number of removed functions that have been filtered
8912/// out.
8913///
8914/// @param t the new value.
8915void
8917{priv_->num_removed_func_filtered_out = t;}
8918
8919/// Getter for the net number of function removed.
8920///
8921/// This is the difference between the number of functions removed and
8922/// the number of functons removed that have been filtered out.
8923///
8924/// @return the net number of function removed.
8925size_t
8927{
8928 ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8929 return num_func_removed() - num_removed_func_filtered_out();
8930}
8931
8932/// Getter for the number of functions added.
8933///
8934/// @return the number of functions added.
8935size_t
8937{return priv_->num_func_added;}
8938
8939/// Setter for the number of functions added.
8940///
8941/// @param n the new number of functions added.
8942void
8944{priv_->num_func_added = n;}
8945
8946/// Getter for the number of added function that have been filtered out.
8947///
8948/// @return the number of added function that have been filtered out.
8949size_t
8951{
8952 if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8953 return num_func_added();
8954 return priv_->num_added_func_filtered_out;
8955}
8956
8957/// Setter for the number of added function that have been filtered
8958/// out.
8959///
8960/// @param n the new value.
8961void
8963{priv_->num_added_func_filtered_out = n;}
8964
8965/// Getter for the net number of added functions.
8966///
8967/// The net number of added functions is the difference between the
8968/// number of added functions and the number of added functions that
8969/// have been filtered out.
8970///
8971/// @return the net number of added functions.
8972size_t
8974{
8975 ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8976 return num_func_added() - num_added_func_filtered_out();
8977}
8978
8979/// Getter for the number of functions that have a change in one of
8980/// their sub-types.
8981///
8982/// @return the number of functions that have a change in one of their
8983/// sub-types.
8984size_t
8986{return priv_->num_func_changed;}
8987
8988/// Setter for the number of functions that have a change in one of
8989/// their sub-types.
8990///
8991/// @@param n the new number of functions that have a change in one of
8992/// their sub-types.
8993void
8995{priv_->num_func_changed = n;}
8996
8997/// Getter for the number of functions that have a change in one of
8998/// their sub-types, and that have been filtered out.
8999///
9000/// @return the number of functions that have a change in one of their
9001/// sub-types, and that have been filtered out.
9002size_t
9004{return priv_->num_changed_func_filtered_out;}
9005
9006/// Setter for the number of functions that have a change in one of
9007/// their sub-types, and that have been filtered out.
9008///
9009/// @param n the new number of functions that have a change in one of their
9010/// sub-types, and that have been filtered out.
9011void
9013{priv_->num_changed_func_filtered_out = n;}
9014
9015/// Getter for the number of functions that carry virtual member
9016/// offset changes.
9017///
9018/// @return the number of functions that carry virtual member changes.
9019size_t
9021{return priv_->num_func_with_virt_offset_changes;}
9022
9023/// Setter for the number of functions that carry virtual member
9024/// offset changes.
9025///
9026/// @param n the new number of functions that carry virtual member
9027/// offset. changes.
9028void
9030{priv_->num_func_with_virt_offset_changes = n;}
9031
9032/// Getter for the number of functions with local harmful changes.
9033///
9034/// A local harmful change is a harmful change that is local to the
9035/// function itself or is local to a return or parameter type.
9036///
9037/// @return the number of functions with local harmful changes.
9038size_t
9040{return priv_->num_func_with_local_harmful_changes;}
9041
9042/// Setter for the number of functions with local harmful changes.
9043///
9044/// A local harmful change is a harmful change that is local to the
9045/// function itself or is local to a return or parameter type.
9046///
9047/// @param n the number of functions with local harmful changes.
9048void
9050{priv_->num_func_with_local_harmful_changes = n;}
9051
9052/// Getter for the number of variables with local harmful changes.
9053///
9054/// A local harmful change is a harmful change that is local to the
9055/// variable itself or is local to its type.
9056///
9057/// @return the number of variables with local harmful changes.
9058size_t
9060{return priv_->num_var_with_local_harmful_changes;}
9061
9062/// Setter for the number of variables with local harmful changes.
9063///
9064/// A local harmful change is a harmful change that is local to the
9065/// variable itself or is local to its type.
9066///
9067/// @param n the number of variables with local harmful changes.
9068void
9070{priv_->num_var_with_local_harmful_changes = n;}
9071
9072/// Getter for the number of functions with incompatible changes.
9073///
9074/// @return the number of functions with incompatible changes.
9075size_t
9077{return priv_->num_func_with_incompatible_changes;}
9078
9079/// Setter for the number of functions with incompatible changes.
9080///
9081/// @param n the number of functions with incompatible changes.
9082void
9084{priv_->num_func_with_incompatible_changes = n;}
9085
9086/// Getter for the number of variables with incompatible changes.
9087///
9088/// @return the number of variables with incompatible changes.
9089size_t
9091{return priv_->num_var_with_incompatible_changes;}
9092
9093/// Setter for the number of variables with incompatible changes.
9094///
9095/// @param n the number of variables with incompatible changes.
9096void
9098{priv_->num_var_with_incompatible_changes = n;}
9099
9100/// Getter for the number of functions that have a change in their
9101/// sub-types, minus the number of these functions that got filtered
9102/// out from the diff.
9103///
9104/// @return for the the number of functions that have a change in
9105/// their sub-types, minus the number of these functions that got
9106/// filtered out from the diff.
9107size_t
9109{return num_func_changed() - num_changed_func_filtered_out();}
9110
9111/// Getter of the net number of functions with changes that are not
9112/// incompatible.
9113///
9114/// @return net number of functions with changes that are not
9115/// incompatible.
9116size_t
9118{return net_num_func_changed() - num_func_with_incompatible_changes();}
9119
9120/// Getter for the number of variables removed.
9121///
9122/// @return the number of variables removed.
9123size_t
9125{return priv_->num_vars_removed;}
9126
9127/// Setter for the number of variables removed.
9128///
9129/// @param n the new number of variables removed.
9130void
9132{priv_->num_vars_removed = n;}
9133
9134/// Getter for the number removed variables that have been filtered
9135/// out.
9136///
9137/// @return the number removed variables that have been filtered out.
9138size_t
9140{
9141 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
9142 return num_vars_removed();
9143 return priv_->num_removed_vars_filtered_out;
9144}
9145
9146/// Setter for the number of removed variables that have been filtered
9147/// out.
9148///
9149/// @param n the new value.
9150void
9152{priv_->num_removed_vars_filtered_out = n;}
9153
9154/// Getter for the net number of removed variables.
9155///
9156/// The net number of removed variables is the difference between the
9157/// number of removed variables and the number of removed variables
9158/// that have been filtered out.
9159///
9160/// @return the net number of removed variables.
9161size_t
9163{
9164 ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
9165 return num_vars_removed() - num_removed_vars_filtered_out();
9166}
9167
9168/// Getter for the number of variables added.
9169///
9170/// @return the number of variables added.
9171size_t
9173{return priv_->num_vars_added;}
9174
9175/// Setter for the number of variables added.
9176///
9177/// @param n the new number of variables added.
9178void
9180{priv_->num_vars_added = n;}
9181
9182/// Getter for the number of added variables that have been filtered
9183/// out.
9184///
9185/// @return the number of added variables that have been filtered out.
9186size_t
9188{
9189 if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
9190 return num_vars_added();
9191 return priv_->num_added_vars_filtered_out;
9192}
9193
9194/// Setter for the number of added variables that have been filtered
9195/// out.
9196///
9197/// @param n the new value.
9198void
9200{priv_->num_added_vars_filtered_out = n;}
9201
9202/// Getter for the net number of added variables.
9203///
9204/// The net number of added variables is the difference between the
9205/// number of added variables and the number of added variables that
9206/// have been filetered out.
9207///
9208/// @return the net number of added variables.
9209size_t
9211{
9212 ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
9213 return num_vars_added() - num_added_vars_filtered_out();
9214}
9215
9216/// Getter for the number of variables that have a change in one of
9217/// their sub-types.
9218///
9219/// @return the number of variables that have a change in one of their
9220/// sub-types.
9221size_t
9223{return priv_->num_vars_changed;}
9224
9225/// Setter for the number of variables that have a change in one of
9226/// their sub-types.
9227///
9228/// @param n the new number of variables that have a change in one of
9229/// their sub-types.
9230void
9232{priv_->num_vars_changed = n;}
9233
9234/// Getter for the number of variables that have a change in one of
9235/// their sub-types, and that have been filtered out.
9236///
9237/// @return the number of functions that have a change in one of their
9238/// sub-types, and that have been filtered out.
9239size_t
9241{return priv_->num_changed_vars_filtered_out;}
9242
9243/// Setter for the number of variables that have a change in one of
9244/// their sub-types, and that have been filtered out.
9245///
9246/// @param n the new number of variables that have a change in one of their
9247/// sub-types, and that have been filtered out.
9248void
9250{priv_->num_changed_vars_filtered_out = n;}
9251
9252/// Getter for the number of variables that have a change in their
9253/// sub-types, minus the number of these variables that got filtered
9254/// out from the diff.
9255///
9256/// @return for the the number of variables that have a change in
9257/// their sub-types, minus the number of these variables that got
9258/// filtered out from the diff.
9259size_t
9261{return num_vars_changed() - num_changed_vars_filtered_out();}
9262
9263/// Getter of the net number of variables with changes that are not
9264/// incompatible.
9265///
9266/// @return net number of variables with changes that are not
9267/// incompatible.
9268size_t
9270{return net_num_vars_changed() - num_var_with_incompatible_changes();}
9271
9272/// Getter for the number of function symbols (not referenced by any
9273/// debug info) that got removed.
9274///
9275/// @return the number of function symbols (not referenced by any
9276/// debug info) that got removed.
9277size_t
9279{return priv_->num_func_syms_removed;}
9280
9281/// Setter for the number of function symbols (not referenced by any
9282/// debug info) that got removed.
9283///
9284/// @param n the number of function symbols (not referenced by any
9285/// debug info) that got removed.
9286void
9288{priv_->num_func_syms_removed = n;}
9289
9290/// Getter for the number of removed function symbols, not referenced
9291/// by debug info, that have been filtered out.
9292///
9293/// @return the number of removed function symbols, not referenced by
9294/// debug info, that have been filtered out.
9295size_t
9297{
9298 if (priv_->ctxt()
9299 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
9300 return num_func_syms_removed();
9301 return priv_->num_removed_func_syms_filtered_out;
9302}
9303
9304/// Setter for the number of removed function symbols, not referenced
9305/// by debug info, that have been filtered out.
9306///
9307/// @param n the new the number of removed function symbols, not
9308/// referenced by debug info, that have been filtered out.
9309void
9311{priv_->num_removed_func_syms_filtered_out = n;}
9312
9313/// Getter of the net number of removed function symbols that are not
9314/// referenced by any debug info.
9315///
9316/// This is the difference between the total number of removed
9317/// function symbols and the number of removed function symbols that
9318/// have been filteted out. Both numbers are for symbols not
9319/// referenced by debug info.
9320///
9321/// return the net number of removed function symbols that are not
9322/// referenced by any debug info.
9323size_t
9325{
9326 ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
9327 return num_func_syms_removed() - num_removed_func_syms_filtered_out();
9328}
9329
9330/// Getter for the number of function symbols (not referenced by any
9331/// debug info) that got added.
9332///
9333/// @return the number of function symbols (not referenced by any
9334/// debug info) that got added.
9335size_t
9337{return priv_->num_func_syms_added;}
9338
9339/// Setter for the number of function symbols (not referenced by any
9340/// debug info) that got added.
9341///
9342/// @param n the new number of function symbols (not referenced by any
9343/// debug info) that got added.
9344void
9346{priv_->num_func_syms_added = n;}
9347
9348/// Getter for the number of added function symbols, not referenced by
9349/// any debug info, that have been filtered out.
9350///
9351/// @return the number of added function symbols, not referenced by
9352/// any debug info, that have been filtered out.
9353size_t
9355{
9356 if (priv_->ctxt()
9357 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9358 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9359 return num_func_syms_added();
9360 return priv_->num_added_func_syms_filtered_out;
9361}
9362
9363/// Setter for the number of added function symbols, not referenced by
9364/// any debug info, that have been filtered out.
9365///
9366/// @param n the new number of added function symbols, not referenced
9367/// by any debug info, that have been filtered out.
9368void
9370{priv_->num_added_func_syms_filtered_out = n;}
9371
9372/// Getter of the net number of added function symbols that are not
9373/// referenced by any debug info.
9374///
9375/// This is the difference between the total number of added
9376/// function symbols and the number of added function symbols that
9377/// have been filteted out. Both numbers are for symbols not
9378/// referenced by debug info.
9379///
9380/// return the net number of added function symbols that are not
9381/// referenced by any debug info.
9382size_t
9384{
9385 ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
9386 return num_func_syms_added()- num_added_func_syms_filtered_out();
9387}
9388
9389/// Getter for the number of variable symbols (not referenced by any
9390/// debug info) that got removed.
9391///
9392/// @return the number of variable symbols (not referenced by any
9393/// debug info) that got removed.
9394size_t
9396{return priv_->num_var_syms_removed;}
9397
9398/// Setter for the number of variable symbols (not referenced by any
9399/// debug info) that got removed.
9400///
9401/// @param n the number of variable symbols (not referenced by any
9402/// debug info) that got removed.
9403void
9405{priv_->num_var_syms_removed = n;}
9406
9407/// Getter for the number of removed variable symbols, not referenced
9408/// by any debug info, that have been filtered out.
9409///
9410/// @return the number of removed variable symbols, not referenced
9411/// by any debug info, that have been filtered out.
9412size_t
9414{
9415 if (priv_->ctxt()
9416 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
9417 return num_var_syms_removed();
9418 return priv_->num_removed_var_syms_filtered_out;
9419}
9420
9421/// Setter for the number of removed variable symbols, not referenced
9422/// by any debug info, that have been filtered out.
9423///
9424/// @param n the number of removed variable symbols, not referenced by
9425/// any debug info, that have been filtered out.
9426void
9428{priv_->num_removed_var_syms_filtered_out = n;}
9429
9430/// Getter of the net number of removed variable symbols that are not
9431/// referenced by any debug info.
9432///
9433/// This is the difference between the total number of removed
9434/// variable symbols and the number of removed variable symbols that
9435/// have been filteted out. Both numbers are for symbols not
9436/// referenced by debug info.
9437///
9438/// return the net number of removed variable symbols that are not
9439/// referenced by any debug info.
9440size_t
9442{
9443 ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
9444 return num_var_syms_removed() - num_removed_var_syms_filtered_out();
9445}
9446
9447/// Getter for the number of variable symbols (not referenced by any
9448/// debug info) that got added.
9449///
9450/// @return the number of variable symbols (not referenced by any
9451/// debug info) that got added.
9452size_t
9454{return priv_->num_var_syms_added;}
9455
9456/// Setter for the number of variable symbols (not referenced by any
9457/// debug info) that got added.
9458///
9459/// @param n the new number of variable symbols (not referenced by any
9460/// debug info) that got added.
9461void
9463{priv_->num_var_syms_added = n;}
9464
9465/// Getter for the number of added variable symbols, not referenced by
9466/// any debug info, that have been filtered out.
9467///
9468/// @return the number of added variable symbols, not referenced by
9469/// any debug info, that have been filtered out.
9470size_t
9472{
9473 if (priv_->ctxt()
9474 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9475 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9476 return num_var_syms_added();
9477 return priv_->num_added_var_syms_filtered_out;
9478}
9479
9480/// Setter for the number of added variable symbols, not referenced by
9481/// any debug info, that have been filtered out.
9482///
9483/// @param n the new number of added variable symbols, not referenced
9484/// by any debug info, that have been filtered out.
9485void
9487{priv_->num_added_var_syms_filtered_out = n;}
9488
9489/// Getter of the net number of added variable symbols that are not
9490/// referenced by any debug info.
9491///
9492/// This is the difference between the total number of added
9493/// variable symbols and the number of added variable symbols that
9494/// have been filteted out. Both numbers are for symbols not
9495/// referenced by debug info.
9496///
9497/// return the net number of added variable symbols that are not
9498/// referenced by any debug info.
9499size_t
9501{
9502 ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
9503 return num_var_syms_added() - num_added_var_syms_filtered_out();
9504}
9505
9506/// Getter of the number of leaf type change diff nodes.
9507///
9508/// @return the number of leaf type change diff nodes.
9509size_t
9511{return priv_->num_leaf_changes;}
9512
9513/// Setter of the number of leaf type change diff nodes.
9514///
9515/// @param n the new number of leaf type change diff nodes.
9516void
9518{priv_->num_leaf_changes = n;}
9519
9520/// Getter of the number of leaf type change diff nodes that have been
9521/// filtered out.
9522///
9523/// @return the number of leaf type change diff nodes that have been
9524size_t
9526{return priv_->num_leaf_changes_filtered_out;}
9527
9528/// Setter of the number of leaf type change diff nodes that have been
9529/// filtered out.
9530///
9531/// @param n the new number of leaf type change diff nodes that have
9532/// been filtered out.
9533void
9535{priv_->num_leaf_changes_filtered_out = n;}
9536
9537/// Getter of the net number of leaf change diff nodes.
9538///
9539/// This is the difference between the total number of leaf change
9540/// diff nodes, and the number of the leaf change diff nodes that have
9541/// been filtered out.
9542///
9543/// A leaf change is either a type change, a function change or a
9544/// variable change.
9545size_t
9547{
9548 ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
9549 return num_leaf_changes() - num_leaf_changes_filtered_out();
9550}
9551
9552/// Getter for the number of leaf type change diff nodes.
9553///
9554/// @return the number of leaf type changes diff nodes.
9555size_t
9557{return priv_->num_leaf_type_changes;}
9558
9559/// Setter for the number of leaf type change diff nodes.
9560///
9561/// @param n the new number of leaf type change diff nodes.
9562void
9564{priv_->num_leaf_type_changes = n;}
9565
9566/// Getter for the number of filtered out leaf type change diff nodes.
9567///
9568/// @return the number of filtered out leaf type change diff nodes.
9569size_t
9571{return priv_->num_leaf_type_changes_filtered_out;}
9572
9573/// Setter for the number of filtered out leaf type change diff nodes.
9574/// @param n the new number of filtered out leaf type change diff nodes.
9575void
9577{priv_->num_leaf_type_changes_filtered_out = n;}
9578
9579/// Getter for the net number of leaf type change diff nodes.
9580///
9581/// This is the difference between the number of leaf type changes and
9582/// the number of filtered out leaf type changes.
9583///
9584/// @return the net number of leaf type change diff nodes.
9585size_t
9587{return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
9588
9589/// Getter for the number of leaf function change diff nodes.
9590///
9591/// @return the number of leaf function change diff nodes.
9592size_t
9594{return priv_->num_leaf_func_changes;}
9595
9596/// Setter for the number of leaf function change diff nodes.
9597///
9598/// @param n the new number of leaf function change diff nodes.
9599void
9601{priv_->num_leaf_func_changes = n;}
9602
9603/// Getter for the number of leaf function diff nodes that carry
9604/// incompatible changes.
9605///
9606/// @return the number of leaf function diff nodes that carry
9607/// incompatible changes.
9608size_t
9610{return priv_->num_leaf_func_with_incompatible_changes;}
9611
9612/// Setter for the number of leaf function diff nodes that carry
9613/// incompatible changes.
9614///
9615/// @param n the new number of leaf function diff nodes that carry
9616/// incompatible changes.
9617void
9619{priv_->num_leaf_func_with_incompatible_changes = n;}
9620
9621/// Getter for the number of leaf function change diff nodes that were
9622/// filtered out.
9623///
9624/// @return the number of leaf function change diff nodes that were
9625/// filtered out.
9626size_t
9628{return priv_->num_leaf_func_changes_filtered_out;}
9629
9630/// Setter for the number of leaf function change diff nodes that were
9631/// filtered out.
9632///
9633/// @param n the new number of leaf function change diff nodes that
9634/// were filtered out.
9635void
9637{priv_->num_leaf_func_changes_filtered_out = n;}
9638
9639/// Getter for the net number of leaf function change diff nodes.
9640///
9641/// This is the difference between the number of leaf function change
9642/// diff nodes and the number of filtered out leaf function change
9643/// diff nodes.
9644///
9645/// @return the net number of leaf function change diff nodes.
9646size_t
9648{return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
9649
9650/// Getter for the net number of leaf function diff nodes that carry
9651/// changes that are NOT incompatible.
9652///
9653/// @return net number of leaf function diff nodes that carry changes
9654/// that are NOT incompatible.
9655size_t
9657{
9658 return (net_num_leaf_func_changes()
9659 - num_leaf_func_with_incompatible_changes());
9660}
9661
9662/// Getter for the number of leaf variable change diff nodes.
9663///
9664/// @return the number of leaf variable change diff nodes.
9665size_t
9667{return priv_->num_leaf_var_changes;}
9668
9669/// Setter for the number of leaf variable change diff nodes.
9670///
9671/// @param n the number of leaf variable change diff nodes.
9672void
9674{priv_->num_leaf_var_changes = n;}
9675
9676/// Getter for the number of leaf variable diff nodes that carry
9677/// incompatible changes.
9678///
9679/// @return the number of leaf variable diff nodes that carry
9680/// incompatible changes.
9681size_t
9683{return priv_->num_leaf_var_with_incompatible_changes;}
9684
9685/// Setter for the number of leaf variable diff nodes that carry
9686/// incompatible changes.
9687///
9688/// @param n the new number of leaf variable diff nodes that carry
9689/// incompatible changes.
9690void
9692{priv_->num_leaf_var_with_incompatible_changes = n;}
9693
9694/// Getter of the number of added types that are unreachable from the
9695/// public interface of the ABI corpus.
9696///
9697/// Public interface means the set of defined and publicly exported
9698/// functions and variables of the ABI corpus.
9699///
9700/// @return the number of added types that are unreachable from the
9701/// public interface of the ABI corpus.
9702size_t
9704{return priv_->num_added_unreachable_types;}
9705
9706/// Setter of the number of added types that are unreachable from the
9707/// public interface (global functions or variables) of the ABI
9708/// corpus.
9709///
9710/// Public interface means the set of defined and publicly exported
9711/// functions and variables of the ABI corpus.
9712///
9713/// @param n the new number of added types that are unreachable from
9714/// the public interface of the ABI corpus.
9715void
9717{priv_->num_added_unreachable_types = n;}
9718
9719/// Getter of the number of added types that are unreachable from
9720/// public interfaces and that are filtered out by suppression
9721/// specifications.
9722///
9723/// @return the number of added types that are unreachable from public
9724/// interfaces and that are filtered out by suppression
9725/// specifications.
9726size_t
9728{return priv_->num_added_unreachable_types_filtered_out;}
9729
9730/// Setter of the number of added types that are unreachable from
9731/// public interfaces and that are filtered out by suppression
9732/// specifications.
9733///
9734/// @param n the new number of added types that are unreachable from
9735/// public interfaces and that are filtered out by suppression
9736/// specifications.
9737void
9739{priv_->num_added_unreachable_types_filtered_out = n;}
9740
9741/// Getter of the number of added types that are unreachable from
9742/// public interfaces and that are *NOT* filtered out by suppression
9743/// specifications.
9744///
9745/// @return the number of added types that are unreachable from public
9746/// interfaces and that are *NOT* filtered out by suppression
9747/// specifications.
9748size_t
9750{
9751 ABG_ASSERT(num_added_unreachable_types()
9752 >=
9753 num_added_unreachable_types_filtered_out());
9754
9755 return (num_added_unreachable_types()
9756 -
9757 num_added_unreachable_types_filtered_out());
9758}
9759
9760/// Getter of the number of removed types that are unreachable from
9761/// the public interface of the ABI corpus.
9762///
9763/// Public interface means the set of defined and publicly exported
9764/// functions and variables of the ABI corpus.
9765///
9766/// @return the number of removed types that are unreachable from
9767/// the public interface of the ABI corpus.
9768size_t
9770{return priv_->num_removed_unreachable_types;}
9771
9772/// Setter of the number of removed types that are unreachable from
9773/// the public interface of the ABI corpus.
9774///
9775/// Public interface means the set of defined and publicly exported
9776/// functions and variables of the ABI corpus.
9777///
9778///@param n the new number of removed types that are unreachable from
9779/// the public interface of the ABI corpus.
9780void
9782{priv_->num_removed_unreachable_types = n;}
9783
9784/// Getter of the number of removed types that are not reachable from
9785/// public interfaces and that have been filtered out by suppression
9786/// specifications.
9787///
9788/// @return the number of removed types that are not reachable from
9789/// public interfaces and that have been filtered out by suppression
9790/// specifications.
9791size_t
9793{return priv_->num_removed_unreachable_types_filtered_out;}
9794
9795/// Setter of the number of removed types that are not reachable from
9796/// public interfaces and that have been filtered out by suppression
9797/// specifications.
9798///
9799/// @param n the new number of removed types that are not reachable
9800/// from public interfaces and that have been filtered out by
9801/// suppression specifications.
9802void
9804{priv_->num_removed_unreachable_types_filtered_out = n;}
9805
9806/// Getter of the number of removed types that are not reachable from
9807/// public interfaces and that have *NOT* been filtered out by
9808/// suppression specifications.
9809///
9810/// @return the number of removed types that are not reachable from
9811/// public interfaces and that have *NOT* been filtered out by
9812/// suppression specifications.
9813size_t
9815{
9816 ABG_ASSERT(num_removed_unreachable_types()
9817 >=
9818 num_removed_unreachable_types_filtered_out());
9819
9820 return (num_removed_unreachable_types()
9821 -
9822 num_removed_unreachable_types_filtered_out());
9823}
9824
9825/// Getter of the number of changed types that are unreachable from
9826/// the public interface of the ABI corpus.
9827///
9828/// Public interface means the set of defined and publicly exported
9829/// functions and variables of the ABI corpus.
9830///
9831/// @return the number of changed types that are unreachable from the
9832/// public interface of the ABI corpus.
9833size_t
9835{return priv_->num_changed_unreachable_types;}
9836
9837/// Setter of the number of changed types that are unreachable from
9838/// the public interface of the ABI corpus.
9839///
9840/// Public interface means the set of defined and publicly exported
9841/// functions and variables of the ABI corpus.
9842///
9843///@param n the new number of changed types that are unreachable from
9844/// the public interface of the ABI corpus.
9845void
9847{priv_->num_changed_unreachable_types = n;}
9848
9849/// Getter of the number of changed types that are unreachable from
9850/// public interfaces and that have been filtered out by suppression
9851/// specifications.
9852///
9853/// @return the number of changed types that are unreachable from
9854/// public interfaces and that have been filtered out by suppression
9855/// specifications.
9856size_t
9858{return priv_->num_changed_unreachable_types_filtered_out;}
9859
9860/// Setter of the number of changed types that are unreachable from
9861/// public interfaces and that have been filtered out by suppression
9862/// specifications.
9863///
9864/// @param n the new number of changed types that are unreachable from
9865/// public interfaces and that have been filtered out by suppression
9866/// specifications.
9867void
9869{priv_->num_changed_unreachable_types_filtered_out = n;}
9870
9871/// Getter of the number of changed types that are unreachable from
9872/// public interfaces and that have *NOT* been filtered out by
9873/// suppression specifications.
9874///
9875/// @return the number of changed types that are unreachable from
9876/// public interfaces and that have *NOT* been filtered out by
9877/// suppression specifications.
9878size_t
9880{
9881 ABG_ASSERT(num_changed_unreachable_types()
9882 >=
9883 num_changed_unreachable_types_filtered_out());
9884
9885 return (num_changed_unreachable_types()
9886 -
9887 num_changed_unreachable_types_filtered_out());
9888}
9889
9890/// Getter for the number of leaf variable changes diff nodes that
9891/// have been filtered out.
9892///
9893/// @return the number of leaf variable changes diff nodes that have
9894/// been filtered out.
9895size_t
9897{return priv_->num_leaf_var_changes_filtered_out;}
9898
9899/// Setter for the number of leaf variable changes diff nodes that
9900/// have been filtered out.
9901///
9902/// @param n the number of leaf variable changes diff nodes that have
9903/// been filtered out.
9904void
9906{priv_->num_leaf_var_changes_filtered_out = n;}
9907
9908/// Getter for the net number of leaf variable change diff nodes.
9909///
9910/// This the difference between the number of leaf variable change
9911/// diff nodes and the number of filtered out leaf variable change
9912/// diff nodes.
9913///
9914/// @return the net number of leaf variable change diff nodes.
9915size_t
9917{return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9918
9919/// Getter for the net number of leaf variable diff nodes that carry
9920/// changes that are NOT incompatible.
9921///
9922/// @return the net number of leaf variable diff nodes that carry
9923/// changes that are NOT incompatible.
9924size_t
9926{return net_num_leaf_var_changes() - num_leaf_var_with_incompatible_changes();}
9927// <corpus_diff stuff>
9928
9929/// Getter of the context associated with this corpus.
9930///
9931/// @return a smart pointer to the context associate with the corpus.
9934{return ctxt_.lock();}
9935
9936/// Tests if the lookup tables are empty.
9937///
9938/// @return true if the lookup tables are empty, false otherwise.
9939bool
9941{
9942 return (deleted_fns_.empty()
9943 && added_fns_.empty()
9944 && changed_fns_map_.empty()
9945 && deleted_vars_.empty()
9946 && added_vars_.empty()
9947 && changed_vars_map_.empty());
9948}
9949
9950/// Clear the lookup tables useful for reporting an enum_diff.
9951void
9953{
9954 deleted_fns_.clear();
9955 added_fns_.clear();
9956 changed_fns_map_.clear();
9957 deleted_vars_.clear();
9958 added_vars_.clear();
9959 changed_vars_map_.clear();
9960}
9961
9962/// Add a @ref function_decl* to the 'deleted_fns_' map in the current
9963/// instance of @ref corpus_diff::priv.
9964///
9965/// @param fn the function to add to the 'deleted_fns_' data member of
9966/// @ref corpus_diff::priv.
9967void
9969{
9970
9971 if (!fn)
9972 return;
9973
9975 auto it = deleted_fns_.find(id);
9976 if (it == deleted_fns_.end())
9977 it = deleted_fns_.emplace(id, functions_set_type()).first;
9978 it->second.insert(fn);
9979}
9980
9981/// Add a @ref function_decl* to the 'added_fns_' map in the current
9982/// instance of @ref corpus_diff::priv.
9983///
9984/// @param fn the function to add to the 'added_fns_' data member of
9985/// @ref corpus_diff::priv.
9986void
9988{
9989 if (!fn)
9990 return;
9991
9993 auto it = added_fns_.find(id);
9994 if (it == added_fns_.end())
9995 it = added_fns_.emplace(id, functions_set_type()).first;
9996 it->second.insert(fn);
9997}
9998
9999/// If the lookup tables are not yet built, walk the differences and
10000/// fill the lookup tables.
10001void
10003{
10004 if (!lookup_tables_empty())
10005 return;
10006
10007 diff_context_sptr ctxt = get_context();
10008
10009 // Use hash-based set difference to classify functions as
10010 // added/deleted/changed, avoiding the quadratic Myers diff.
10011 {
10012 // Build an ancillary map of function symbol ID -> function_decl*
10013 // for the first corpus. It ultimately collects functions found
10014 // in the first corpus and not present in the second.
10015 unordered_map<string, const function_decl*> first_fns_map;
10016 first_fns_map.reserve(first_->get_functions().size());
10017 for (const auto* fn : first_->get_functions())
10018 {
10019 string n = get_function_symbol_id(fn);
10020 ABG_ASSERT(!n.empty());
10021 first_fns_map[n] = fn;
10022 }
10023
10024 for (const auto* fn : second_->get_functions())
10025 {
10026 string n = get_function_symbol_id(fn);
10027 ABG_ASSERT(!n.empty());
10028
10029 const unordered_set<const function_decl*>* found = nullptr;
10030 // This variable should be set to true to mean that one
10031 // instance of the function was present in the first_ corpus,
10032 // one instance of it is still present in the second_ corpus
10033 // and the two instances of the function are different.
10034 // That's a function /change/ (not an addition, not a removal,
10035 // a real change).
10036 //
10037 // Let's initialize it to true, and then try to detect cases
10038 // where the function got either added, removed, or hasn't
10039 // changed at all.
10040 bool fn_has_changed = true;
10041 if ((found = first_->lookup_functions(n)))
10042 {
10043 for (auto first_fn : *found)
10044 {
10045 if (*first_fn == *fn)
10046 {
10047 fn_has_changed = false;
10048 break;
10049 }
10050 }
10051 }
10052 else
10053 fn_has_changed = false;
10054
10055 if (fn_has_changed)
10056 {
10057 // "found" is a vector of functions (from the first ABI
10058 // corpus) which all have the same ID. These functions
10059 // are also /all/ different from the function having the
10060 // same ID and found in the second ABI corpus. Let's
10061 // compare the first function from "found" against the one
10062 // in the second ABI corpus. Once the user fixes the
10063 // sub-type differences described by the function-diff
10064 // below, he'll be able to re-run the comparison and see
10065 // if there are other function changes like this.
10066 vector<const function_decl*> sorted_fns;
10067 sorted_fns.reserve(found->size());
10068 for (auto f : *found)
10069 sorted_fns.push_back(f);
10071 std::sort(sorted_fns.begin(), sorted_fns.end(), comp);
10072
10073 const function_decl* first_fn = *sorted_fns.begin();
10074
10075 // Function exists in both corpora and has changed.
10076 ABG_ASSERT(*first_fn != *fn);
10077 function_decl_sptr f(const_cast<function_decl*>(first_fn),
10078 noop_deleter());
10079 function_decl_sptr s(const_cast<function_decl*>(fn),
10080 noop_deleter());
10081 function_decl_diff_sptr d = compute_diff(f, s, ctxt);
10082 changed_fns_map_[n] = d;
10083 first_fns_map.erase(n);
10084 }
10085 else
10086 {
10087 if (found)
10088 first_fns_map.erase(n);
10089 else
10090 add_function_to_added_functions(fn);
10091 }
10092 }
10093
10094 // Remaining entries in first_fns_map are deleted functions.
10095 for (const auto& entry : first_fns_map)
10096 add_function_to_deleted_functions(entry.second);
10097
10098 sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
10099
10100 // Now walk the allegedly deleted functions; check if their
10101 // underlying symbols are deleted as well; otherwise, consider
10102 // that the function in question hasn't been deleted.
10103
10104 vector<interned_string> to_delete;
10105 for (auto& entry : deleted_fns_)
10106 {
10107 // If the entry describing a deleted function designated by a
10108 // function ID has at least one associated function then let's
10109 // see if the associated ELF symbol is present in the second
10110 // corpus. If it is, then the entry should be removed as the
10111 // function is not removed from the corpus. Let's schedule
10112 // the entry for removal then.
10113 bool do_delete = entry.second.empty();
10114 for (auto fn : entry.second)
10115 {
10116 if (!fn->get_symbol()
10117 && !(is_member_function(fn)
10119 {
10120 // A non-virtual function with an empty symbol.
10121 // Delete it from the set of deleted functions.
10122 do_delete = true;
10123 break;
10124 }
10125
10126 if (second_->lookup_function_symbol(get_function_symbol_id(fn)))
10127 {
10128 // The function is still present in the second ABI
10129 // corpus. So there is no way it's been deleted,
10130 // obviously. So deleted from the set of deleted
10131 // functions.
10132 do_delete = true;
10133 break;
10134 }
10135 }
10136
10137 if (do_delete)
10138 to_delete.push_back(entry.first);
10139 }
10140
10141 for (auto i = to_delete.begin(); i != to_delete.end(); ++i)
10142 deleted_fns_.erase(*i);
10143
10144 // Do something similar for added functions.
10145 to_delete.clear();
10146 for (auto& entry : added_fns_)
10147 {
10148 bool do_delete = entry.second.empty();
10149 for (auto f : entry.second)
10150 {
10151 if (!f->get_symbol()
10152 && !(is_member_function(f)
10154 {
10155 do_delete = true;
10156 break;
10157 }
10158
10159 if (first_->lookup_function_symbol(*f->get_symbol()))
10160 {
10161 do_delete = true;
10162 break;
10163 }
10164 }
10165
10166 if (do_delete)
10167 to_delete.push_back(entry.first);
10168 else
10169 {
10170 if (!entry.second.empty())
10171 {
10172 const function_decl* f = *entry.second.begin();
10173 if (!f->get_symbol()->get_version().is_empty()
10174 && f->get_symbol()->get_version().is_default())
10175 // We are looking for a symbol that has a default version,
10176 // and which seems to be newly added. Let's see if the same
10177 // symbol with *no* version was already present in the
10178 // former corpus. If yes, then the symbol shouldn't be
10179 // considered as 'added'.
10180 {
10181 const string& sym_name = f->get_symbol()->get_name();
10182 elf_symbol::version empty_version;
10183 if (first_->lookup_function_symbol(sym_name,
10184 empty_version))
10185 // The ELF symbol of the 'added function' was
10186 // already present in the first corpus. So
10187 // let's schedule the removal the added function
10188 // from the set of added functions.
10189 to_delete.push_back(entry.first);
10190 }
10191 }
10192 }
10193 }
10194
10195 // Let's remove the added functions that have been scheduled for
10196 // removal.
10197 for (auto& s : to_delete)
10198 added_fns_.erase(s);
10199 }
10200
10201 // Use hash-based set difference to classify variables as
10202 // added/deleted/changed, avoiding the quadratic Myers diff.
10203 {
10204 // Build a map of variable ID -> var_decl_sptr for the first corpus.
10205 unordered_map<string, var_decl_sptr> first_vars_map;
10206 first_vars_map.reserve(first_->get_variables().size());
10207 for (const auto& var : first_->get_variables())
10208 {
10209 string n = var->get_id();
10210 ABG_ASSERT(!n.empty());
10211 // Keep only the first instance of duplicate IDs (static
10212 // member variables from multiple translation units).
10213 if (first_vars_map.find(n) == first_vars_map.end())
10214 first_vars_map[n] = var;
10215 else
10217 || !is_member_decl(var));
10218 }
10219
10220 for (const auto& var : second_->get_variables())
10221 {
10222 string n = var->get_id();
10223 ABG_ASSERT(!n.empty());
10224 auto j = first_vars_map.find(n);
10225 if (j != first_vars_map.end())
10226 {
10227 // Variable exists in both corpora -- check if changed.
10228 if (*j->second != *var)
10229 {
10230 var_decl_sptr f = j->second;
10231 var_decl_sptr s = var;
10232 changed_vars_map_[n] = compute_diff(f, s, ctxt);
10233 }
10234 first_vars_map.erase(j);
10235 }
10236 else if (added_vars_.find(n) == added_vars_.end())
10237 added_vars_[n] = var;
10238 else
10240 }
10241
10242 // Remaining entries in first_vars_map are deleted variables.
10243 for (const auto& entry : first_vars_map)
10244 deleted_vars_[entry.first] = entry.second;
10245
10246 sort_string_var_diff_sptr_map(changed_vars_map_,
10247 sorted_changed_vars_);
10248
10249 // Now walk the allegedly deleted variables; check if their
10250 // underlying symbols are deleted as well; otherwise consider
10251 // that the variable in question hasn't been deleted.
10252
10253 vector<string> to_delete;
10254 for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
10255 i != deleted_vars_.end();
10256 ++i)
10257 if (second_->lookup_variable_symbol(*i->second->get_symbol()))
10258 to_delete.push_back(i->first);
10259
10260 for (vector<string>::const_iterator i = to_delete.begin();
10261 i != to_delete.end();
10262 ++i)
10263 deleted_vars_.erase(*i);
10264
10265 // Do something similar for added variables.
10266
10267 to_delete.clear();
10268 for (string_var_ptr_map::const_iterator i = added_vars_.begin();
10269 i != added_vars_.end();
10270 ++i)
10271 if (first_->lookup_variable_symbol(*i->second->get_symbol()))
10272 to_delete.push_back(i->first);
10273 else if (! i->second->get_symbol()->get_version().is_empty()
10274 && i->second->get_symbol()->get_version().is_default())
10275 // We are looking for a symbol that has a default version,
10276 // and which seems to be newly added. Let's see if the same
10277 // symbol with *no* version was already present in the
10278 // former corpus. If yes, then the symbol shouldn't be
10279 // considered as 'added'.
10280 {
10281 elf_symbol::version empty_version;
10282 if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
10283 empty_version))
10284 to_delete.push_back(i->first);
10285 }
10286
10287 for (vector<string>::const_iterator i = to_delete.begin();
10288 i != to_delete.end();
10289 ++i)
10290 added_vars_.erase(*i);
10291 }
10292
10293 // Handle the unreachable types
10294 {
10295 // First build the set of non-reachable types from public
10296 // interfaces here
10297 unordered_map<string, type_base*> first_non_reachable_types;
10298 for (auto type : first_->get_sorted_types_not_reachable_from_public_interfaces())
10299 {
10300 if (auto d = is_class_or_union_type(type))
10301 {
10303 if (d->get_is_declaration_only())
10304 continue;
10305 type = is_type(d);
10306 }
10307
10308 if (!is_user_defined_type(type))
10309 continue;
10310 ABG_ASSERT(type);
10311 string repr =
10312 type->get_cached_pretty_representation(/*internal=*/false);
10313 first_non_reachable_types[repr] = type;
10314 }
10315
10316 for (auto type : second_->get_sorted_types_not_reachable_from_public_interfaces())
10317 {
10318 if (auto d = is_class_or_union_type(type))
10319 {
10321 if (d->get_is_declaration_only())
10322 continue;
10323 type = is_type(d);
10324 }
10325
10326 if (!is_user_defined_type(type))
10327 continue;
10328 string repr =
10329 type->get_cached_pretty_representation(/*internal=*/false);
10330 auto it = first_non_reachable_types.find(repr);
10331 if (it == first_non_reachable_types.end())
10332 {
10333 if (!lookup_type(repr, *first_))
10334 {
10335 type_base_sptr t(type, noop_deleter());
10336 added_unreachable_types_[repr] = t;
10337 }
10338 }
10339 else
10340 {
10341 type_base_sptr first(it->second, noop_deleter());
10342 type_base_sptr second(type, noop_deleter());
10343
10344 if (*first != *second)
10345 {
10346 diff_sptr d = compute_diff(first, second, ctxt);
10347 ABG_ASSERT(d->has_changes());
10348 changed_unreachable_types_[repr]= d;
10349 }
10350 first_non_reachable_types.erase(it);
10351 }
10352 }
10353
10354 // At this point, types that remain in first_non_reachable_types
10355 // can be considered deleted.
10356 for (auto e : first_non_reachable_types)
10357 {
10358 type_base_sptr type(e.second, noop_deleter());
10359 string repr =
10360 type->get_cached_pretty_representation(/*internal=*/false);
10361
10362 if (!lookup_type(repr, *second_))
10363 deleted_unreachable_types_[repr] = type;
10364 }
10365
10366 // Handle anonymous enums that got changed. An anonymous enum is
10367 // designated by its flat textual representation. So a change to
10368 // any of its enumerators results in a different enum. That is
10369 // represented by a deletion of the previous anonymous enum, and
10370 // the addition of a new one. For the user however, it's the same
10371 // enum that changed. Let's massage this "added/removed" pattern
10372 // to show what the user expects, namely, a changed anonymous
10373 // enum.
10374 {
10375 std::set<type_base_sptr> deleted_anon_types;
10376 std::set<type_base_sptr> added_anon_types;
10377
10378 for (auto entry : deleted_unreachable_types_)
10379 {
10380 if ((is_enum_type(entry.second)
10381 && is_enum_type(entry.second)->get_is_anonymous())
10382 || (is_class_or_union_type(entry.second)
10383 && is_class_or_union_type(entry.second)->get_is_anonymous()))
10384 deleted_anon_types.insert(entry.second);
10385 }
10386
10387
10388 for (auto entry : added_unreachable_types_)
10389 if ((is_enum_type(entry.second)
10390 && is_enum_type(entry.second)->get_is_anonymous())
10391 || (is_class_or_union_type(entry.second)
10392 && is_class_or_union_type(entry.second)->get_is_anonymous()))
10393 added_anon_types.insert(entry.second);
10394
10395 string_type_base_sptr_map added_anon_types_to_erase;
10396 string_type_base_sptr_map removed_anon_types_to_erase;
10397 enum_type_decl_sptr deleted_enum;
10398 class_or_union_sptr deleted_class;
10399
10400 // Look for deleted anonymous types (enums, unions, structs &
10401 // classes) which have enumerators or data members present in an
10402 // added anonymous type ...
10403 for (auto deleted: deleted_anon_types)
10404 {
10405 deleted_enum = is_enum_type(deleted);
10406 deleted_class = is_class_or_union_type(deleted);
10407
10408 // For enums, look for any enumerator of 'deleted_enum' that
10409 // is also present in an added anonymous enum.
10410 if (deleted_enum)
10411 {
10412 for (auto enr : deleted_enum->get_enumerators())
10413 {
10414 bool this_enum_got_changed = false;
10415 for (auto t : added_anon_types)
10416 {
10417 if (enum_type_decl_sptr added_enum = is_enum_type(t))
10418 if (is_enumerator_present_in_enum(enr, *added_enum))
10419 {
10420 // So the enumerator 'enr' from the
10421 // 'deleted_enum' enum is also present in the
10422 // 'added_enum' enum so we assume that
10423 // 'deleted_enum' and 'added_enum' are the same
10424 // enum that got changed. Let's represent it
10425 // using a diff node.
10426 diff_sptr d = compute_diff(deleted_enum,
10427 added_enum, ctxt);
10428 ABG_ASSERT(d->has_changes());
10429 string repr =
10431 /*internal=*/false);
10432 changed_unreachable_types_[repr]= d;
10433 this_enum_got_changed = true;
10434 string r1 =
10436 /*internal=*/false);
10437 string r2 =
10439 /*internal=*/false);
10440 removed_anon_types_to_erase[r1] = deleted_enum;
10441 added_anon_types_to_erase[r2] = added_enum;
10442 break;
10443 }
10444 }
10445 if (this_enum_got_changed)
10446 break;
10447 }
10448 }
10449 else if (deleted_class)
10450 {
10451 // For unions, structs & classes, look for any data
10452 // member of 'deleted_class' that is also present in an
10453 // added anonymous class.
10454 for (auto dm : deleted_class->get_data_members())
10455 {
10456 bool this_class_got_changed = false;
10457 for (auto klass : added_anon_types)
10458 {
10459 if (class_or_union_sptr added_class =
10461 if (class_or_union_types_of_same_kind(deleted_class,
10462 added_class)
10463 && lookup_data_member(added_class, dm))
10464 {
10465 // So the data member 'dm' from the
10466 // 'deleted_class' class is also present in
10467 // the 'added_class' class so we assume that
10468 // 'deleted_class' and 'added_class' are the
10469 // same anonymous class that got changed.
10470 // Let's represent it using a diff node.
10471 diff_sptr d = compute_diff(is_type(deleted_class),
10472 is_type(added_class),
10473 ctxt);
10474 ABG_ASSERT(d->has_changes());
10475 string repr =
10477 /*internal=*/false);
10478 changed_unreachable_types_[repr]= d;
10479 this_class_got_changed = true;
10480 string r1 =
10482 /*internal=*/false);
10483 string r2 =
10485 /*internal=*/false);
10486 removed_anon_types_to_erase[r1] = deleted_class;
10487 added_anon_types_to_erase[r2] = added_class;
10488 break;
10489 }
10490 }
10491 if (this_class_got_changed)
10492 break;
10493 }
10494 }
10495 }
10496
10497 // Now remove the added/removed anonymous types from their maps,
10498 // as they are now represented as a changed type, not an added
10499 // and removed anonymous type.
10500 for (auto entry : added_anon_types_to_erase)
10501 added_unreachable_types_.erase(entry.first);
10502
10503 for (auto entry : removed_anon_types_to_erase)
10504 deleted_unreachable_types_.erase(entry.first);
10505 }
10506 }
10507}
10508
10509/// This is a sub-routine of ensure_lookup_tables_populated.
10510///
10511/// When there are several /different/ functions with the same linkage
10512/// name that are marked as deleted and several different functions
10513/// with that very same linkage name that are marked as added, then
10514/// this function tries to construct pairs of deleted/added function
10515/// with the same function ID (function pretty representation and
10516/// linkage name). With each pair, a diff is computed and added to
10517/// the changed_fns_map_ data member.
10518///
10519/// If at least of pair of deleted/added function is matched then the
10520/// function returns true. Matched functions are removed from the
10521/// deleted_fns/added_fns sets.
10522///
10523/// @param deleted_fns the set of functions (with the same linkage
10524/// name) that are considered deleted.
10525///
10526/// @param added_fns the set of functions with the same linkage name
10527/// as in @p deleted_fns that are considered added.
10528///
10529/// @return true iff at least of pair of deleted/added function is
10530/// matched. Note that matched functions are removed from deleted_fns
10531/// and added_fns.
10532bool
10534(functions_set_type& deleted_fns, functions_set_type& added_fns)
10535{
10536 bool built_some_diffs = false;
10537
10538 //1 try to see if we can make comparison pairs by looking at
10539 //function IDs
10540 vector<const function_decl*> deleted_fns_to_delete;
10541 vector<const function_decl*> added_fns_to_delete;
10542 for (auto& deleted_fn : deleted_fns)
10543 {
10544 for (auto& added_fn : added_fns)
10545 {
10546 interned_string f_fn_id = deleted_fn->get_id();
10547 interned_string s_fn_id = added_fn->get_id();
10548 if (f_fn_id == s_fn_id)
10549 {
10550 deleted_fns_to_delete.push_back(deleted_fn);
10551 added_fns_to_delete.push_back(added_fn);
10552 function_decl_sptr f(const_cast<function_decl*>(deleted_fn),
10553 noop_deleter());
10554 function_decl_sptr s(const_cast<function_decl*>(added_fn),
10555 noop_deleter());
10556 function_decl_diff_sptr d = compute_diff(f, s, get_context());
10557 changed_fns_map_[f_fn_id] = d;
10558 built_some_diffs = true;
10559 }
10560 }
10561 }
10562
10563
10564 // 2/ TODO: try to see if we can comparison pairs by looking another
10565 // kind of key.
10566
10567
10568 // Erase the functions used to build diff nodes from the input.
10569 for (auto& f : deleted_fns_to_delete)
10570 deleted_fns.erase(f);
10571 for (auto& f : added_fns_to_delete)
10572 added_fns.erase(f);
10573
10574 return built_some_diffs;
10575}
10576
10577/// Test if a change reports about a given @ref function_decl that is
10578/// changed in a certain way is suppressed by a given suppression
10579/// specifiation
10580///
10581/// @param fn the @ref function_decl to consider.
10582///
10583/// @param suppr the suppression specification to consider.
10584///
10585/// @param k the kind of change that happened to @p fn.
10586///
10587/// @param ctxt the context of the current diff.
10588///
10589/// @return true iff the suppression specification @p suppr suppresses
10590/// change reports about function @p fn, if that function changes in
10591/// the way expressed by @p k.
10592static bool
10593function_is_suppressed(const function_decl* fn,
10594 const suppression_sptr suppr,
10596 const diff_context_sptr ctxt)
10597{
10599 if (!fn_suppr)
10600 return false;
10601 return fn_suppr->suppresses_function(fn, k, ctxt);
10602}
10603
10604/// Test if a change reports about a given @ref var_decl that is
10605/// changed in a certain way is suppressed by a given suppression
10606/// specifiation
10607///
10608/// @param fn the @ref var_decl to consider.
10609///
10610/// @param suppr the suppression specification to consider.
10611///
10612/// @param k the kind of change that happened to @p fn.
10613///
10614/// @param ctxt the context of the current diff.
10615///
10616/// @return true iff the suppression specification @p suppr suppresses
10617/// change reports about variable @p fn, if that variable changes in
10618/// the way expressed by @p k.
10619static bool
10620variable_is_suppressed(const var_decl_sptr& var,
10621 const suppression_sptr suppr,
10623 const diff_context_sptr ctxt)
10624{
10626 if (!var_suppr)
10627 return false;
10628 return var_suppr->suppresses_variable(var, k, ctxt);
10629}
10630
10631/// Apply suppression specifications for this corpus diff to the set
10632/// of added/removed functions/variables, as well as to types not
10633/// reachable from global functions/variables.
10634void
10636{
10637 diff_context_sptr ctxt = get_context();
10638
10639 const suppressions_type& suppressions = ctxt->suppressions();
10640 for (suppressions_type::const_iterator i = suppressions.begin();
10641 i != suppressions.end();
10642 ++i)
10643 {
10644 // Added/Deleted functions.
10646 {
10647 // Added functions
10648 for (auto& entry : added_fns_)
10649 if (function_is_suppressed(*entry.second.begin(), fn_suppr,
10651 ctxt))
10652 suppressed_added_fns_[entry.first] = *entry.second.begin();
10653
10654 // Deleted functions.
10655 for (auto& entry : deleted_fns_)
10656 if (function_is_suppressed(*entry.second.begin(), fn_suppr,
10658 ctxt))
10659 suppressed_deleted_fns_[entry.first] = *entry.second.begin();
10660
10661 // Added function symbols not referenced by any debug info
10662 for (string_elf_symbol_map::const_iterator e =
10663 added_unrefed_fn_syms_.begin();
10664 e != added_unrefed_fn_syms_.end();
10665 ++e)
10666 if (fn_suppr->suppresses_function_symbol(e->second,
10668 ctxt))
10669 suppressed_added_unrefed_fn_syms_[e->first] = e->second;
10670
10671 // Removed function symbols not referenced by any debug info
10672 for (string_elf_symbol_map::const_iterator e =
10673 deleted_unrefed_fn_syms_.begin();
10674 e != deleted_unrefed_fn_syms_.end();
10675 ++e)
10676 if (fn_suppr->suppresses_function_symbol(e->second,
10678 ctxt))
10679 suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
10680 }
10681 // Added/Delete virtual member functions changes that might be
10682 // suppressed by a type_suppression that matches the enclosing
10683 // class of the virtual member function.
10684 else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
10685 {
10686 // Added virtual functions
10687 for (auto& entry : added_fns_)
10688 {
10689 const function_decl* f = *entry.second.begin();
10690 if (is_member_function(f)
10692 {
10693 class_decl_sptr c =
10694 is_class_type(is_method_type(f->get_type())->get_class_type());
10695 ABG_ASSERT(c);
10696 if (type_suppr->suppresses_type(c, ctxt))
10697 suppressed_added_fns_[entry.first] = f;
10698 }
10699 }
10700 // Deleted virtual functions
10701 for (auto& entry : deleted_fns_)
10702 {
10703 const function_decl* f = *entry.second.begin();
10704 if (is_member_function(f)
10706 {
10707 class_decl_sptr c =
10708 is_class_type(is_method_type(f->get_type())->get_class_type());
10709 ABG_ASSERT(c);
10710 if (type_suppr->suppresses_type(c, ctxt))
10711 suppressed_deleted_fns_[entry.first] = f;
10712 }
10713 }
10714
10715 // Apply this type suppression to deleted types
10716 // non-reachable from a public interface.
10717 for (string_type_base_sptr_map::const_iterator e =
10718 deleted_unreachable_types_.begin();
10719 e != deleted_unreachable_types_.end();
10720 ++e)
10721 if (type_suppr->suppresses_type(e->second, ctxt))
10722 suppressed_deleted_unreachable_types_[e->first] = e->second;
10723
10724 // Apply this type suppression to added types
10725 // non-reachable from a public interface.
10726 for (string_type_base_sptr_map::const_iterator e =
10727 added_unreachable_types_.begin();
10728 e != added_unreachable_types_.end();
10729 ++e)
10730 if (type_suppr->suppresses_type(e->second, ctxt))
10731 suppressed_added_unreachable_types_[e->first] = e->second;
10732 }
10733 // Added/Deleted variables
10734 else if (variable_suppression_sptr var_suppr =
10736 {
10737 // Added variables
10738 for (string_var_ptr_map::const_iterator e = added_vars_.begin();
10739 e != added_vars_.end();
10740 ++e)
10741 if (variable_is_suppressed(e->second, var_suppr,
10743 ctxt))
10744 suppressed_added_vars_[e->first] = e->second;
10745
10746 //Deleted variables
10747 for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
10748 e != deleted_vars_.end();
10749 ++e)
10750 if (variable_is_suppressed(e->second, var_suppr,
10752 ctxt))
10753 suppressed_deleted_vars_[e->first] = e->second;
10754
10755 // Added variable symbols not referenced by any debug info
10756 for (string_elf_symbol_map::const_iterator e =
10757 added_unrefed_var_syms_.begin();
10758 e != added_unrefed_var_syms_.end();
10759 ++e)
10760 if (var_suppr->suppresses_variable_symbol(e->second,
10762 ctxt))
10763 suppressed_added_unrefed_var_syms_[e->first] = e->second;
10764
10765 // Removed variable symbols not referenced by any debug info
10766 for (string_elf_symbol_map::const_iterator e =
10767 deleted_unrefed_var_syms_.begin();
10768 e != deleted_unrefed_var_syms_.end();
10769 ++e)
10770 if (var_suppr->suppresses_variable_symbol(e->second,
10772 ctxt))
10773 suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
10774 }
10775 }
10776}
10777
10778/// Test if the change reports for a given deleted function have
10779/// been deleted.
10780///
10781/// @param fn the function to consider.
10782///
10783/// @return true iff the change reports for a give given deleted
10784/// function have been deleted.
10785bool
10787{
10788 if (!fn)
10789 return false;
10790
10791 string n = get_function_symbol_id(fn);
10792 string_function_ptr_map::const_iterator i =
10793 suppressed_deleted_fns_.find(n);
10794
10795 return (i != suppressed_deleted_fns_.end());
10796}
10797
10798/// Test if an added type that is unreachable from public interface
10799/// has been suppressed by a suppression specification.
10800///
10801/// @param t the added unreachable type to be considered.
10802///
10803/// @return true iff @p t has been suppressed by a suppression
10804/// specification.
10805bool
10807{
10808 if (!t)
10809 return false;
10810
10811 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10812 string_type_base_sptr_map::const_iterator i =
10813 suppressed_added_unreachable_types_.find(repr);
10814 if (i == suppressed_added_unreachable_types_.end())
10815 return false;
10816
10817 return true;
10818}
10819
10820/// Test if a deleted type that is unreachable from public interface
10821/// has been suppressed by a suppression specification.
10822///
10823/// @param t the deleted unreachable type to be considered.
10824///
10825/// @return true iff @p t has been suppressed by a suppression
10826/// specification.
10827bool
10829{
10830 if (!t)
10831 return false;
10832
10833 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10834 string_type_base_sptr_map::const_iterator i =
10835 suppressed_deleted_unreachable_types_.find(repr);
10836 if (i == suppressed_deleted_unreachable_types_.end())
10837 return false;
10838
10839 return true;
10840}
10841
10842/// Test if the change reports for a give given added function has
10843/// been deleted.
10844///
10845/// @param fn the function to consider.
10846///
10847/// @return true iff the change reports for a give given added
10848/// function has been deleted.
10849bool
10851{
10852 if (!fn)
10853 return false;
10854
10855 string n = get_function_symbol_id(fn);
10856 string_function_ptr_map::const_iterator i =
10857 suppressed_added_fns_.find(n);
10858
10859 return (i != suppressed_added_fns_.end());
10860}
10861
10862/// Test if the change reports for a give given deleted variable has
10863/// been deleted.
10864///
10865/// @param var the variable to consider.
10866///
10867/// @return true iff the change reports for a give given deleted
10868/// variable has been deleted.
10869bool
10871{
10872 if (!var)
10873 return false;
10874
10875 string n = var->get_id();
10876 string_var_ptr_map::const_iterator i =
10877 suppressed_deleted_vars_.find(n);
10878
10879 return (i != suppressed_deleted_vars_.end());
10880}
10881
10882/// Test if the change reports for a given added variable have been
10883/// suppressed.
10884///
10885/// @param var the variable to consider.
10886///
10887/// @return true iff the change reports for a given deleted
10888/// variable has been deleted.
10889bool
10891{
10892 if (!var)
10893 return false;
10894
10895 string n = var->get_id();
10896 string_var_ptr_map::const_iterator i =
10897 suppressed_added_vars_.find(n);
10898
10899 return (i != suppressed_added_vars_.end());
10900}
10901
10902/// Test if the change reports for a given deleted function symbol
10903/// (that is not referenced by any debug info) has been suppressed.
10904///
10905/// @param var the function to consider.
10906///
10907/// @return true iff the change reports for a given deleted function
10908/// symbol has been suppressed.
10909bool
10911{
10912 if (!s)
10913 return false;
10914
10915 string_elf_symbol_map::const_iterator i =
10916 suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10917
10918 return (i != suppressed_deleted_unrefed_fn_syms_.end());
10919}
10920
10921/// Test if the change reports for a given added function symbol
10922/// (that is not referenced by any debug info) has been suppressed.
10923///
10924/// @param var the function to consider.
10925///
10926/// @return true iff the change reports for a given added function
10927/// symbol has been suppressed.
10928bool
10930{
10931 if (!s)
10932 return false;
10933
10934 string_elf_symbol_map::const_iterator i =
10935 suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10936
10937 return (i != suppressed_added_unrefed_fn_syms_.end());
10938}
10939
10940/// Test if the change reports for a given deleted variable symbol
10941/// (that is not referenced by any debug info) has been suppressed.
10942///
10943/// @param var the variable to consider.
10944///
10945/// @return true iff the change reports for a given deleted variable
10946/// symbol has been suppressed.
10947bool
10949{
10950 if (!s)
10951 return false;
10952
10953 string_elf_symbol_map::const_iterator i =
10954 suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10955
10956 return (i != suppressed_deleted_unrefed_var_syms_.end());
10957}
10958
10959/// Test if the change reports for a given added variable symbol
10960/// (that is not referenced by any debug info) has been suppressed.
10961///
10962/// @param var the variable to consider.
10963///
10964/// @return true iff the change reports for a given added variable
10965/// symbol has been suppressed.
10966bool
10968{
10969 if (!s)
10970 return false;
10971
10972 string_elf_symbol_map::const_iterator i =
10973 suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10974
10975 return (i != suppressed_added_unrefed_var_syms_.end());
10976}
10977
10978#ifdef do_count_diff_map_changes
10979#undef do_count_diff_map_changes
10980#endif
10981#define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10982 { \
10983 string_diff_ptr_map::const_iterator i; \
10984 for (i = diff_map.begin(); \
10985 i != diff_map.end(); \
10986 ++i) \
10987 { \
10988 if (const var_diff* d = is_var_diff(i->second)) \
10989 if (is_data_member(d->first_var())) \
10990 continue; \
10991 \
10992 if (i->second->has_local_changes()) \
10993 ++n_changes; \
10994 if (!i->second->get_canonical_diff()->to_be_reported()) \
10995 ++n_filtered; \
10996 } \
10997 }
10998
10999/// Count the number of leaf changes as well as the number of the
11000/// changes that have been filtered out.
11001///
11002/// @param num_changes out parameter. This is set to the total number
11003/// of leaf changes.
11004///
11005/// @param num_filtered out parameter. This is set to the number of
11006/// leaf changes that have been filtered out.
11007void
11008corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
11009{
11010 count_leaf_type_changes(num_changes, num_filtered);
11011
11012 // Now count the non-type changes.
11013 do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
11014 num_changes, num_filtered);
11015 do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
11016 num_changes, num_filtered);
11017}
11018
11019/// Count the number of leaf *type* changes as well as the number of
11020/// the leaf type changes that have been filtered out.
11021///
11022/// @param num_changes out parameter. This is set to the total number
11023/// of leaf type changes.
11024///
11025/// @param num_filtered out parameter. This is set to the number of
11026/// leaf type changes that have been filtered out.
11027void
11029 size_t &num_filtered)
11030{
11031 do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
11032 num_changes, num_filtered);
11033 do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
11034 num_changes, num_filtered);
11035 do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
11036 num_changes, num_filtered);
11037 do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
11038 num_changes, num_filtered);
11039 do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
11040 num_changes, num_filtered);
11041 do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
11042 num_changes, num_filtered);
11043 do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
11044 num_changes, num_filtered);
11045 do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
11046 num_changes, num_filtered);
11047 do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
11048 num_changes, num_filtered);
11049}
11050
11051/// Count the number of types not reachable from the interface (i.e,
11052/// not reachable from global functions or variables).
11053///
11054/// @param num_added this is set to the number of added types not
11055/// reachable from the interface.
11056///
11057/// @param num_deleted this is set to the number of deleted types not
11058/// reachable from the interface.
11059///
11060/// @param num_changed this is set to the number of changed types not
11061/// reachable from the interface.
11062///
11063/// @param num_filtered_added this is set to the number of added types
11064/// not reachable from the interface and that have been filtered out
11065/// by suppression specifications.
11066///
11067/// @param num_filtered_deleted this is set to the number of deleted
11068/// types not reachable from the interface and that have been filtered
11069/// out by suppression specifications.
11070///
11071/// @param num_filtered_changed this is set to the number of changed
11072/// types not reachable from the interface and that have been filtered
11073/// out by suppression specifications.
11074void
11076 size_t &num_deleted,
11077 size_t &num_changed,
11078 size_t &num_filtered_added,
11079 size_t &num_filtered_deleted,
11080 size_t &num_filtered_changed)
11081{
11082 num_added = added_unreachable_types_.size();
11083 num_deleted = deleted_unreachable_types_.size();
11084 num_changed = changed_unreachable_types_.size();
11085 num_filtered_added = suppressed_added_unreachable_types_.size();
11086 num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
11087
11088 std::map<string, type_base*> counted_changed_non_reachable_types;
11089 string repr;
11090 type_base_sptr t;
11091
11092 for (auto d : changed_unreachable_types_sorted())
11093 {
11094 t = is_type(d->first_subject());
11095 repr = t->get_pretty_representation();
11096 if (counted_changed_non_reachable_types.find(repr)
11097 != counted_changed_non_reachable_types.end())
11098 continue;
11099
11100 if (d->is_filtered_out())
11101 {
11102 ++num_filtered_changed;
11103 counted_changed_non_reachable_types[repr] = t.get();
11104 }
11105 }
11106}
11107
11108/// Get the map of diff nodes representing changed unreachable types.
11109///
11110/// @return the map of diff nodes representing changed unreachable
11111/// types.
11114{return changed_unreachable_types_;}
11115
11116/// Get the sorted vector of diff nodes representing changed
11117/// unreachable types.
11118///
11119/// Upon the first invocation of this method, if the vector is empty,
11120/// this function gets the diff nodes representing changed
11121/// unreachable, sort them, and return the sorted vector.
11122///
11123/// @return the sorted vector of diff nodes representing changed
11124/// unreachable types.
11125const vector<diff_sptr>&
11127{
11128if (changed_unreachable_types_sorted_.empty())
11129 if (!changed_unreachable_types_.empty())
11130 sort_string_diff_sptr_map(changed_unreachable_types_,
11131 changed_unreachable_types_sorted_);
11132
11133 return changed_unreachable_types_sorted_;
11134}
11135
11136/// Apply the diff change categorization filters to the current ABI
11137/// corpus. As a result, the diff node are all categorized.
11138void
11140{
11141 diff_context_sptr ctxt = get_context();
11142
11144 if (ctxt->perform_change_categorization())
11145 {
11146 if (get_context()->do_log())
11147 {
11148 std::cerr << "in corpus_diff::priv::maybe_perform_change_categorization:"
11149 << "applying filters to "
11150 << changed_fns_.size()
11151 << " changed fns ...\n";
11152 t.start();
11153 }
11154
11155 // Walk the changed function diff nodes to apply the categorization
11156 // filters.
11158 for (function_decl_diff_sptrs_type::const_iterator i =
11159 changed_fns_.begin();
11160 i != changed_fns_.end();
11161 ++i)
11162 {
11163 diff_sptr diff = *i;
11164 ctxt->maybe_apply_filters(diff);
11165 }
11166
11167 if (get_context()->do_log())
11168 {
11169 t.stop();
11170 std::cerr << "in corpus_diff::priv::perform_change_categorization():"
11171 << "filters to changed fn applied in:" << t << "\n";
11172
11173 std::cerr << "in corpus_diff::priv::perform_change_categorization:"
11174 << "applying filters to "
11175 << sorted_changed_vars_.size()
11176 << " changed vars ...\n";
11177 t.start();
11178 }
11179
11180 // Walk the changed variable diff nodes to apply the categorization
11181 // filters.
11182 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11183 i != sorted_changed_vars_.end();
11184 ++i)
11185 {
11186 diff_sptr diff = *i;
11187 ctxt->maybe_apply_filters(diff);
11188 }
11189
11190 if (get_context()->do_log())
11191 {
11192 t.stop();
11193 std::cerr << "in corpus_diff::priv::perform_change_categorization:"
11194 << "filters to changed vars applied in:" << t << "\n";
11195
11196 unsigned n = changed_unreachable_types_sorted().size();
11197
11198 std::cerr << "in corpus_diff::priv::perform_change_categorization:"
11199 << "applying filters to "
11200 << n
11201 <<" unreachable types ...\n";
11202 t.start();
11203 }
11204
11205 // walk the changed unreachable types to apply categorization
11206 // filters
11208 ctxt->maybe_apply_filters(diff);
11209
11210 if (get_context()->do_log())
11211 {
11212 t.stop();
11213 unsigned n = changed_unreachable_types_sorted().size();
11214 std::cerr << "in corpus_diff::priv::perform_change_categorization:"
11215 << "applied filters to " << n << " unreachable types in "
11216 << t << "\n";
11217 }
11218 }
11219}
11220
11221/// If diff_context::perform_change_categorization() is true, then
11222/// perform the redundancy categorization of the diff nodes of the
11223/// current ABI corpus.
11224void
11226{
11227 diff_context_sptr ctxt = get_context();
11229 if (ctxt->perform_change_categorization())
11230 {
11231 if (get_context()->do_log())
11232 {
11233 std::cerr << "in corpus_diff::priv::perform_redundant_node_categorization:"
11234 << "filters to unreachable types applied in:" << t << "\n";
11235
11236 std::cerr << "in corpus_diff::priv::perform_redundant_node_categorization:"
11237 << "categorizing redundant changed sub nodes ...\n";
11238 t.start();
11239 }
11240
11241 categorize_redundant_changed_sub_nodes();
11242
11243 if (get_context()->do_log())
11244 {
11245 t.stop();
11246 std::cerr << "in corpus_diff::priv::perform_redundant_node_categorization:"
11247 << "redundant changed sub nodes categorized in:" << t << "\n";
11248
11249 std::cerr << "in corpus_diff::priv::perform_redundant_node_categorization:"
11250 << "count changed fns ...\n";
11251 t.start();
11252 }
11253 }
11254}
11255
11256/// Compute the diff stats.
11257///
11258/// To know the number of functions that got filtered out, this
11259/// function applies the categorizing filters to the diff sub-trees of
11260/// each function changes diff, prior to calculating the stats.
11261///
11262/// @param num_removed the number of removed functions.
11263///
11264/// @param num_added the number of added functions.
11265///
11266/// @param num_changed the number of changed functions.
11267///
11268/// @param num_filtered_out the number of changed functions that are
11269/// got filtered out from the report
11270void
11272 diff_stats& stat)
11273{
11275 maybe_perform_change_categorization();
11276 maybe_perform_redundant_node_categorization();
11277
11278 get_context()->perform_change_categorization(false);
11279
11280 stat.num_func_removed(deleted_fns_.size());
11281 stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
11282 stat.num_func_added(added_fns_.size());
11283 stat.num_added_func_filtered_out(suppressed_added_fns_.size());
11284 stat.num_func_changed(changed_fns_map_.size());
11285
11286 stat.num_vars_removed(deleted_vars_.size());
11287 stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
11288 stat.num_vars_added(added_vars_.size());
11289 stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
11290 stat.num_vars_changed(changed_vars_map_.size());
11291
11292 diff_context_sptr ctxt = get_context();
11293
11294 // Walk the changed function diff nodes to count the number of
11295 // filtered-out functions and the number of functions with virtual
11296 // offset changes.
11297 for (function_decl_diff_sptrs_type::const_iterator i =
11298 changed_fns_.begin();
11299 i != changed_fns_.end();
11300 ++i)
11301 {
11302 bool incompatible_change = false;
11303 if ((*i)->is_filtered_out())
11304 {
11306 (stat.num_changed_func_filtered_out() + 1);
11307
11308 if ((*i)->has_local_changes())
11311 }
11312
11313 // Now let's detect functions with incompatible changes.
11314 if (!(*i)->is_categorized_as_suppressed())
11315 {
11316 // Note that a filtered-out function diff (because of
11317 // redundancy) can still carry an incompatible change. In
11318 // that case, the diff will later be removed from the
11319 // account of filtered diff nodes.
11320 //
11321 // Also note that such a filtered-out function was *NOT*
11322 // suppressed by a user-provided suppression specification.
11323
11325 {
11328 incompatible_change = true;
11329 }
11330
11331 // Are any of the local changes of the function_diff harmful?
11332 // If yes, then set stat.num_func_with_local_harmful_changes()
11333 // and stat.num_var_with_local_harmful_changes().
11335 {
11338 incompatible_change = true;
11339 }
11340 }
11341
11342 if ((*i)->has_local_changes())
11344 (stat.num_leaf_func_changes() + 1);
11345
11346 if (incompatible_change)
11347 {
11348 incompatible_changed_fns_.push_back(*i);
11351
11352 if ((*i)->has_local_changes())
11353 // The function is a leaf node.
11356
11357 if ((*i)->is_filtered_out())
11358 {
11359 // If the incompatible change was filtered-out (possibly
11360 // b/c of redundancy) consider it as not being filtered
11361 // out anymore.
11363 (stat.num_changed_func_filtered_out() - 1);
11364
11365 if ((*i)->has_local_changes())
11368 }
11369 }
11370 }
11371
11373 if (get_context()->do_log())
11374 {
11375 std::cerr << "in apply_filters_and_compute_diff_stats:"
11376 << "changed fn counted in:" << t << "\n";
11377
11378 std::cerr << "in apply_filters_and_compute_diff_stats:"
11379 << "count changed vars ...\n";
11380 t.start();
11381 }
11382
11383 // Similarly to function diff nodes above, walk the changed
11384 // variables diff nodes to count the number of filtered-out,
11385 // suppressed and incompatible variable diff nodes.
11386 for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
11387 i != sorted_changed_vars_.end();
11388 ++i)
11389 {
11390 bool incompatible_change = false;
11391 if ((*i)->is_filtered_out())
11392 {
11394 (stat.num_changed_vars_filtered_out() + 1);
11395
11396 if ((*i)->has_local_changes())
11399 }
11400
11401 if (!(*i)->is_categorized_as_suppressed())
11402 {
11404 {
11405 incompatible_change = true;
11406 incompatible_changed_vars_.push_back(*i);
11411
11412 if ((*i)->is_filtered_out())
11413 {
11415 (stat.num_changed_vars_filtered_out() - 1);
11416
11417 if ((*i)->has_local_changes())
11420 }
11421 }
11422 }
11423
11424 if ((*i)->has_local_changes())
11425 {
11427 (stat.num_leaf_var_changes() + 1);
11428
11429 if (incompatible_change)
11432 }
11433 }
11434
11435 if (get_context()->do_log())
11436 {
11437 t.stop();
11438 std::cerr << "in apply_filters_and_compute_diff_stats:"
11439 << "changed vars counted in:" << t << "\n";
11440
11441 std::cerr << "in apply_filters_and_compute_diff_stats:"
11442 << "count leaf changed types ...\n";
11443 t.start();
11444 }
11445
11446 stat.num_func_syms_added(added_unrefed_fn_syms_.size());
11447 stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
11448 stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
11449 stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
11450 stat.num_var_syms_added(added_unrefed_var_syms_.size());
11451 stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
11452 stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
11453 stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
11454
11455 // Walk the general leaf type diff nodes to count them
11456 {
11457 size_t num_type_changes = 0, num_type_filtered = 0;
11458 count_leaf_type_changes(num_type_changes, num_type_filtered);
11459
11460 stat.num_leaf_type_changes(num_type_changes);
11461 stat.num_leaf_type_changes_filtered_out(num_type_filtered);
11462 }
11463
11464 if (get_context()->do_log())
11465 {
11466 t.stop();
11467 std::cerr << "in apply_filters_and_compute_diff_stats:"
11468 << "changed leaf types counted in:" << t << "\n";
11469
11470 std::cerr << "in apply_filters_and_compute_diff_stats:"
11471 << "count leaf changed artefacts ...\n";
11472 t.start();
11473 }
11474
11475 // Walk the general leaf artefacts diff nodes to count them
11476 {
11477 size_t num_changes = 0, num_filtered = 0;
11478 count_leaf_changes(num_changes, num_filtered);
11479
11480 stat.num_leaf_changes(num_changes);
11481 stat.num_leaf_changes_filtered_out(num_filtered);
11482 }
11483
11484 if (get_context()->do_log())
11485 {
11486 t.stop();
11487 std::cerr << "in apply_filters_and_compute_diff_stats:"
11488 << "changed leaf artefacts counted in:" << t << "\n";
11489
11490 std::cerr << "in apply_filters_and_compute_diff_stats:"
11491 << "count unreachable types ...\n";
11492 t.start();
11493 }
11494
11495 // Walk the unreachable types to count them
11496 {
11497 size_t num_added_unreachable_types = 0,
11498 num_changed_unreachable_types = 0,
11499 num_deleted_unreachable_types = 0,
11500 num_added_unreachable_types_filtered = 0,
11501 num_changed_unreachable_types_filtered = 0,
11502 num_deleted_unreachable_types_filtered = 0;
11503
11504 count_unreachable_types(num_added_unreachable_types,
11505 num_deleted_unreachable_types,
11506 num_changed_unreachable_types,
11507 num_added_unreachable_types_filtered,
11508 num_deleted_unreachable_types_filtered,
11509 num_changed_unreachable_types_filtered);
11510
11511 if (get_context()->do_log())
11512 {
11513 t.stop();
11514 std::cerr << "in apply_filters_and_compute_diff_stats:"
11515 << "unreachable types counted in:" << t << "\n";
11516 }
11517
11518 stat.num_added_unreachable_types(num_added_unreachable_types);
11519 stat.num_removed_unreachable_types(num_deleted_unreachable_types);
11520 stat.num_changed_unreachable_types(num_changed_unreachable_types);
11522 (num_added_unreachable_types_filtered);
11524 (num_deleted_unreachable_types_filtered);
11526 (num_changed_unreachable_types_filtered);
11527 }
11528}
11529
11530/// Emit the summary of the functions & variables that got
11531/// removed/changed/added.
11532///
11533/// TODO: This should be handled by the reporters, just like what is
11534/// done for reporter_base::diff_to_be_reported.
11535///
11536/// @param out the output stream to emit the stats to.
11537///
11538/// @param indent the indentation string to use in the summary.
11539void
11541 ostream& out,
11542 const string& indent)
11543{
11544 /// Report added/removed/changed functions.
11545 size_t net_num_leaf_changes =
11547 s.net_num_func_added() +
11550 s.net_num_vars_added() +
11557
11558 if (!sonames_equal_)
11559 out << indent << "ELF SONAME changed\n";
11560
11561 if (!architectures_equal_)
11562 out << indent << "ELF architecture changed\n";
11563
11564 diff_context_sptr ctxt = get_context();
11565
11566 if (ctxt->show_leaf_changes_only())
11567 {
11568 out << "Leaf changes summary: ";
11569 out << net_num_leaf_changes << " artifact";
11570 if (net_num_leaf_changes > 1)
11571 out << "s";
11572 out << " changed";
11573
11574 if (size_t num_filtered = s.num_leaf_changes_filtered_out())
11575 out << " (" << num_filtered << " filtered out)";
11576 out << "\n";
11577
11578 out << indent << "Changed leaf types summary: "
11581 out << " (" << s.num_leaf_type_changes_filtered_out()
11582 << " filtered out)";
11583 out << " leaf type";
11584 if (s.num_leaf_type_changes() > 1)
11585 out << "s";
11586 out << " changed\n";
11587
11588 // function changes summary
11589 out << indent << "Removed/Changed/Added functions summary: ";
11590 out << s.net_num_func_removed() << " Removed";
11592 out << " ("
11594 << " filtered out)";
11595 out << ", ";
11596
11597 out << s.net_num_leaf_func_changes() << " Changed";
11599 out << " ("
11601 << " filtered out)";
11602 out << ", ";
11603
11604 out << s.net_num_func_added()<< " Added ";
11605 if (s.net_num_func_added() <= 1)
11606 out << "function";
11607 else
11608 out << "functions";
11610 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11611 out << "\n";
11612
11613 // variables changes summary
11614 out << indent << "Removed/Changed/Added variables summary: ";
11615 out << s.net_num_vars_removed() << " Removed";
11617 out << " (" << s.num_removed_vars_filtered_out()
11618 << " filtered out)";
11619 out << ", ";
11620
11621 out << s.net_num_leaf_var_changes() << " Changed";
11623 out << " ("
11625 << " filtered out)";
11626 out << ", ";
11627
11628 out << s.net_num_vars_added() << " Added ";
11629 if (s.net_num_vars_added() <= 1)
11630 out << "variable";
11631 else
11632 out << "variables";
11634 out << " (" << s.num_added_vars_filtered_out()
11635 << " filtered out)";
11636 out << "\n";
11637 }
11638 else // if (ctxt->show_leaf_changes_only())
11639 {
11640 size_t total_nb_function_changes = s.num_func_removed()
11641 + s.num_func_changed() + s.num_func_added();
11642
11643 // function changes summary
11644 out << indent << "Functions changes summary: ";
11645 out << s.net_num_func_removed() << " Removed";
11647 out << " ("
11649 << " filtered out)";
11650 out << ", ";
11651
11652 out << s.net_num_func_changed() << " Changed";
11654 out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
11655 out << ", ";
11656
11657 out << s.net_num_func_added() << " Added";
11659 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11660 if (total_nb_function_changes <= 1)
11661 out << " function";
11662 else
11663 out << " functions";
11664 out << "\n";
11665
11666 // variables changes summary
11667 size_t total_nb_variable_changes = s.num_vars_removed()
11668 + s.num_vars_changed() + s.num_vars_added();
11669
11670 out << indent << "Variables changes summary: ";
11671 out << s.net_num_vars_removed() << " Removed";
11673 out << " (" << s.num_removed_vars_filtered_out()
11674 << " filtered out)";
11675 out << ", ";
11676
11677 out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
11679 out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
11680 out << ", ";
11681
11682 out << s.net_num_vars_added() << " Added";
11684 out << " (" << s.num_added_vars_filtered_out()
11685 << " filtered out)";
11686 if (total_nb_variable_changes <= 1)
11687 out << " variable";
11688 else
11689 out << " variables";
11690 out << "\n";
11691 }
11692
11693 // Show statistics about types not reachable from global
11694 // functions/variables.
11695 if (ctxt->show_unreachable_types())
11696 {
11697 size_t total_nb_unreachable_type_changes =
11701
11702 // Show summary of unreachable types
11703 out << indent << "Unreachable types summary: "
11705 << " removed";
11708 << " filtered out)";
11709 out << ", ";
11710
11712 << " changed";
11715 << " filtered out)";
11716 out << ", ";
11717
11719 << " added";
11722 << " filtered out)";
11723 if (total_nb_unreachable_type_changes <= 1)
11724 out << " type";
11725 else
11726 out << " types";
11727 out << "\n";
11728 }
11729
11730 if (ctxt->show_symbols_unreferenced_by_debug_info()
11731 && (s.num_func_syms_removed()
11732 || s.num_func_syms_added()
11734 || s.num_var_syms_added()))
11735 {
11736 // function symbols changes summary.
11737
11738 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11739 && s.num_func_syms_removed() == 0
11740 && s.num_func_syms_added() != 0)
11741 // If the only unreferenced function symbol change is function
11742 // syms that got added, but we were forbidden to show function
11743 // syms being added, do nothing.
11744 ;
11745 else
11746 {
11747 out << indent
11748 << "Function symbols changes summary: "
11749 << s.net_num_removed_func_syms() << " Removed";
11751 out << " (" << s.num_removed_func_syms_filtered_out()
11752 << " filtered out)";
11753 out << ", ";
11754 out << s.net_num_added_func_syms() << " Added";
11756 out << " (" << s.num_added_func_syms_filtered_out()
11757 << " filtered out)";
11758 out << " function symbol";
11760 out << "s";
11761 out << " not referenced by debug info\n";
11762 }
11763
11764 // variable symbol changes summary.
11765
11766 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11767 && s.num_var_syms_removed() == 0
11768 && s.num_var_syms_added() != 0)
11769 // If the only unreferenced variable symbol change is variable
11770 // syms that got added, but we were forbidden to show variable
11771 // syms being added, do nothing.
11772 ;
11773 else
11774 {
11775 out << indent
11776 << "Variable symbols changes summary: "
11777 << s.net_num_removed_var_syms() << " Removed";
11779 out << " (" << s.num_removed_var_syms_filtered_out()
11780 << " filtered out)";
11781 out << ", ";
11782 out << s.net_num_added_var_syms() << " Added";
11784 out << " (" << s.num_added_var_syms_filtered_out()
11785 << " filtered out)";
11786 out << " variable symbol";
11787 if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
11788 out << "s";
11789 out << " not referenced by debug info\n";
11790 }
11791 }
11792}
11793/// Walk the changed functions and variables diff nodes to categorize
11794/// redundant nodes.
11795void
11797{
11799
11800 diff_context_sptr ctxt = get_context();
11801
11802 ctxt->forget_visited_diffs();
11803 for (function_decl_diff_sptrs_type::const_iterator i =
11804 changed_fns_.begin();
11805 i!= changed_fns_.end();
11806 ++i)
11807 {
11808 diff = *i;
11810 }
11811
11812 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11813 i!= sorted_changed_vars_.end();
11814 ++i)
11815 {
11816 diff_sptr diff = *i;
11818 }
11819
11820 for (diff_sptrs_type::const_iterator i =
11823 ++i)
11824 {
11825 diff_sptr diff = *i;
11827 }
11828}
11829
11830
11831/// Walk the changed functions and variables diff nodes and clear the
11832/// redundancy categorization they might carry.
11833void
11835{
11837 for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
11838 i!= changed_fns_.end();
11839 ++i)
11840 {
11841 diff = *i;
11843 }
11844
11845 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11846 i!= sorted_changed_vars_.end();
11847 ++i)
11848 {
11849 diff = *i;
11851 }
11852}
11853
11854/// If the user asked to dump the diff tree node (for changed
11855/// variables and functions) on the error output stream, then just do
11856/// that.
11857///
11858/// This function is used for debugging purposes.
11859void
11861{
11862 diff_context_sptr ctxt = get_context();
11863
11864 if (!ctxt->dump_diff_tree()
11865 || ctxt->error_output_stream() == 0)
11866 return;
11867
11868 if (!changed_fns_.empty())
11869 {
11870 *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
11871 for (function_decl_diff_sptrs_type::const_iterator i =
11872 changed_fns_.begin();
11873 i != changed_fns_.end();
11874 ++i)
11875 {
11876 diff_sptr d = *i;
11877 print_diff_tree(d, *ctxt->error_output_stream());
11878 }
11879 }
11880
11881 if (!sorted_changed_vars_.empty())
11882 {
11883 *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
11884 for (var_diff_sptrs_type::const_iterator i =
11885 sorted_changed_vars_.begin();
11886 i != sorted_changed_vars_.end();
11887 ++i)
11888 {
11889 diff_sptr d = *i;
11890 print_diff_tree(d, *ctxt->error_output_stream());
11891 }
11892 }
11893
11894 if (!changed_unreachable_types_sorted().empty())
11895 {
11896 *ctxt->error_output_stream() << "\nchanged unreachable "
11897 "types diff tree: \n\n";
11898 for (vector<diff_sptr>::const_iterator i =
11901 ++i)
11902 {
11903 diff_sptr d = *i;
11904 print_diff_tree(d, *ctxt->error_output_stream());
11905 }
11906 }
11907}
11908
11909/// Populate the vector of children node of the @ref corpus_diff type.
11910///
11911/// The children node can then later be retrieved using
11912/// corpus_diff::children_node().
11913void
11915{
11916 for (function_decl_diff_sptrs_type::const_iterator i =
11917 changed_functions_sorted().begin();
11918 i != changed_functions_sorted().end();
11919 ++i)
11920 if (diff_sptr d = *i)
11922}
11923
11924/// Constructor for @ref corpus_diff.
11925///
11926/// @param first the first corpus of the diff.
11927///
11928/// @param second the second corpus of the diff.
11929///
11930/// @param ctxt the diff context to use. Note that this context
11931/// object must stay alive at least during the life time of the
11932/// current instance of @ref corpus_diff. Otherwise memory corruption
11933/// issues occur.
11935 corpus_sptr second,
11936 diff_context_sptr ctxt)
11937 : priv_(new priv(first, second, ctxt))
11938{}
11939
11940corpus_diff::~corpus_diff() = default;
11941
11942/// Finish building the current instance of @ref corpus_diff.
11943void
11945{
11946 if (priv_->finished_)
11947 return;
11949 priv_->finished_ = true;
11950}
11951
11952/// Test if logging was requested.
11953///
11954/// @return true iff logging was requested.
11955bool
11957{return context()->do_log();}
11958
11959/// Request logging, or not.
11960///
11961/// @param f true iff logging is requested.
11962void
11964{context()->do_log(f);}
11965
11966/// @return the first corpus of the diff.
11967corpus_sptr
11969{return priv_->first_;}
11970
11971/// @return the second corpus of the diff.
11972corpus_sptr
11974{return priv_->second_;}
11975
11976/// @return the children nodes of the current instance of corpus_diff.
11977const vector<diff*>&
11979{return priv_->children_;}
11980
11981/// Append a new child node to the vector of children nodes for the
11982/// current instance of @ref corpus_diff node.
11983///
11984/// Note that the vector of children nodes for the current instance of
11985/// @ref corpus_diff node must remain sorted, using
11986/// diff_less_than_functor.
11987///
11988/// @param d the new child node. Note that the life time of the
11989/// object held by @p d will thus equal the life time of the current
11990/// instance of @ref corpus_diff.
11991void
11993{
11994 ABG_ASSERT(d);
11995
11997 bool inserted = false;
11998 for (vector<diff*>::iterator i = priv_->children_.begin();
11999 i != priv_->children_.end();
12000 ++i)
12001 // Look for the point where to insert the diff child node.
12002 if (!is_less_than(d.get(), *i))
12003 {
12004 context()->keep_diff_alive(d);
12005 priv_->children_.insert(i, d.get());
12006 // As we have just inserted 'd' into the vector, the iterator
12007 // 'i' is invalidated. We must *NOT* use it anymore.
12008 inserted = true;
12009 break;
12010 }
12011
12012 if (!inserted)
12013 {
12014 context()->keep_diff_alive(d);
12015 // We didn't insert anything to the vector, presumably b/c it was
12016 // empty or had one element that was "less than" 'd'. We can thus
12017 // just append 'd' to the end of the vector.
12018 priv_->children_.push_back(d.get());
12019 }
12020}
12021
12022/// Test if the soname of the underlying corpus has changed.
12023///
12024/// @return true iff the soname has changed.
12025bool
12027{return !priv_->sonames_equal_;}
12028
12029/// Test if the architecture of the underlying corpus has changed.
12030///
12031/// @return true iff the architecture has changed.
12032bool
12034{return !priv_->architectures_equal_;}
12035
12036/// Getter for the deleted functions of the diff.
12037///
12038/// @return the the deleted functions of the diff.
12041{return priv_->deleted_fns_;}
12042
12043/// Getter for the added functions of the diff.
12044///
12045/// @return the added functions of the diff.
12048{return priv_->added_fns_;}
12049
12050/// Getter for the functions which signature didn't change, but which
12051/// do have some indirect changes in their parms.
12052///
12053/// @return a non-sorted map of functions which signature didn't
12054/// change, but which do have some indirect changes in their parms.
12055/// The key of the map is a unique identifier for the function; it's
12056/// usually made of the name and version of the underlying ELF symbol
12057/// of the function for corpora that were built from ELF files.
12060{return priv_->changed_fns_map_;}
12061
12062/// Getter for a sorted vector of functions which signature didn't
12063/// change, but which do have some indirect changes in their parms.
12064///
12065/// @return a sorted vector of functions which signature didn't
12066/// change, but which do have some indirect changes in their parms.
12069{return priv_->changed_fns_;}
12070
12071/// Getter of the set of diff nodes representing incompatibly changed
12072/// functions
12073///
12074/// @return the set of diff nodes representing incompatibly changed
12075/// functions
12078{return priv_->incompatible_changed_fns_;}
12079
12080/// Getter of the set of diff nodes representing incompatibly changed
12081/// functions
12082///
12083/// @return the set of diff nodes representing incompatibly changed
12084/// functions
12087{return priv_->incompatible_changed_fns_;}
12088
12089/// Getter for the variables that got deleted from the first subject
12090/// of the diff.
12091///
12092/// @return the map of deleted variable.
12093const string_var_ptr_map&
12095{return priv_->deleted_vars_;}
12096
12097/// Getter for the added variables of the diff.
12098///
12099/// @return the map of added variable.
12100const string_var_ptr_map&
12102{return priv_->added_vars_;}
12103
12104/// Getter for the non-sorted map of variables which signature didn't
12105/// change but which do have some indirect changes in some sub-types.
12106///
12107/// @return the non-sorted map of changed variables.
12110{return priv_->changed_vars_map_;}
12111
12112/// Getter for the sorted vector of variables which signature didn't
12113/// change but which do have some indirect changes in some sub-types.
12114///
12115/// @return a sorted vector of changed variables.
12118{return priv_->sorted_changed_vars_;}
12119
12120/// Getter of the set of diff nodes representing incompatibly changed
12121/// global variables.
12122///
12123/// @return the set of diff nodes representing incompatibly changed
12124/// global variables.
12127{return priv_->incompatible_changed_vars_;}
12128
12129/// Getter of the set of diff nodes representing incompatibly changed
12130/// global variables.
12131///
12132/// @return the set of diff nodes representing incompatibly changed
12133/// global variables.
12136{return priv_->incompatible_changed_vars_;}
12137
12138/// Getter for function symbols not referenced by any debug info and
12139/// that got deleted.
12140///
12141/// @return a map of elf function symbols not referenced by any debug
12142/// info and that got deleted.
12145{return priv_->deleted_unrefed_fn_syms_;}
12146
12147/// Getter for function symbols not referenced by any debug info and
12148/// that got added.
12149///
12150/// @return a map of elf function symbols not referenced by any debug
12151/// info and that got added.
12154{return priv_->added_unrefed_fn_syms_;}
12155
12156/// Getter for variable symbols not referenced by any debug info and
12157/// that got deleted.
12158///
12159/// @return a map of elf variable symbols not referenced by any debug
12160/// info and that got deleted.
12163{return priv_->deleted_unrefed_var_syms_;}
12164
12165/// Getter for variable symbols not referenced by any debug info and
12166/// that got added.
12167///
12168/// @return a map of elf variable symbols not referenced by any debug
12169/// info and that got added.
12172{return priv_->added_unrefed_var_syms_;}
12173
12174/// Getter for a map of deleted types that are not reachable from
12175/// global functions/variables.
12176///
12177/// @return a map that associates pretty representation of deleted
12178/// unreachable types and said types.
12181{return priv_->deleted_unreachable_types_;}
12182
12183/// Getter of a sorted vector of deleted types that are not reachable
12184/// from global functions/variables.
12185///
12186/// @return a sorted vector of deleted types that are not reachable
12187/// from global functions/variables. The types are lexicographically
12188/// sorted by considering their pretty representation.
12189const vector<type_base_sptr>&
12191{
12192 if (priv_->deleted_unreachable_types_sorted_.empty())
12193 if (!priv_->deleted_unreachable_types_.empty())
12194 sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
12195 priv_->deleted_unreachable_types_sorted_);
12196
12197 return priv_->deleted_unreachable_types_sorted_;
12198}
12199
12200/// Getter for a map of added types that are not reachable from global
12201/// functions/variables.
12202///
12203/// @return a map that associates pretty representation of added
12204/// unreachable types and said types.
12207{return priv_->added_unreachable_types_;}
12208
12209/// Getter of a sorted vector of added types that are not reachable
12210/// from global functions/variables.
12211///
12212/// @return a sorted vector of added types that are not reachable from
12213/// global functions/variables. The types are lexicographically
12214/// sorted by considering their pretty representation.
12215const vector<type_base_sptr>&
12217{
12218 if (priv_->added_unreachable_types_sorted_.empty())
12219 if (!priv_->added_unreachable_types_.empty())
12220 sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
12221 priv_->added_unreachable_types_sorted_);
12222
12223 return priv_->added_unreachable_types_sorted_;
12224}
12225
12226/// Getter for a map of changed types that are not reachable from
12227/// global functions/variables.
12228///
12229/// @return a map that associates pretty representation of changed
12230/// unreachable types and said types.
12233{return priv_->changed_unreachable_types_;}
12234
12235/// Getter of a sorted vector of changed types that are not reachable
12236/// from global functions/variables.
12237///
12238/// @return a sorted vector of changed types that are not reachable
12239/// from global functions/variables. The diffs are lexicographically
12240/// sorted by considering their pretty representation.
12241const vector<diff_sptr>&
12243{return priv_->changed_unreachable_types_sorted();}
12244
12245/// Getter of the diff context of this diff
12246///
12247/// @return the diff context for this diff.
12250{return priv_->get_context();}
12251
12252/// @return the pretty representation for the current instance of @ref
12253/// corpus_diff
12254const string&
12256{
12257 if (priv_->pretty_representation_.empty())
12258 {
12259 std::ostringstream o;
12260 o << "corpus_diff["
12261 << first_corpus()->get_path()
12262 << ", "
12263 << second_corpus()->get_path()
12264 << "]";
12265 priv_->pretty_representation_ = o.str();
12266 }
12267 return priv_->pretty_representation_;
12268}
12269/// Return true iff the current @ref corpus_diff node carries a
12270/// change.
12271///
12272/// @return true iff the current diff node carries a change.
12273bool
12275{
12276 diff_context_sptr ctxt = context();
12277
12278 return (soname_changed()
12280 || !(priv_->deleted_fns_.empty()
12281 && (priv_->added_fns_.empty()
12282 || !ctxt->show_added_fns())
12283 && priv_->changed_fns_map_.empty()
12284 && priv_->deleted_vars_.empty()
12285 && (priv_->added_vars_.empty()
12286 || !ctxt->show_added_vars())
12287 && priv_->changed_vars_map_.empty()
12288 && (priv_->added_unrefed_fn_syms_.empty()
12289 || !ctxt->show_added_symbols_unreferenced_by_debug_info())
12290 && (priv_->deleted_unrefed_fn_syms_.empty()
12291 || !ctxt->show_symbols_unreferenced_by_debug_info())
12292 && (priv_->added_unrefed_var_syms_.empty()
12293 || !ctxt->show_added_symbols_unreferenced_by_debug_info())
12294 && (priv_->deleted_unrefed_var_syms_.empty()
12295 || !ctxt->show_symbols_unreferenced_by_debug_info())
12296 && (priv_->deleted_unreachable_types_.empty()
12297 || !ctxt->show_unreachable_types())
12298 && (priv_->added_unreachable_types_.empty()
12299 || !ctxt->show_unreachable_types())
12300 && (priv_->changed_unreachable_types_.empty()
12301 || !ctxt->show_unreachable_types())));
12302}
12303
12304/// Test if the current instance of @ref corpus_diff carries changes
12305/// that we are sure are incompatible. By incompatible change we mean
12306/// a change that "breaks" the ABI of the corpus we are looking at.
12307///
12308/// In concrete terms, this function considers the following changes
12309/// as being ABI incompatible for sure:
12310///
12311/// - a soname change
12312/// - if exported functions or variables got removed
12313///
12314/// Note that subtype changes *can* represent changes that break ABI
12315/// too. But they also can be changes that are OK, ABI-wise.
12316///
12317/// It's up to the user to provide suppression specifications to say
12318/// explicitely which subtype change is OK. The remaining sub-type
12319/// changes are then considered to be ABI incompatible. But to test
12320/// if such ABI incompatible subtype changes are present you need to
12321/// use the function @ref corpus_diff::has_net_subtype_changes()
12322///
12323/// @return true iff the current instance of @ref corpus_diff carries
12324/// changes that we are sure are ABI incompatible.
12325bool
12327{
12328 const diff_stats& stats = const_cast<corpus_diff*>(this)->
12330
12331 diff_context_sptr ctxt = context();
12332
12336 || stats.net_num_func_removed() != 0
12338 // If all reports about functions changes have been
12339 // suppressed, then even those about incompatible changes
12340 // don't matter anymore because the user willingly requested
12341 // to shut them down.
12342 && stats.net_num_func_changed() != 0)
12343 || stats.net_num_vars_removed() != 0
12345 && stats.net_num_vars_changed() != 0)
12346 || (stats.net_num_removed_func_syms() != 0
12347 && ctxt->show_symbols_unreferenced_by_debug_info())
12348 || (stats.net_num_removed_var_syms() != 0
12349 && ctxt->show_symbols_unreferenced_by_debug_info())
12350 || (stats.net_num_removed_unreachable_types() != 0
12351 && ctxt->show_unreachable_types()));
12352
12353 // If stats.net_num_changed_unreachable_types() != 0 then walk the
12354 // corpus_diff::priv::changed_unreachable_types_, and see if there
12355 // is one that is harmful by bitwise and-ing their category with
12356 // abigail::comparison::get_default_harmful_categories_bitmap().
12359 && ctxt->show_unreachable_types())
12360 {
12361 // The changed unreachable types can carry harmful changes.
12362 // Let's figure if they actually do.
12363
12364 diff_context_sptr ctxt = context();
12365 for (auto &entry : priv_->changed_unreachable_types())
12366 {
12367 diff_sptr dif = entry.second;
12368
12369 // Let's see if any of the categories of this diff node
12370 // belong to the "harmful" ones.
12371 if (dif->get_category() & get_default_harmful_categories_bitmap())
12372 {
12374 break;
12375 }
12376 }
12377 }
12378
12380}
12381
12382/// Test if the current instance of @ref corpus_diff carries subtype
12383/// changes whose reports are not suppressed by any suppression
12384/// specification. In effect, these are deemed incompatible ABI
12385/// changes.
12386///
12387/// @return true iff the the current instance of @ref corpus_diff
12388/// carries subtype changes that are deemed incompatible ABI changes.
12389bool
12391{
12392 const diff_stats& stats = const_cast<corpus_diff*>(this)->
12394
12395 return (stats.net_num_func_changed() != 0
12396 || stats.net_num_vars_changed() != 0
12397 || stats.net_num_removed_unreachable_types() != 0
12398 || stats.net_num_changed_unreachable_types() != 0);
12399}
12400
12401/// Test if the current instance of @ref corpus_diff carries changes
12402/// whose reports are not suppressed by any suppression specification.
12403/// In effect, these are deemed incompatible ABI changes.
12404///
12405/// @return true iff the the current instance of @ref corpus_diff
12406/// carries subtype changes that are deemed incompatible ABI changes.
12407bool
12409{return context()->get_reporter()->diff_has_net_changes(this);}
12410
12411/// Mark leaf nodes and apply the different filters that are
12412/// registered to be applied to the diff tree; that includes the
12413/// categorization filters. Also, apply the suppression
12414/// interpretation filters.
12415///
12416/// After the filters are applied, this function calculates some
12417/// statistics about the changes carried by the current instance of
12418/// @ref corpus_diff. These statistics are represented by an instance
12419/// of @ref corpus_diff::diff_stats.
12420///
12421/// This member function is called by the reporting function
12422/// corpus_diff::report().
12423///
12424/// Note that for a given instance of corpus_diff, this function
12425/// applies the filters and suppressions only the first time it is
12426/// invoked. Subsequent invocations just return the instance of
12427/// corpus_diff::diff_stats that was cached after the first
12428/// invocation.
12429///
12430/// @return a reference to the statistics about the changes carried by
12431/// the current instance of @ref corpus_diff.
12434{
12435 if (priv_->diff_stats_)
12436 return *priv_->diff_stats_;
12437
12439
12440 priv_->diff_stats_.reset(new diff_stats(context()));
12441
12442 if (do_log())
12443 {
12444 std::cerr << "Marking leaf nodes ...\n";
12445 t.start();
12446 }
12447
12449
12450 if (do_log())
12451 {
12452 t.stop();
12453 std::cerr << "leaf nodes marked in:" << t << "\n";
12454 std::cerr << "Applying filters and computing diff stats ...\n";
12455 t.start();
12456 }
12457
12458 priv_->apply_filters_and_compute_diff_stats(this, *priv_->diff_stats_);
12459
12460 if (do_log())
12461 {
12462 t.stop();
12463 std::cerr << "Filters applied and diff stats computed in: " << t << "\n";
12464 }
12465
12466 return *priv_->diff_stats_;
12467}
12468
12469/// A visitor that marks leaf diff nodes by storing them in the
12470/// instance of @ref diff_maps returned by
12471/// corpus_diff::get_leaf_diffs() invoked on the current instance of
12472/// corpus_diff.
12473struct leaf_diff_node_marker_visitor : public diff_node_visitor
12474{
12475 /// This is called when the visitor visits a diff node.
12476 ///
12477 /// It basically tests if the diff node being visited is a leaf diff
12478 /// node - that is, it contains local changes. If it does, then the
12479 /// node is added to the set of maps that hold leaf diffs in the
12480 /// current corpus_diff.
12481 ///
12482 /// Note that only leaf nodes that are reachable from public
12483 /// interfaces (global functions or variables) are collected by this
12484 /// visitor.
12485 ///
12486 /// @param d the diff node being visited.
12487 virtual void
12488 visit_begin(diff *d)
12489 {
12490 if (d->has_local_changes()
12491 // A leaf basic (or class/union) type name change makes no
12492 // sense when showing just leaf changes. It only makes sense
12493 // when it can explain the details about a non-leaf change.
12494 // In other words, it doesn't make sense to say that an "int"
12495 // became "unsigned int". But it does make sense to say that
12496 // a typedef changed because its underlying type was 'int' and
12497 // is now an "unsigned int".
12499 // Similarly, a *local* change describing a type that changed
12500 // its nature doesn't make sense.
12501 && !is_distinct_diff(d)
12502 // Similarly, a pointer (or reference or array), a typedef or
12503 // qualified type change in itself doesn't make sense. It
12504 // would rather make sense to show that pointer change as part
12505 // of the variable change whose pointer type changed, for
12506 // instance.
12507 && !is_pointer_diff(d)
12508 && !is_reference_diff(d)
12510 && !is_typedef_diff(d)
12511 && !is_array_diff(d)
12512 // Similarly a parameter change in itself doesn't make sense.
12513 // It should have already been reported as part of the change
12514 // of the function it belongs to.
12515 && !is_fn_parm_diff(d)
12516 // An anonymous class or union diff doesn't make sense on its
12517 // own. It must have been described already by the diff of
12518 // the enclosing struct or union if 'd' is from an anonymous
12519 // data member, or from a typedef change if 'd' is from a
12520 // typedef change which underlying type is an anonymous
12521 // struct/union.
12523 // An anonymous subrange doesn't make sense either.
12525 // Don't show decl-only-ness changes either.
12527 // Sometime, we can encounter artifacts of bogus DWARF that
12528 // yield a diff node for a decl-only class (and empty class
12529 // with the is_declaration flag set) that carries a non-zero
12530 // size! And of course at some point that non-zero size
12531 // changes. We need to be able to detect that.
12533 {
12534 diff_context_sptr ctxt = d->context();
12535 const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
12536 ABG_ASSERT(corpus_diff_node);
12537
12538 if (diff *iface_diff = get_current_topmost_iface_diff())
12539 {
12540 type_or_decl_base_sptr iface = iface_diff->first_subject();
12541 // So, this diff node that is reachable from a global
12542 // function or variable carries a leaf change. Let's add
12543 // it to the set of of leaf diffs of corpus_diff_node.
12544 const_cast<corpus_diff*>(corpus_diff_node)->
12545 get_leaf_diffs().insert_diff_node(d, iface);
12546 }
12547 }
12548 }
12549}; // end struct leaf_diff_node_marker_visitor
12550
12551/// Walks the diff nodes associated to the current corpus diff and
12552/// mark those that carry local changes. They are said to be leaf
12553/// diff nodes.
12554///
12555/// The marked nodes are available from the
12556/// corpus_diff::get_leaf_diffs() function.
12557void
12559{
12560 if (!has_changes())
12561 return;
12562
12563 if (!context()->show_leaf_changes_only())
12564 return;
12565
12566 leaf_diff_node_marker_visitor v;
12567 context()->forget_visited_diffs();
12568 bool s = context()->visiting_a_node_twice_is_forbidden();
12569 context()->forbid_visiting_a_node_twice(true);
12570 if (context()->show_impacted_interfaces())
12571 context()->forbid_visiting_a_node_twice_per_interface(true);
12572 traverse(v);
12573 context()->forbid_visiting_a_node_twice(s);
12574 context()->forbid_visiting_a_node_twice_per_interface(false);
12575}
12576
12577/// Get the set of maps that contain leaf nodes. A leaf node being a
12578/// node with a local change.
12579///
12580/// @return the set of maps that contain leaf nodes. A leaf node
12581/// being a node with a local change.
12582diff_maps&
12584{return priv_->leaf_diffs_;}
12585
12586/// Get the set of maps that contain leaf nodes. A leaf node being a
12587/// node with a local change.
12588///
12589/// @return the set of maps that contain leaf nodes. A leaf node
12590/// being a node with a local change.
12591const diff_maps&
12593{return priv_->leaf_diffs_;}
12594
12595/// Report the diff in a serialized form.
12596///
12597/// @param out the stream to serialize the diff to.
12598///
12599/// @param indent the prefix to use for the indentation of this
12600/// serialization.
12601void
12602corpus_diff::report(ostream& out, const string& indent) const
12603{
12604 context()->get_reporter()->report(*this, out, indent);
12605}
12606
12607/// Traverse the diff sub-tree under the current instance corpus_diff.
12608///
12609/// @param v the visitor to invoke on each diff node of the sub-tree.
12610///
12611/// @return true if the traversing has to keep going on, false otherwise.
12612bool
12614{
12616
12617 v.visit_begin(this);
12618
12619 if (!v.visit(this, true))
12620 {
12621 v.visit_end(this);
12622 return false;
12623 }
12624
12625 for (function_decl_diff_sptrs_type::const_iterator i =
12626 changed_functions_sorted().begin();
12627 i != changed_functions_sorted().end();
12628 ++i)
12629 {
12630 if (diff_sptr d = *i)
12631 {
12632 const diff_context_sptr &ctxt = context();
12633 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12634 ctxt->forget_visited_diffs();
12635
12637
12638 if (!d->traverse(v))
12639 {
12640 v.visit_end(this);
12642 return false;
12643 }
12644 }
12645 }
12646
12647 for (var_diff_sptrs_type::const_iterator i =
12648 changed_variables_sorted().begin();
12649 i != changed_variables_sorted().end();
12650 ++i)
12651 {
12652 if (diff_sptr d = *i)
12653 {
12654 const diff_context_sptr &ctxt = context();
12655 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12656 ctxt->forget_visited_diffs();
12657
12659
12660 if (!d->traverse(v))
12661 {
12662 v.visit_end(this);
12664 return false;
12665 }
12666 }
12667 }
12668
12670
12671 // Traverse the changed unreachable type diffs. These diffs are on
12672 // types that are not reachable from global functions or variables.
12673 for (vector<diff_sptr>::const_iterator i =
12676 ++i)
12677 {
12678 if (diff_sptr d = *i)
12679 {
12680 const diff_context_sptr &ctxt = context();
12681 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12682 ctxt->forget_visited_diffs();
12683
12684 if (!d->traverse(v))
12685 {
12686 v.visit_end(this);
12687 return false;
12688 }
12689 }
12690 }
12691
12692 v.visit_end(this);
12693 return true;
12694}
12695
12696/// Use a hash-based set difference to compute added/deleted
12697/// unreferenced symbols between two corpora. This replaces the
12698/// previous Myers diff approach which was O(N*D) and became quadratic
12699/// when most symbols differ. The downstream consumer only needs
12700/// unordered maps keyed by symbol id_string, so ordering is not
12701/// required.
12702///
12703/// @param first the first corpus.
12704///
12705/// @param second the second corpus.
12706///
12707/// @param first_syms unreferenced symbols from the first corpus.
12708///
12709/// @param second_syms unreferenced symbols from the second corpus.
12710///
12711/// @param deleted_syms output map of deleted symbols (in first but
12712/// not second), keyed by id_string.
12713///
12714/// @param added_syms output map of added symbols (in second but not
12715/// first), keyed by id_string.
12716///
12717/// @param lookup_in_corpus a function that looks up whether a symbol
12718/// exists in a given corpus.
12719template<typename lookup_fn>
12720static void
12721compute_unreferenced_symbol_set_diff(const corpus_sptr& first,
12722 const corpus_sptr& second,
12723 const elf_symbols& first_syms,
12724 const elf_symbols& second_syms,
12725 string_elf_symbol_map& deleted_syms,
12726 string_elf_symbol_map& added_syms,
12727 lookup_fn lookup_in_corpus)
12728{
12729 // Build a map of id_string -> symbol for each side.
12730 unordered_map<string, elf_symbol_sptr> first_map, second_map;
12731 first_map.reserve(first_syms.size());
12732 second_map.reserve(second_syms.size());
12733
12734 for (const auto& sym : first_syms)
12735 first_map[sym->get_id_string()] = sym;
12736
12737 for (const auto& sym : second_syms)
12738 second_map[sym->get_id_string()] = sym;
12739
12740 // Symbols in first but not in second are candidate deletions.
12741 for (const auto& entry : first_map)
12742 {
12743 if (second_map.find(entry.first) == second_map.end())
12744 {
12745 if (!lookup_in_corpus(second, *entry.second))
12746 deleted_syms[entry.first] = entry.second;
12747 }
12748 }
12749
12750 // Symbols in second but not in first are candidate additions.
12751 for (const auto& entry : second_map)
12752 {
12753 if (first_map.find(entry.first) != first_map.end())
12754 continue;
12755
12756 if (!lookup_in_corpus(first, *entry.second))
12757 {
12758 bool do_add = true;
12759 if (!entry.second->get_version().is_empty()
12760 && entry.second->get_version().is_default())
12761 {
12762 // added_sym has a default version. If the former
12763 // corpus had a symbol with the same name but with
12764 // *no* version, then it shouldn't be considered as
12765 // newly added.
12766 elf_symbol::version empty_version;
12767 if (lookup_in_corpus(first, entry.second->get_name(),
12768 empty_version))
12769 do_add = false;
12770 }
12771 if (do_add)
12772 added_syms[entry.first] = entry.second;
12773 }
12774 }
12775}
12776
12777/// Compute the diff between two instances of @ref corpus.
12778///
12779/// Note that the two corpora must have been created in the same @ref
12780/// environment, otherwise, this function aborts.
12781///
12782/// @param f the first @ref corpus to consider for the diff.
12783///
12784/// @param s the second @ref corpus to consider for the diff.
12785///
12786/// @param ctxt the diff context to use.
12787///
12788/// @return the resulting diff between the two @ref corpus.
12790compute_diff(const corpus_sptr f,
12791 const corpus_sptr s,
12792 diff_context_sptr ctxt)
12793{
12794 ABG_ASSERT(f && s);
12795
12796 if (!ctxt)
12797 ctxt.reset(new diff_context);
12798
12799 corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
12800
12801 ctxt->set_corpus_diff(r);
12802
12803 if(ctxt->show_soname_change())
12804 r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
12805 else
12806 r->priv_->sonames_equal_ = true;
12807
12808 r->priv_->architectures_equal_ =
12809 f->get_architecture_name() == s->get_architecture_name();
12810
12811 // Note: the diff of functions, variables, unreferenced symbols and
12812 // unreachable types is computed by
12813 // compare_fns_vars_and_ensure_lookup_tables_populated() below using
12814 // hash-based set difference, which avoids the quadratic behavior of
12815 // Myers diff when most entries differ between large corpora.
12816
12817 // Compute the diff of function elf symbols not referenced by debug
12818 // info. Use hash-based set difference instead of Myers diff to
12819 // avoid quadratic behavior when most symbols differ.
12820 compute_unreferenced_symbol_set_diff
12821 (f, s,
12822 f->get_unreferenced_function_symbols(),
12823 s->get_unreferenced_function_symbols(),
12824 r->priv_->deleted_unrefed_fn_syms_,
12825 r->priv_->added_unrefed_fn_syms_,
12826 [](const auto& c, auto&&... args)
12827 {return c->lookup_function_symbol(std::forward<decltype(args)>(args)...);});
12828
12829 // Compute the diff of variable elf symbols not referenced by debug
12830 // info. Use hash-based set difference instead of Myers diff to
12831 // avoid quadratic behavior when most symbols differ.
12832 compute_unreferenced_symbol_set_diff
12833 (f, s,
12834 f->get_unreferenced_variable_symbols(),
12835 s->get_unreferenced_variable_symbols(),
12836 r->priv_->deleted_unrefed_var_syms_,
12837 r->priv_->added_unrefed_var_syms_,
12838 [](const auto& c, auto&&... args)
12839 {return c->lookup_variable_symbol(std::forward<decltype(args)>(args)...);});
12840
12841 r->priv_->compare_fns_vars_and_ensure_lookup_tables_populated();
12842
12843 return r;
12844}
12845
12846// </corpus stuff>
12847
12848/// Compute the diff between two instances of @ref corpus_group.
12849///
12850/// Note that the two corpus_diff must have been created in the same
12851/// @ref environment, otherwise, this function aborts.
12852///
12853/// @param f the first @ref corpus_group to consider for the diff.
12854///
12855/// @param s the second @ref corpus_group to consider for the diff.
12856///
12857/// @param ctxt the diff context to use.
12858///
12859/// @return the resulting diff between the two @ref corpus_group.
12861compute_diff(const corpus_group_sptr& f,
12862 const corpus_group_sptr& s,
12863 diff_context_sptr ctxt)
12864{
12865
12866 corpus_sptr c1 = f;
12867 corpus_sptr c2 = s;
12868
12869 return compute_diff(c1, c2, ctxt);
12870}
12871
12872// <corpus_group stuff>
12873
12874// </corpus_group stuff>
12875
12876// <diff_node_visitor stuff>
12877
12878/// The private data of the @diff_node_visitor type.
12879struct diff_node_visitor::priv
12880{
12881 diff* topmost_interface_diff;
12882 visiting_kind kind;
12883
12884 priv()
12885 : topmost_interface_diff(),
12886 kind()
12887 {}
12888
12889 priv(visiting_kind k)
12890 : topmost_interface_diff(),
12891 kind(k)
12892 {}
12893}; // end struct diff_node_visitor
12894
12895/// Default constructor of the @ref diff_node_visitor type.
12897 : priv_(new priv)
12898{}
12899
12900diff_node_visitor::~diff_node_visitor() = default;
12901
12902/// Constructor of the @ref diff_node_visitor type.
12903///
12904/// @param k how the visiting has to be performed.
12906 : priv_(new priv(k))
12907{}
12908
12909/// Getter for the visiting policy of the traversing code while
12910/// invoking this visitor.
12911///
12912/// @return the visiting policy used by the traversing code when
12913/// invoking this visitor.
12916{return priv_->kind;}
12917
12918/// Setter for the visiting policy of the traversing code while
12919/// invoking this visitor.
12920///
12921/// @param v a bit map representing the new visiting policy used by
12922/// the traversing code when invoking this visitor.
12923void
12926
12927/// Setter for the visiting policy of the traversing code while
12928/// invoking this visitor. This one makes a logical or between the
12929/// current policy and the bitmap given in argument and assigns the
12930/// current policy to the result.
12931///
12932/// @param v a bitmap representing the visiting policy to or with
12933/// the current policy.
12934void
12936{priv_->kind = priv_->kind | v;}
12937
12938/// Setter of the diff current topmost interface which is impacted by
12939/// the current diff node being visited.
12940///
12941/// @param d the current topmost interface diff impacted.
12942void
12944{priv_->topmost_interface_diff = d;}
12945
12946/// Getter of the diff current topmost interface which is impacted by
12947/// the current diff node being visited.
12948///
12949/// @return the current topmost interface diff impacted.
12950diff*
12952{return priv_->topmost_interface_diff;}
12953
12954/// This is called by the traversing code on a @ref diff node just
12955/// before visiting it. That is, before visiting it and its children
12956/// node.
12957///
12958/// @param d the diff node to visit.
12959void
12962
12963/// This is called by the traversing code on a @ref diff node just
12964/// after visiting it. That is after visiting it and its children
12965/// nodes.
12966///
12967/// @param d the diff node that got visited.
12968void
12971
12972/// This is called by the traversing code on a @ref corpus_diff node
12973/// just before visiting it. That is, before visiting it and its
12974/// children node.
12975///
12976/// @param p the corpus_diff node to visit.
12977///
12978void
12981
12982/// This is called by the traversing code on a @ref corpus_diff node
12983/// just after visiting it. That is after visiting it and its children
12984/// nodes.
12985///
12986/// @param d the diff node that got visited.
12987void
12990
12991/// Default visitor implementation
12992///
12993/// @return true
12994bool
12996{return true;}
12997
12998/// Default visitor implementation.
12999///
13000/// @return true
13001bool
13003{
13004 diff* d = dif;
13005 visit(d, pre);
13006
13007 return true;
13008}
13009
13010/// Default visitor implementation.
13011///
13012/// @return true
13013bool
13015{
13016 diff* d = dif;
13017 visit(d, pre);
13018
13019 return true;
13020}
13021
13022/// Default visitor implementation.
13023///
13024/// @return true
13025bool
13027{
13028 diff* d = dif;
13029 visit(d, pre);
13030
13031 return true;
13032}
13033
13034/// Default visitor implementation.
13035///
13036/// @return true
13037bool
13039{
13040 diff* d = dif;
13041 visit(d, pre);
13042
13043 return true;
13044}
13045
13046/// Default visitor implementation.
13047///
13048/// @return true
13049bool
13051{
13052 diff* d = dif;
13053 visit(d, pre);
13054
13055 return true;
13056}
13057
13058/// Default visitor implementation.
13059///
13060/// @return true
13061bool
13063{
13064 diff* d = dif;
13065 visit(d, pre);
13066
13067 return true;
13068}
13069
13070/// Default visitor implementation.
13071///
13072/// @return true
13073bool
13075{
13076 diff* d = dif;
13077 visit(d, pre);
13078
13079 return true;
13080}
13081
13082/// Default visitor implementation.
13083///
13084/// @return true
13085bool
13087{
13088 diff* d = dif;
13089 visit(d, pre);
13090
13091 return true;
13092}
13093
13094/// Default visitor implementation.
13095///
13096/// @return true
13097bool
13099{
13100 diff* d = dif;
13101 visit(d, pre);
13102
13103 return true;
13104}
13105
13106/// Default visitor implementation.
13107///
13108/// @return true
13109bool
13111{
13112 diff* d = dif;
13113 visit(d, pre);
13114
13115 return true;
13116}
13117
13118/// Default visitor implementation.
13119///
13120/// @return true
13121bool
13123{
13124 diff* d = dif;
13125 visit(d, pre);
13126
13127 return true;
13128}
13129
13130/// Default visitor implementation.
13131///
13132/// @return true
13133bool
13135{
13136 diff* d = dif;
13137 visit(d, pre);
13138
13139 return true;
13140}
13141
13142/// Default visitor implementation.
13143///
13144/// @return true
13145bool
13147{
13148 diff* d = dif;
13149 visit(d, pre);
13150
13151 return true;
13152}
13153
13154/// Default visitor implementation.
13155///
13156/// @return true
13157bool
13159{return true;}
13160
13161// </diff_node_visitor stuff>
13162
13163// <redundant diff node marking>
13164
13165// </redundant diff node marking>
13166
13167// <diff tree category propagation>
13168
13169/// A visitor to propagate the category of a node up to its parent
13170/// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
13171/// SUPPRESSED_CATEGORY because those are propagated using other
13172/// specific visitors.
13173struct category_propagation_visitor : public diff_node_visitor
13174{
13175 virtual void
13176 visit_end(diff* d)
13177 {
13178 // Has this diff node 'd' been already visited ?
13179 bool already_visited = d->context()->diff_has_been_visited(d);
13180
13181 // The canonical diff node of the class of equivalence of the diff
13182 // node 'd'.
13183 diff* canonical = d->get_canonical_diff();
13184
13185 // If this class of equivalence of diff node is being visited for
13186 // the first time, then update its canonical node's category too.
13187 bool update_canonical = !already_visited && canonical;
13188
13189 for (auto node : d->children_nodes())
13190 {
13191 if (node->get_category() & (SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY))
13192 // Do not propagate categories from a suppressed child node.
13193 // Note that the suppression application pass (via
13194 // corpus_diff::priv::apply_suppressions) must have been
13195 // done prior to this pass.
13196 continue;
13197
13198 // If we are visiting the class of equivalence of 'd' for the
13199 // first time, then let's look at the children of 'd' and
13200 // propagate their categories to 'd'.
13201 //
13202 // If the class of equivalence of 'd' has already been
13203 // visited, then let's look at the canonical diff nodes of the
13204 // children of 'd' and propagate their categories to 'd'.
13205 diff* diff = (already_visited
13206 ? node->get_canonical_diff()
13207 : node);
13208
13210
13212 // Do not propagate redundant and suppressed categories. Those
13213 // are propagated in a specific pass elsewhere.
13214 c &= ~(REDUNDANT_CATEGORY
13220 // Also, if a (class) type has got a harmful name change, do not
13221 // propagate harmless name changes coming from its sub-types
13222 // (i.e, data members) to the class itself.
13225
13226 d->add_to_category(c);
13227 if (!already_visited && canonical)
13228 if (update_canonical)
13229 canonical->add_to_category(c);
13230 }
13231
13234 {
13235 // The current diff node has either:
13236 //
13237 // 1/ a harmless "void pointer to pointer" change
13238 //
13239 // or:
13240 //
13241 // 2/ a harmless "enum to int" change.
13242 //
13243 // The change 1/ was most likely flagged locally as a
13244 // non-compatible distinct change, aka, a non-compatible
13245 // change between two types of different kinds. At a higher
13246 // level however, as we see that it's just a void pointer to
13247 // pointer change, we should unset the
13248 // NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY categorization.
13249 //
13250 // The change 2/ was most likely flagged locally (in the
13251 // children nodes of the current diff node) as a
13252 // non-compatible name change. At a higher level however, as
13253 // we see that it's just a harmless "enum to int" change,
13254 // let's unset the NON_COMPATIBLE_NAME_CHANGE_CATEGORY
13255 // categorization as well.
13256 diff_category c = d->get_category();
13257 c &= (~NON_COMPATIBLE_NAME_CHANGE_CATEGORY
13258 & ~NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY);
13259 d->set_category(c);
13261 {
13262 // For pointers and references, changes to
13263 // pointed-to-types are considered local. So, if some
13264 // pointed-to-types have non-compatible name or distinct
13265 // change, then the local category of the
13266 // pointer/reference will reflect that. Let's thus clear
13267 // those NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY and
13268 // NON_COMPATIBLE_NAME_CHANGE_CATEGORY bits from the local
13269 // category as well.
13270 c = d->get_local_category();
13271 c &= (~NON_COMPATIBLE_NAME_CHANGE_CATEGORY
13272 & ~NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY);
13273 d->set_local_category(c);
13274 }
13275 }
13276
13278 {
13279 diff_category c = d->get_category();
13280 c &= ~NON_COMPATIBLE_NAME_CHANGE_CATEGORY;
13281 d->set_category(c);
13282 }
13283 }
13284};// end struct category_propagation_visitor
13285
13286/// Visit all the nodes of a given sub-tree. For each node that has a
13287/// particular category set, propagate that category set up to its
13288/// parent nodes.
13289///
13290/// @param diff_tree the diff sub-tree to walk for categorization
13291/// purpose;
13292void
13294{
13295 category_propagation_visitor v;
13296 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13297 diff_tree->context()->forbid_visiting_a_node_twice(true);
13298 diff_tree->context()->forget_visited_diffs();
13299 diff_tree->traverse(v);
13300 diff_tree->context()->forbid_visiting_a_node_twice(s);
13301}
13302
13303/// Visit all the nodes of a given sub-tree. For each node that has a
13304/// particular category set, propagate that category set up to its
13305/// parent nodes.
13306///
13307/// @param diff_tree the diff sub-tree to walk for categorization
13308/// purpose;
13309void
13311{propagate_categories(diff_tree.get());}
13312
13313/// Visit all the nodes of a given corpus tree. For each node that
13314/// has a particular category set, propagate that category set up to
13315/// its parent nodes.
13316///
13317/// @param diff_tree the corpus_diff tree to walk for categorization
13318/// purpose;
13319void
13321{
13322 category_propagation_visitor v;
13323 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13324 diff_tree->context()->forbid_visiting_a_node_twice(false);
13325 diff_tree->traverse(v);
13326 diff_tree->context()->forbid_visiting_a_node_twice(s);
13327}
13328
13329/// Visit all the nodes of a given corpus tree. For each node that
13330/// has a particular category set, propagate that category set up to
13331/// its parent nodes.
13332///
13333/// @param diff_tree the corpus_diff tree to walk for categorization
13334/// purpose;
13335void
13338
13339/// A tree node visitor that knows how to categorizes a given diff
13340/// node in the SUPPRESSED_CATEGORY category and how to propagate that
13341/// categorization.
13342struct suppression_categorization_visitor : public diff_node_visitor
13343{
13344 /// Before visiting the children of the diff node, check if the node
13345 /// is suppressed by a suppression specification. If it is, mark
13346 /// the node as belonging to the SUPPRESSED_CATEGORY category.
13347 ///
13348 /// @param p the diff node to visit.
13349 virtual void
13350 visit_begin(diff* d)
13351 {
13352 bool is_private_type = false;
13353 if (d->is_suppressed(is_private_type))
13354 {
13355 diff_category c = is_private_type
13359
13360 // If a node was suppressed, all the other nodes of its class
13361 // of equivalence are suppressed too.
13362 diff *canonical_diff = d->get_canonical_diff();
13363 if (canonical_diff != d)
13364 canonical_diff->add_to_category(c);
13365 }
13367 {
13368 // This diff node is specifically allowed by a
13369 // negated_suppression, then mark it as being in the
13370 // HAS_ALLOWED_CHANGE_CATEGORY.
13373 diff *canonical_diff = d->get_canonical_diff();
13374 canonical_diff->add_to_category(c);
13375
13376 // Note that some complementary code later down below does
13377 // categorize the descendants and parents nodes of this node
13378 // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
13379 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
13380 }
13381
13382 // If a parent node has been allowed by a negated suppression
13383 // specification, then categorize the current node as
13384 // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
13385 if (d->parent_node())
13386 {
13391 else
13392 {
13393 c = d->parent_node()->get_category();
13397 }
13398 }
13399
13400 }
13401
13402 /// After visiting the children nodes of a given diff node,
13403 /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
13404 /// diff node, if need be.
13405 ///
13406 /// That is, if all children nodes carry a suppressed change the
13407 /// current node should be marked as suppressed as well.
13408 ///
13409 /// In practice, this might be too strong of a condition. If the
13410 /// current node carries a local change (i.e, a change not carried
13411 /// by any of its children node) and if that change is not
13412 /// suppressed, then the current node should *NOT* be suppressed.
13413 ///
13414 /// But right now, the IR doesn't let us know about local vs
13415 /// children-carried changes. So we cannot be that precise yet.
13416 virtual void
13417 visit_end(diff* d)
13418 {
13419 bool has_non_suppressed_child = false;
13420 bool has_non_empty_child = false;
13421 bool has_suppressed_child = false;
13422 bool has_non_private_child = false;
13423 bool has_private_child = false;
13424 bool has_descendant_with_allowed_change = false;
13425
13426 if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
13427 // (or the PRIVATE_TYPE_CATEGORY for the same matter)
13428 // category from its children is a node which:
13429 //
13430 // 1/ hasn't been suppressed already
13431 //
13432 // 2/ and has no local change (unless it's a pointer,
13433 // reference or qualified diff node).
13434 //
13435 // Note that qualified type and typedef diff nodes are a bit
13436 // special. The local changes of the underlying type are
13437 // considered local for the qualified/typedef type, just like
13438 // for pointer/reference types. But then the qualified or
13439 // typedef type itself can have local changes of its own, and
13440 // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
13441 // So a qualified type which have local changes that are
13442 // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
13443 // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
13444 // or SUPPRESSED_CATEGORY can see these categories be
13445 // propagated.
13446 //
13447 // Note that all pointer/reference diff node changes are
13448 // potentially considered local, i.e, local changes of the
13449 // pointed-to-type are considered local to the pointer itself.
13450 //
13451 // Similarly, changes local to the type of function parameters,
13452 // variables (and data members) and classes (that are not of
13453 // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
13454 // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
13455 // those kinds of diff node.
13456 !(d->get_category() & SUPPRESSED_CATEGORY)
13457 && (!d->has_local_changes()
13458 || is_pointer_diff(d)
13459 || is_reference_diff(d)
13461 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13462 || (is_typedef_diff(d)
13463 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13465 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13466 || (is_fn_parm_diff(d)
13467 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13469 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13470 || (is_var_diff(d)
13471 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13472 || (is_class_diff(d)
13473 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
13474 {
13475 // Note that we handle private diff nodes differently from
13476 // generally suppressed diff nodes. E.g, it's not because a
13477 // type is private (and suppressed because of that; i.e, in
13478 // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
13479 // type should also be private and so suppressed. Private
13480 // diff nodes thus have different propagation rules than
13481 // generally suppressed rules.
13482 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
13483 i != d->children_nodes().end();
13484 ++i)
13485 {
13486 diff* child = *i;
13487 if (child->has_changes())
13488 {
13489 has_non_empty_child = true;
13490 if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY
13491 || child->get_category() & SUPPRESSED_CATEGORY
13492 || child->get_category() & REDUNDANT_CATEGORY)
13493 has_suppressed_child = true;
13494 else if (child->get_class_of_equiv_category()
13496 // Propagation of the PRIVATE_TYPE_CATEGORY is going
13497 // to be handled later below.
13498 ;
13499 else
13500 has_non_suppressed_child = true;
13501
13502 if (child->get_class_of_equiv_category()
13504 has_private_child = true;
13505 else if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY
13506 || child->get_category() & SUPPRESSED_CATEGORY
13507 || child->get_category() & REDUNDANT_CATEGORY)
13508 // Propagation of the SUPPRESSED_CATEGORY has been
13509 // handled above already.
13510 ;
13511 else
13512 has_non_private_child = true;
13513 }
13514 }
13515
13516 if (has_non_empty_child
13517 && has_suppressed_child
13518 && !has_non_suppressed_child)
13519 {
13521 // If a node was suppressed, all the other nodes of its class
13522 // of equivalence are suppressed too.
13523 diff *canonical_diff = d->get_canonical_diff();
13524 if (canonical_diff != d)
13525 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
13526 }
13527
13528 // Note that the private-ness of a an underlying type won't be
13529 // propagated to its parent typedef, by virtue of the big "if"
13530 // clause at the beginning of this function. So we don't have
13531 // to handle that case here. So the idiom of defining
13532 // typedefs of private (opaque) types will be respected;
13533 // meaning that changes to opaque underlying type will be
13534 // flagged as private and the typedef will be flagged private
13535 // as well, unless the typedef itself has local non-type
13536 // changes. In the later case, changes to the typedef will be
13537 // emitted because the typedef won't inherit the privateness
13538 // of its underlying type. So in practise, the typedef
13539 // remains public for the purpose of change reporting.
13540 if (has_non_empty_child
13541 && has_private_child
13542 && !has_non_private_child)
13543 {
13544 d->add_to_category(PRIVATE_TYPE_CATEGORY);
13545 // If a node was suppressed, all the other nodes of its class
13546 // of equivalence are suppressed too.
13547 diff *canonical_diff = d->get_canonical_diff();
13548 if (canonical_diff != d)
13549 canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
13550 }
13551
13552 // If the underlying type of a typedef is private and carries
13553 // changes (that are implicitely suppressed because it's
13554 // private) then the typedef must be suppressed too, so that
13555 // those changes to the underlying type are not seen.
13556 if (is_typedef_diff(d)
13557 && !d->has_local_changes()
13558 && has_private_child
13559 && has_non_empty_child)
13560 {
13561 d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
13562 // If a node was suppressed, all the other nodes of its class
13563 // of equivalence are suppressed too.
13564 diff *canonical_diff = d->get_canonical_diff();
13565 if (canonical_diff != d)
13566 canonical_diff->add_to_category
13568 }
13569
13570 if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
13571 if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
13572 {
13573 // d is a function diff that carries a local *type*
13574 // change (that means it's a change to the function
13575 // type). Let's see if the child function type diff
13576 // node is suppressed. That would mean that we are
13577 // instructed to show details of a diff that is deemed
13578 // suppressed; this means the suppression conflicts with
13579 // a local type change. In that case, let's follow what
13580 // the user asked and suppress the function altogether,
13581 if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
13582 if (fn_type_diff->is_suppressed())
13583 {
13584 d->add_to_category(SUPPRESSED_CATEGORY);
13585 // If a node was suppressed, all the other nodes
13586 // of its class of equivalence are suppressed too.
13587 diff *canonical_diff = d->get_canonical_diff();
13588 if (canonical_diff != d)
13589 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
13590 }
13591 }
13592 }
13593
13594 // If any descendant node was selected by a negated suppression
13595 // specification then categorize the current one as
13596 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
13597 for (auto child_node : d->children_nodes())
13598 {
13599 diff *canonical_diff = child_node->get_canonical_diff();
13600 diff_category c = canonical_diff->get_category();
13603 has_descendant_with_allowed_change = true;
13604 }
13605 if (has_descendant_with_allowed_change)
13606 {
13608 d->add_to_category(c);
13609 d->get_canonical_diff()->add_to_category(c);
13610 }
13611 }
13612}; //end struct suppression_categorization_visitor
13613
13614/// Apply suppression specifications to a sub-tree of corpus_diff*.
13615///
13616/// @param d the corpus_diff sub-tree to apply the suppression
13617/// specifications to.
13618void
13620{
13621 if (!get_context() || get_context()->suppressions().empty())
13622 return;
13623
13624 // First, visit the children trees of changed constructs:
13625 // changed functions, variables, as well as sub-types of these,
13626 // and apply suppression specifications to these ...
13627 suppression_categorization_visitor v;
13628 get_context()->forget_visited_diffs();
13629 bool s = get_context()->visiting_a_node_twice_is_forbidden();
13630 get_context()->forbid_visiting_a_node_twice(true);
13631 d->traverse(v);
13632 get_context()->forbid_visiting_a_node_twice(s);
13633
13634 // ... then also visit the set of added and removed functions,
13635 // variables, symbols, and types not reachable from global
13636 // functions and variables.
13638}
13639
13640/// Walk a given diff-sub tree and appply the suppressions carried by
13641/// the context. If the suppression applies to a given node than
13642/// categorize the node into the SUPPRESSED_CATEGORY category and
13643/// propagate that categorization.
13644///
13645/// @param diff_tree the diff-sub tree to apply the suppressions to.
13646void
13648{
13649 if (diff_tree && !diff_tree->context()->suppressions().empty())
13650 {
13651 // Apply suppressions to functions and variables that have
13652 // changed sub-types.
13653 suppression_categorization_visitor v;
13654 diff_tree->context()->forget_visited_diffs();
13655 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13656 diff_tree->context()->forbid_visiting_a_node_twice(true);
13657 diff_tree->traverse(v);
13658 diff_tree->context()->forbid_visiting_a_node_twice(s);
13659 }
13660}
13661
13662/// Walk a given diff-sub tree and appply the suppressions carried by
13663/// the context. If the suppression applies to a given node than
13664/// categorize the node into the SUPPRESSED_CATEGORY category and
13665/// propagate that categorization.
13666///
13667/// @param diff_tree the diff-sub tree to apply the suppressions to.
13668void
13670{apply_suppressions(diff_tree.get());}
13671
13672/// Walk a @ref corpus_diff tree and appply the suppressions carried
13673/// by the context. If the suppression applies to a given node then
13674/// categorize the node into the SUPPRESSED_CATEGORY category and
13675/// propagate that categorization.
13676///
13677/// @param diff_tree the diff tree to apply the suppressions to.
13678void
13680{
13681 if (diff_tree && !diff_tree->context()->suppressions().empty())
13682 {
13683 // First, visit the children trees of changed constructs:
13684 // changed functions, variables, as well as sub-types of these,
13685 // and apply suppression specifications to these ...
13686 suppression_categorization_visitor v;
13687 diff_tree->context()->forget_visited_diffs();
13688 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13689 diff_tree->context()->forbid_visiting_a_node_twice(true);
13690 const_cast<corpus_diff*>(diff_tree)->traverse(v);
13691 diff_tree->context()->forbid_visiting_a_node_twice(s);
13692
13693 // ... then also visit the set of added and removed functions,
13694 // variables, symbols, and types not reachable from global
13695 // functions and variables.
13696 diff_tree->priv_->
13697 apply_supprs_to_added_removed_fns_vars_unreachable_types();
13698 }
13699}
13700
13701/// Walk a diff tree and appply the suppressions carried by the
13702/// context. If the suppression applies to a given node than
13703/// categorize the node into the SUPPRESSED_CATEGORY category and
13704/// propagate that categorization.
13705///
13706/// @param diff_tree the diff tree to apply the suppressions to.
13707void
13709{apply_suppressions(diff_tree.get());}
13710
13711// </diff tree category propagation>
13712
13713// <diff tree printing stuff>
13714
13715/// A visitor to print (to an output stream) a pretty representation
13716/// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
13717struct diff_node_printer : public diff_node_visitor
13718{
13719 ostream& out_;
13720 unsigned level_;
13721
13722 /// Emit a certain number of spaces to the output stream associated
13723 /// to this diff_node_printer.
13724 ///
13725 /// @param level half of the numver of spaces to emit.
13726 void
13727 do_indent(unsigned level)
13728 {
13729 for (unsigned i = 0; i < level; ++i)
13730 out_ << " ";
13731 }
13732
13733 diff_node_printer(ostream& out)
13734 : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
13735 out_(out),
13736 level_(0)
13737 {}
13738
13739 virtual void
13740 visit_begin(diff*)
13741 {
13742 ++level_;
13743 }
13744
13745 virtual void
13746 visit_end(diff*)
13747 {
13748 --level_;
13749 }
13750
13751 virtual void
13752 visit_begin(corpus_diff*)
13753 {
13754 ++level_;
13755 }
13756
13757 virtual void
13758 visit_end(corpus_diff*)
13759 {
13760 --level_;
13761 }
13762
13763 virtual bool
13764 visit(diff* d, bool pre)
13765 {
13766 if (!pre)
13767 // We are post-visiting the diff node D. Which means, we have
13768 // printed a pretty representation for it already. So do
13769 // nothing now.
13770 return true;
13771
13772 do_indent(level_);
13773 out_ << d->get_pretty_representation();
13774 out_ << "\n";
13775 do_indent(level_);
13776 out_ << "{\n";
13777 do_indent(level_ + 1);
13778 out_ << "category: "<< d->get_category() << "\n";
13779 do_indent(level_ + 1);
13780 out_ << "local category: "<< d->get_local_category() << "\n";
13781 do_indent(level_ + 1);
13782 out_ << "@: " << std::hex << d << std::dec << "\n";
13783 do_indent(level_ + 1);
13784 out_ << "@-canonical: " << std::hex
13785 << d->get_canonical_diff()
13786 << std::dec << "\n";
13787 do_indent(level_);
13788 out_ << "}\n";
13789
13790 return true;
13791 }
13792
13793 virtual bool
13794 visit(corpus_diff* d, bool pre)
13795 {
13796 if (!pre)
13797 // We are post-visiting the diff node D. Which means, we have
13798 // printed a pretty representation for it already. So do
13799 // nothing now.
13800 return true;
13801
13802 // indent
13803 for (unsigned i = 0; i < level_; ++i)
13804 out_ << ' ';
13805 out_ << d->get_pretty_representation();
13806 out_ << '\n';
13807 return true;
13808 }
13809}; // end struct diff_printer_visitor
13810
13811// </ diff tree printing stuff>
13812
13813/// Emit a textual representation of a @ref diff sub-tree to an
13814/// output stream.
13815///
13816/// @param diff_tree the sub-tree to emit the textual representation
13817/// for.
13818///
13819/// @param out the output stream to emit the textual representation
13820/// for @p diff_tree to.
13821void
13822print_diff_tree(diff* diff_tree, ostream& out)
13823{
13824 diff_node_printer p(out);
13825 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13826 diff_tree->context()->forbid_visiting_a_node_twice(false);
13827 diff_tree->traverse(p);
13828 diff_tree->context()->forbid_visiting_a_node_twice(s);
13829}
13830
13831/// Emit a textual representation of a @ref corpus_diff tree to an
13832/// output stream.
13833///
13834/// @param diff_tree the @ref corpus_diff tree to emit the textual
13835/// representation for.
13836///
13837/// @param out the output stream to emit the textual representation
13838/// for @p diff_tree to.
13839void
13840print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
13841{
13842 diff_node_printer p(out);
13843 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13844 diff_tree->context()->forbid_visiting_a_node_twice(false);
13845 diff_tree->traverse(p);
13846 diff_tree->context()->forbid_visiting_a_node_twice(s);
13847}
13848
13849/// Emit a textual representation of a @ref diff sub-tree to an
13850/// output stream.
13851///
13852/// @param diff_tree the sub-tree to emit the textual representation
13853/// for.
13854///
13855/// @param out the output stream to emit the textual representation
13856/// for @p diff_tree to.
13857void
13859 std::ostream& o)
13860{print_diff_tree(diff_tree.get(), o);}
13861
13862/// Emit a textual representation of a @ref corpus_diff tree to an
13863/// output stream.
13864///
13865/// @param diff_tree the @ref corpus_diff tree to emit the textual
13866/// representation for.
13867///
13868/// @param out the output stream to emit the textual representation
13869/// for @p diff_tree to.
13870void
13872 std::ostream& o)
13873{print_diff_tree(diff_tree.get(), o);}
13874
13875/// Print a given category out to stdout for debuging purposes
13876///
13877/// @param c the category to print to stdout.
13878void
13880{
13881 std::cout << c << std::endl;
13882}
13883
13884// <redundancy_marking_visitor>
13885
13886/// A tree visitor to categorize nodes with respect to the
13887/// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
13888/// present on several spots of the tree) and mark such nodes
13889/// appropriatly. This visitor also takes care of propagating the
13890/// REDUNDANT_CATEGORY of a given node to its parent nodes as
13891/// appropriate.
13892struct redundancy_marking_visitor : public diff_node_visitor
13893{
13894 bool skip_children_nodes_;
13895
13896 redundancy_marking_visitor()
13897 : skip_children_nodes_()
13898 {}
13899
13900 virtual void
13901 visit_begin(diff* d)
13902 {
13903 if (d->to_be_reported())
13904 {
13905 // A diff node that carries a change and that has been already
13906 // traversed elsewhere is considered redundant. So let's mark
13907 // it as such and let's not traverse it; that is, let's not
13908 // visit its children.
13909 if ((d->context()->diff_has_been_visited(d)
13910 || d->get_canonical_diff()->is_traversing())
13911 && d->has_changes())
13912 {
13913 // But if two diff nodes are redundant sibbling that carry
13914 // changes of base types, do not mark them as being
13915 // redundant. This is to avoid marking nodes as redundant
13916 // in this case:
13917 //
13918 // int foo(int a, int b);
13919 // compared with:
13920 // float foo(float a, float b); (in C).
13921 //
13922 // In this case, we want to report all the occurences of
13923 // the int->float change because logically, they are at
13924 // the same level in the diff tree.
13925
13926 bool redundant_with_sibling_node = false;
13927 const diff* p = d->parent_node();
13928
13929 // If this is a child node of a fn_parm_diff, look through
13930 // the fn_parm_diff node to get the function diff node.
13931 if (p && dynamic_cast<const fn_parm_diff*>(p))
13932 p = p->parent_node();
13933
13934 if (p)
13935 for (vector<diff*>::const_iterator s =
13936 p->children_nodes().begin();
13937 s != p->children_nodes().end();
13938 ++s)
13939 {
13940 if (*s == d)
13941 continue;
13942 diff* sib = *s;
13943 // If this is a fn_parm_diff, look through the
13944 // fn_parm_diff node to get at the real type node.
13945 if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
13946 sib = f->type_diff().get();
13947 if (sib == d)
13948 continue;
13949 if (sib->get_canonical_diff() == d->get_canonical_diff()
13950 // Sibbling diff nodes that carry base type
13951 // changes are to be marked as redundant.
13952 && (is_base_diff(sib) || is_distinct_diff(sib)))
13953 {
13954 redundant_with_sibling_node = true;
13955 break;
13956 }
13957 }
13958 if (!redundant_with_sibling_node
13959 // Changes to basic types should never be considered
13960 // redundant. For instance, if a member of integer
13961 // type is changed into a char type in both a struct A
13962 // and a struct B, we want to see both changes.
13964 // The same goes for distinct type changes
13965 && !filtering::is_mostly_distinct_diff(d)
13966 // Functions with similar *local* changes are never marked
13967 // redundant because otherwise one could miss important
13968 // similar local changes that are applied to different
13969 // functions.
13971 // Changes involving variadic parameters of functions
13972 // should never be marked redundant because we want to see
13973 // them all.
13976 // If the canonical diff itself has been filtered out,
13977 // then this one is not marked redundant, unless the
13978 // canonical diff was already redundant.
13979 && (!d->get_canonical_diff()->is_filtered_out()
13980 || (d->get_canonical_diff()->get_category()
13982 // If the *same* diff node (not one that is merely
13983 // equivalent to this one) has already been visited
13984 // then do not mark it as being redundant. It's only
13985 // the other nodes that are equivalent to this one
13986 // that must be marked redundant.
13987 && d->context()->diff_has_been_visited(d) != d
13988 // If the diff node is a function parameter and is not
13989 // a reference/pointer (to a non basic or a non
13990 // distinct type diff) then do not mark it as
13991 // redundant.
13992 //
13993 // Children nodes of base class diff nodes are never
13994 // redundant either, we want to see them all.
13998 {
13999 d->add_to_category(REDUNDANT_CATEGORY);
14000 // As we said in preamble, as this node is marked as
14001 // being redundant, let's not visit its children.
14002 // This is not an optimization; it's needed for
14003 // correctness. In the case of a diff node involving
14004 // a class type that refers to himself, visiting the
14005 // children nodes might cause them to be wrongly
14006 // marked as redundant.
14007 set_visiting_kind(get_visiting_kind()
14008 | SKIP_CHILDREN_VISITING_KIND);
14009 skip_children_nodes_ = true;
14010 }
14011 }
14012 }
14013 else
14014 {
14015 // If the node is not to be reported, do not look at it children.
14016 set_visiting_kind(get_visiting_kind() | SKIP_CHILDREN_VISITING_KIND);
14017 skip_children_nodes_ = true;
14018 }
14019 }
14020
14021 virtual void
14022 visit_begin(corpus_diff*)
14023 {
14024 }
14025
14026 virtual void
14027 visit_end(diff* d)
14028 {
14029 if (skip_children_nodes_)
14030 // When visiting this node, we decided to skip its children
14031 // node. Now that we are done visiting the node, lets stop
14032 // avoiding the children nodes visiting for the other tree
14033 // nodes.
14034 {
14035 set_visiting_kind(get_visiting_kind() & (~SKIP_CHILDREN_VISITING_KIND));
14036 skip_children_nodes_ = false;
14037 }
14038 else
14039 {
14040 // Propagate the redundancy categorization of the children
14041 // nodes to this node. But if this node has local harmful
14042 // changes then it doesn't inherit redundancy from its
14043 // children nodes.
14044 if (!(d->get_category() & REDUNDANT_CATEGORY)
14045 && (!(is_harmful_category(d->get_local_category()))
14046 // By default, pointer, reference, array and qualified
14047 // types consider that a local changes to their
14048 // underlying type is always a local change for
14049 // themselves.
14050 //
14051 // This is as if those types don't have local changes
14052 // in the same sense as other types. So we always
14053 // propagate redundancy to them, regardless of if they
14054 // have local changes or not.
14055 //
14056 // We also propagate redundancy to typedef types if
14057 // these /only/ carry changes to their underlying
14058 // type.
14059 //
14060 // Note that changes to the underlying type of a
14061 // typedef is considered local of
14062 // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
14063 // typedef itself are considered local of
14064 // LOCAL_NON_TYPE_CHANGE_KIND kind.
14065 || is_pointer_diff(d)
14066 || is_array_diff(d)
14068 // A typedef with local non-type changes should not
14069 // see redundancy propagation from its underlying
14070 // type, otherwise, the non-type change might be
14071 // "suppressed" away.
14072 || (is_typedef_diff(d)
14073 && (!(d->has_local_changes()
14074 & LOCAL_NON_TYPE_CHANGE_KIND)))
14075 // A (member) variable with non-type local changes
14076 // should not see redundacy propagation from its type.
14077 // If redundant local-type changes are carried by its
14078 // type however, then that redundancy is propagated to
14079 // the variable. This is key to keep the redundancy
14080 // consistency in the system; otherwise, a type change
14081 // would be rightfully considered redundant at some
14082 // places but not at others.
14083 || (is_var_diff(d)
14084 && (!(d->has_local_changes()
14085 & LOCAL_NON_TYPE_CHANGE_KIND)))
14086 // A function parameter with non-type local changes
14087 // should not see redundancy propagation either. But
14088 // a function parameter with local type changes can
14089 // definitely be redundant.
14090 || (is_fn_parm_diff(d)
14091 && (!(d->has_local_changes()
14092 & LOCAL_NON_TYPE_CHANGE_KIND)))
14093 ))
14094 {
14095 bool has_non_redundant_child = false;
14096 bool has_non_empty_child = false;
14097 bool is_array_diff_node = is_array_diff(d);
14098 for (vector<diff*>::const_iterator i =
14099 d->children_nodes().begin();
14100 i != d->children_nodes().end();
14101 ++i)
14102 {
14103 if ((*i)->has_changes())
14104 {
14105 // If we are looking at a child node of an array,
14106 // do not take a subrange diff node change into
14107 // account when considering redundancy. In other
14108 // words, a subrange diff node that carries a
14109 // change should not be considered as a non-empty
14110 // child node. This is because we want to report
14111 // all subrange diff node changes and not consider
14112 // them as redundant.
14113 if (!is_array_diff_node || !is_subrange_diff(*i))
14114 has_non_empty_child = true;
14115 // Let's see if the current child node '*i' is
14116 // "non-redundant".
14117 //
14118 // A non-redundant node would be a node that
14119 // carries a change to be reported and has not
14120 // been marked as being redundant.
14121 if ((*i)->to_be_reported()
14122 && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
14123 has_non_redundant_child = true;
14124 }
14125 if (has_non_redundant_child)
14126 break;
14127 }
14128
14129 // A diff node for which at least a child node carries a
14130 // change, and for which all the children are redundant is
14131 // deemed redundant too, unless it has local changes.
14132 if (has_non_empty_child
14133 && !has_non_redundant_child)
14134 d->add_to_category(REDUNDANT_CATEGORY);
14135 }
14136 }
14137 }
14138
14139 virtual void
14140 visit_end(corpus_diff*)
14141 {
14142 }
14143
14144 virtual bool
14145 visit(diff*, bool)
14146 {return true;}
14147
14148 virtual bool
14149 visit(corpus_diff*, bool)
14150 {
14151 return true;
14152 }
14153};// end struct redundancy_marking_visitor
14154
14155/// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
14156/// category out of the nodes.
14157struct redundancy_clearing_visitor : public diff_node_visitor
14158{
14159 bool
14160 visit(corpus_diff*, bool)
14161 {return true;}
14162
14163 bool
14164 visit(diff* d, bool)
14165 {
14166 // clear the REDUNDANT_CATEGORY out of the current node.
14167 diff_category c = d->get_category();
14168 c &= ~REDUNDANT_CATEGORY;
14169 d->set_category(c);
14170 return true;
14171 }
14172}; // end struct redundancy_clearing_visitor
14173
14174/// Walk a given @ref diff sub-tree to categorize each of the nodes
14175/// with respect to the REDUNDANT_CATEGORY.
14176///
14177/// @param diff_tree the @ref diff sub-tree to walk.
14178void
14180{
14181 if (diff_tree->context()->show_redundant_changes())
14182 return;
14183 redundancy_marking_visitor v;
14184 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
14185 diff_tree->context()->forbid_visiting_a_node_twice(false);
14186 diff_tree->traverse(v);
14187 diff_tree->context()->forbid_visiting_a_node_twice(s);
14188}
14189
14190/// Walk a given @ref diff sub-tree to categorize each of the nodes
14191/// with respect to the REDUNDANT_CATEGORY.
14192///
14193/// @param diff_tree the @ref diff sub-tree to walk.
14194void
14196{categorize_redundancy(diff_tree.get());}
14197
14198/// Walk a given @ref corpus_diff tree to categorize each of the nodes
14199/// with respect to the REDUNDANT_CATEGORY.
14200///
14201/// @param diff_tree the @ref corpus_diff tree to walk.
14202void
14204{
14205 redundancy_marking_visitor v;
14206 diff_tree->context()->forget_visited_diffs();
14207 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
14208 diff_tree->context()->forbid_visiting_a_node_twice(false);
14209 diff_tree->traverse(v);
14210 diff_tree->context()->forbid_visiting_a_node_twice(s);
14211}
14212
14213/// Walk a given @ref corpus_diff tree to categorize each of the nodes
14214/// with respect to the REDUNDANT_CATEGORY.
14215///
14216/// @param diff_tree the @ref corpus_diff tree to walk.
14217void
14220
14221// </redundancy_marking_visitor>
14222
14223/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
14224/// out of the category of the nodes.
14225///
14226/// @param diff_tree the @ref diff sub-tree to walk.
14227void
14229{
14230 redundancy_clearing_visitor v;
14231 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
14232 diff_tree->context()->forbid_visiting_a_node_twice(false);
14233 diff_tree->traverse(v);
14234 diff_tree->context()->forbid_visiting_a_node_twice(s);
14235 diff_tree->context()->forget_visited_diffs();
14236}
14237
14238/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
14239/// out of the category of the nodes.
14240///
14241/// @param diff_tree the @ref diff sub-tree to walk.
14242void
14245
14246/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
14247/// out of the category of the nodes.
14248///
14249/// @param diff_tree the @ref corpus_diff tree to walk.
14250void
14252{
14253 redundancy_clearing_visitor v;
14254 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
14255 diff_tree->context()->forbid_visiting_a_node_twice(false);
14256 diff_tree->traverse(v);
14257 diff_tree->context()->forbid_visiting_a_node_twice(s);
14258 diff_tree->context()->forget_visited_diffs();
14259}
14260
14261/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
14262/// out of the category of the nodes.
14263///
14264/// @param diff_tree the @ref corpus_diff tree to walk.
14265void
14268
14269/// Apply the @ref diff tree filters that have been associated with
14270/// the context of the a given @ref diff, categorize the diff nodes
14271/// subsequently. As a result, the nodes of the @p diff_tree tree are
14272/// going to be properly filtered out at reporting time.
14273///
14274/// @param diff_tree the @ref diff instance to consider.
14275void
14277{
14278 if (!diff_tree)
14279 return;
14280
14281 diff_context_sptr ctxt = diff_tree->context();
14282 ABG_ASSERT(ctxt);
14283
14284 if (!ctxt->perform_change_categorization())
14285 return;
14286
14287 // Suppression specifications must be applied after redundancy
14288 // categorization because the suppression propagation code depends
14289 // on redundancy categorization being set first. And of course,
14290 // redundancy categorization depends on the initial categorization.
14291 // So that order matters.
14292 ctxt->maybe_apply_filters(diff_tree);
14293 categorize_redundancy(diff_tree);
14294 apply_suppressions(diff_tree);
14295}
14296
14297/// Apply the @ref diff tree filters that have been associated with
14298/// the context of the a given @ref corpus_diff, categorize the diff
14299/// nodes subsequently. As a result, the nodes of the @p c tree are
14300/// going to be properly filtered out at reporting time.
14301///
14302/// @param c the @ref corpus_diff instance to consider.
14303void
14305{
14306 if (c)
14307 c->apply_filters_and_suppressions_before_reporting();
14308}
14309
14310/// Test if a diff node represents the difference between a variadic
14311/// parameter type and something else.
14312///
14313/// @param d the diff node to consider.
14314///
14315/// @return true iff @p d is a diff node that represents the
14316/// difference between a variadic parameter type and something else.
14317bool
14319{
14320 if (!d)
14321 return false;
14322
14323 type_base_sptr t = is_type(d->first_subject());
14324 if (t && t->get_environment().is_variadic_parameter_type(t))
14325 return true;
14326
14327 t = is_type(d->second_subject());
14328 if (t && t->get_environment().is_variadic_parameter_type(t))
14329 return true;
14330
14331 return false;
14332}
14333
14334/// Test if a diff node represents the difference between a variadic
14335/// parameter type and something else.
14336///
14337/// @param d the diff node to consider.
14338///
14339/// @return true iff @p d is a diff node that represents the
14340/// difference between a variadic parameter type and something else.
14341bool
14344
14345/// Test if a diff node represents the difference between a variadic
14346/// parameter and something else.
14347///
14348/// @param d the diff node to consider.
14349///
14350/// @return true iff @p d is a diff node that represents the
14351/// difference between a variadic parameter and something else.
14352bool
14354{
14356 dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
14357 return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
14358}
14359
14360/// Test if a diff node represents the difference between a variadic
14361/// parameter and something else.
14362///
14363/// @param d the diff node to consider.
14364///
14365/// @return true iff @p d is a diff node that represents the
14366/// difference between a variadic parameter and something else.
14367bool
14370
14371/// Test if a diff node represents a diff between two basic types.
14372///
14373/// @param d the diff node to consider.
14374///
14375/// @return true iff @p d is a diff between two basic types.
14376const type_decl_diff*
14378{return dynamic_cast<const type_decl_diff*>(d);}
14379
14380/// Test if a diff node represents a diff between two basic types, or
14381/// between pointers, references or qualified type to basic types.
14382///
14383/// @param diff the diff node to consider.
14384///
14385/// @param allow_indirect_type if true, then this function looks into
14386/// pointer, reference or qualified diff types to see if they "point
14387/// to" basic types.
14388///
14389/// @return true iff @p d is a diff between two basic types.
14390const type_decl_diff*
14391is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
14392{
14393 if (allow_indirect_type)
14396}
14397
14398/// If a diff node is about changes between two typedef types, get the
14399/// diff node about changes between the underlying types.
14400///
14401/// Note that this function walks the tree of underlying diff nodes
14402/// returns the first diff node about types that are not typedefs.
14403///
14404/// @param dif the dif node to consider.
14405///
14406/// @return the underlying diff node of @p dif, or just return @p dif
14407/// if it's not a typedef diff node.
14408const diff*
14410{
14411 const typedef_diff *d = 0;
14412 while ((d = is_typedef_diff(dif)))
14413 dif = d->underlying_type_diff().get();
14414 return dif;
14415}
14416
14417/// If a diff node is about changes between two pointer types, get the
14418/// diff node about changes between the underlying (pointed-to) types.
14419///
14420/// Note that this function walks the tree of underlying diff nodes
14421/// returns the first diff node about types that are not pointers.
14422///
14423/// @param dif the dif node to consider.
14424///
14425/// @return the underlying diff node of @p dif, or just return @p dif
14426/// if it's not a pointer diff node.
14427const diff*
14429{
14430 const pointer_diff *d = 0;
14431 while ((d = is_pointer_diff(dif)))
14432 dif = d->underlying_type_diff().get();
14433 return dif;
14434}
14435
14436/// If a diff node is about changes between two reference types, get
14437/// the diff node about changes between the underlying (pointed-to)
14438/// types.
14439///
14440/// Note that this function walks the tree of underlying diff nodes
14441/// returns the first diff node about types that are not references.
14442///
14443/// @param dif the dif node to consider.
14444///
14445/// @return the underlying diff node of @p dif, or just return @p dif
14446/// if it's not a reference diff node.
14447const diff*
14449{
14450 const reference_diff *d = 0;
14451 while ((d = is_reference_diff(dif)))
14452 dif = d->underlying_type_diff().get();
14453 return dif;
14454}
14455
14456/// If a diff node is about changes between two qualified types, get
14457/// the diff node about changes between the underlying (non-qualified)
14458/// types.
14459///
14460/// Note that this function walks the tree of underlying diff nodes
14461/// returns the first diff node about types that are not qualified.
14462///
14463/// @param dif the dif node to consider.
14464///
14465/// @return the underlying diff node of @p dif, or just return @p dif
14466/// if it's not a qualified diff node.
14467const diff*
14469{
14470 const qualified_type_diff *d = 0;
14471 while ((d = is_qualified_type_diff(dif)))
14472 dif = d->underlying_type_diff().get();
14473 return dif;
14474}
14475
14476/// If a diff node is about changes between two function parameters
14477/// get the diff node about changes between the types of the parameters.
14478///
14479/// @param dif the dif node to consider.
14480///
14481/// @return the diff of the types of the parameters.
14482const diff*
14484{
14485 const fn_parm_diff *d = 0;
14486 while ((d = is_fn_parm_diff(dif)))
14487 dif = d->type_diff().get();
14488 return dif;
14489}
14490
14491/// If a diff node is about changes between two pointer, reference or
14492/// qualified types, get the diff node about changes between the
14493/// underlying types.
14494///
14495/// Note that this function walks the tree of underlying diff nodes
14496/// returns the first diff node about types that are not pointer,
14497/// reference or qualified.
14498///
14499/// @param dif the dif node to consider.
14500///
14501/// @return the underlying diff node of @p dif, or just return @p dif
14502/// if it's not a pointer, reference or qualified diff node.
14503const diff*
14505{
14506 while (true)
14507 {
14508 if (const pointer_diff *d = is_pointer_diff(dif))
14509 dif = peel_pointer_diff(d);
14510 else if (const reference_diff *d = is_reference_diff(dif))
14511 dif = peel_reference_diff(d);
14512 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14513 dif = peel_qualified_diff(d);
14514 else
14515 break;
14516 }
14517 return dif;
14518}
14519
14520/// If a diff node is about changes between two typedefs or qualified
14521/// types, get the diff node about changes between the underlying
14522/// types.
14523///
14524/// Note that this function walks the tree of underlying diff nodes
14525/// returns the first diff node about types that are not typedef or
14526/// qualified types.
14527///
14528/// @param dif the dif node to consider.
14529///
14530/// @return the underlying diff node of @p dif, or just return @p dif
14531/// if it's not typedef or qualified diff node.
14532const diff*
14534{
14535 while (true)
14536 {
14537 if (const typedef_diff *d = is_typedef_diff(dif))
14538 dif = peel_typedef_diff(d);
14539 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14540 dif = peel_qualified_diff(d);
14541 else
14542 break;
14543 }
14544 return dif;
14545}
14546
14547/// If a diff node is about changes between two typedefs or qualified
14548/// types, get the diff node about changes between the underlying
14549/// types.
14550///
14551/// Note that this function walks the tree of underlying diff nodes
14552/// returns the first diff node about types that are neither typedef,
14553/// qualified type nor parameters.
14554///
14555/// @param dif the dif node to consider.
14556///
14557/// @return the diff node about changes between the underlying types.
14558const diff*
14560{
14561 while (true)
14562 {
14563 if (const typedef_diff *d = is_typedef_diff(dif))
14564 dif = peel_typedef_diff(d);
14565 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14566 dif = peel_qualified_diff(d);
14567 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
14568 dif = peel_fn_parm_diff(d);
14569 else
14570 break;
14571 }
14572 return dif;
14573}
14574
14575/// Test if a diff node represents a diff between two class or union
14576/// types.
14577///
14578/// @param d the diff node to consider.
14579///
14580/// @return iff @p is a diff between two class or union types then
14581/// return the instance of @ref class_or_union_diff that @p derives
14582/// from. Otherwise, return nil.
14585{return dynamic_cast<const class_or_union_diff*>(d);}
14586
14587/// Test if a given diff node carries *only* a local type change.
14588///
14589/// @param d the diff node to consider.
14590///
14591/// @return true iff @p has a change and that change is a local type
14592/// change.
14593static bool
14594has_local_type_change_only(const diff *d)
14595{
14596 if (enum change_kind k = d->has_local_changes())
14597 if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
14598 && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
14599 return true;
14600
14601 return false;
14602}
14603
14604/// Test if a diff node is a decl diff that only carries a basic type
14605/// change on its type diff sub-node.
14606///
14607///Note that that pointers/references/qualified types diffs to basic
14608/// type diffs are considered as having basic type change only.
14609///
14610/// @param d the diff node to consider.
14611///
14612/// @return true iff @p d is a decl diff that only carries a basic
14613/// type change on its type diff sub-node.
14614bool
14616{
14618
14619 if (is_diff_of_basic_type(d, true) && d->has_changes())
14620 return true;
14621 else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
14622 return (has_local_type_change_only(v)
14623 && is_diff_of_basic_type(v->type_diff().get(), true));
14624 else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
14625 return (has_local_type_change_only(p)
14626 && is_diff_of_basic_type(p->type_diff().get(), true));
14627 else if (const function_decl_diff* f =
14628 dynamic_cast<const function_decl_diff*>(d))
14629 return (has_local_type_change_only(f)
14630 && f->type_diff()
14631 && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
14632 true));
14633 return false;
14634}
14635}// end namespace comparison
14636} // 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:1790
This contains the private implementation of the suppression engine of libabigail.
#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, vector< subrange_diff_sptr > &subrange_diffs, diff_context_sptr ctxt=diff_context_sptr())
Constructor for array_diff.
bool any_subrange_diff_to_be_reported() const
Test if any subrange diff is to be reported.
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
const vector< subrange_diff_sptr > & subrange_diffs() const
Getter for the diffs between the array subranges.
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 unsigned_var_diff_sptr_map & changed_data_members() const
Getter of the map of data members that got replaced by another data member. The key of the map is the...
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 num_var_with_incompatible_changes() const
Getter for the number of variables with incompatible changes.
size_t net_num_leaf_func_non_incompatible_changes() const
Getter for the net number of leaf function diff nodes that carry changes that are NOT incompatible.
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 net_num_non_incompatible_var_changed() const
Getter of the net number of variables with changes that are not incompatible.
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 num_leaf_func_with_incompatible_changes() const
Getter for the number of leaf function diff nodes that carry incompatible changes.
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 num_func_with_local_harmful_changes() const
Getter for the number of functions with local harmful changes.
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 num_func_with_incompatible_changes() const
Getter for the number of functions with incompatible changes.
size_t net_num_non_incompatible_func_changed() const
Getter of the net number of functions with changes that are not incompatible.
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 net_num_leaf_var_non_incompatible_changes() const
Getter for the net number of leaf variable diff nodes that carry changes that are NOT incompatible.
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_var_with_incompatible_changes() const
Getter for the number of leaf variable diff nodes that carry incompatible changes.
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 num_var_with_local_harmful_changes() const
Getter for the number of variables with local harmful changes.
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.
const istring_functions_set_map_type & added_functions()
Getter for the added functions of the diff.
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.
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.
const string_function_decl_diff_sptr_map & changed_functions() const
Getter for the functions which signature didn't change, but which do have some indirect changes in th...
const var_diff_sptrs_type & incompatible_changed_variables() const
Getter of the set of diff nodes representing incompatibly changed global variables.
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()
Mark leaf nodes and apply the different filters that are registered to be applied to the diff tree; t...
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...
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.
const function_decl_diff_sptrs_type & incompatible_changed_functions() const
Getter of the set of diff nodes representing incompatibly changed functions.
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 istring_functions_set_omap_type & deleted_functions() const
Getter for the deleted functions of the diff.
const string & get_pretty_representation() const
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 function_decl_diff_sptrs_type & changed_functions_sorted() const
Getter for a sorted vector of functions which signature didn't change, but which do have some indirec...
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.
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.
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_num_filtered_data_members() const
Get whether to show the number of filtered data members.
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 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 ...
bool is_categorized_as_suppressed() const
Test if the current diff node has been suppressed by a suppression specification or it has been categ...
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.
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.
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.
The abstraction of a diff between two ptr_to_mbr_type.
virtual bool has_changes() const
Test whether the current 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 ptr_to_mbr_...
virtual ~ptr_to_mbr_diff()
Destructor of ptr_to_mbr_diff.
ptr_to_mbr_type_sptr first_ptr_to_mbr_type() const
Getter of the first pointer-to-member subject of the current diff node.
const diff_sptr containing_type_diff() const
Getter of the diff node carrying changes to the containing type of first subject of the current diff ...
const diff_sptr member_type_diff() const
Getter of the diff node carrying changes to the member type of first subject of the current diff node...
ptr_to_mbr_type_sptr second_ptr_to_mbr_type() const
Getter of the second pointer-to-member subject of the current diff node.
virtual enum change_kind has_local_changes() const
Test whether the current diff node carries any local change.
virtual const string & get_pretty_representation() const
Get the pretty representation of the current ptr_to_mbr_diff node.
virtual void report(ostream &, const string &indent="") const
Pure interface to report the diff in a serialized form that is legible for the user.
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.
The abstraction of an interned string.
shared_ptr< subrange_type > subrange_sptr
Convenience typedef for a shared pointer on a function_decl::subrange.
Definition abg-ir.h:2570
shared_ptr< base_spec > base_spec_sptr
Convenience typedef.
Definition abg-ir.h:4229
vector< base_spec_sptr > base_specs
Convenience typedef.
Definition abg-ir.h:4230
vector< method_decl_sptr > member_functions
Convenience typedef.
Definition abg-ir.h:4027
bool get_is_anonymous() const
Test if the current declaration is anonymous.
Definition abg-ir.cc:5774
The abstraction of the version of an ELF symbol.
Definition abg-ir.h:1230
Abstraction of an elf symbol.
Definition abg-ir.h:959
const string & get_id_string() const
Get a string that is representative of a given elf_symbol.
Definition abg-ir.cc:3238
std::vector< enumerator > enumerators
Convenience typedef for a list of enumerator.
Definition abg-ir.h:2812
Abstraction for a function declaration.
Definition abg-ir.h:3167
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition abg-ir.h:3190
const function_type_sptr get_type() const
Return the type of the current instance of function_decl.
Definition abg-ir.cc:23952
const elf_symbol_sptr get_symbol() const
Gets the the underlying ELF symbol for the current variable, that was set using function_decl::set_sy...
Definition abg-ir.cc:24013
An abstraction helper for type declarations.
Definition abg-ir.h:2014
The base class of both types and declarations.
Definition abg-ir.h:1378
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.
bool has_void_ptr_to_ptr_change(const diff *dif)
Test if a diff node carries a void* to pointer type change.
diff_category has_fn_return_or_parm_harmful_change(const diff *d)
Test if a diff node is a function diff node that carries either a return or a parameter type change t...
diff_category has_var_harmful_local_change(const diff *d)
Test if a diff node carries a harmful local change to a variable.
std::vector< filter_base_sptr > filters
Convenience typedef for a vector of filter_base_sptr.
bool has_fn_with_virtual_offset_change(const diff *d)
Test if a diff node carries a change to the offset of a virtual function.
bool has_harmless_enum_to_int_change(const diff *diff)
Test if a diff node carries a harmless change of an enum into an integer (or vice-versa).
bool is_harmful_name_change(const decl_base_sptr &f, const decl_base_sptr &s, const diff_context_sptr &ctxt)
Test if two decls represent a harmful name change.
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_benign_array_of_unknown_size_change(const diff *dif)
Test if a diff node carries a benign change to the size of a variable of type array.
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_harmful_category(diff_category c)
Test if an instance of diff_category (a category bit-field) is harmful or not.
shared_ptr< diff > diff_sptr
Convenience typedef for a shared_ptr for the diff class.
Definition abg-fwd.h:75
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*.
shared_ptr< decl_diff_base > decl_diff_base_sptr
Convenience typedef for a shared_ptr of decl_diff_base.
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.
@ NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY
A change between two non-compatible types of different kinds.
@ 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...
@ NON_COMPATIBLE_NAME_CHANGE_CATEGORY
A non-compatible name change between two types.
@ 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_UNION_OR_CLASS_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless union or class change.
@ HARMLESS_DECL_NAME_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless declaration name change....
@ NO_CHANGE_CATEGORY
This means the diff node does not carry any (meaningful) change, or that it carries changes that have...
@ 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.
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 subrange_diff * is_anonymous_subrange_diff(const diff *d)
Test if a diff node is a subrange_diff between two anonymous subranges.
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.
void sort_string_function_ptr_map(const string_function_ptr_map &map, vector< const function_decl * > &sorted)
Sort an instance of string_function_ptr_map map and stuff a resulting sorted vector of pointers to fu...
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_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.
void print_category(diff_category c)
Print a given category out to stdout for debuging purposes.
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:67
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.
shared_ptr< function_decl_diff > function_decl_diff_sptr
Convenience typedef for a shared pointer to a function_decl type.
shared_ptr< ptr_to_mbr_diff > ptr_to_mbr_diff_sptr
Typedef of a shared_ptr to ptr_to_mbr_diff.
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_less_than(const decl_diff_base &first, const decl_diff_base &second)
Compare two decl diff nodes (decl_diff_base) for the purpose of sorting.
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.
void sort_function_decl_diffs(function_decl_diff_sptrs_type &fn_diffs)
Sort a vector of function_decl_diff_sptr.
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.
unordered_map< string, var_decl_sptr > string_var_ptr_map
Convenience typedef for a map which key is a string and which value is a point to var_decl.
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.
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 sort_string_var_ptr_map(const string_var_ptr_map &map, vector< var_decl_sptr > &sorted)
Sort a map of string -> pointer to var_decl.
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.
void sort_var_diffs(var_diff_sptrs_type &var_diffs)
Sort a vector of var_diff_sptr.
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.
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...
void apply_filters_and_categorize_diff_node_tree(diff_sptr &diff_tree)
Apply the diff tree filters that have been associated with the context of the a given diff,...
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.
unordered_map< string, const 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.
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 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:236
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition abg-ir.cc:7544
bool equals(const decl_base &l, const decl_base &r, change_kind *k, bool qualified_name, bool linkage_name)
Compares two instances of decl_base.
Definition abg-ir.cc:6243
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:6684
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition abg-fwd.h:273
const global_scope_sptr get_global_scope(decl_base_sptr decl)
Return the global scope as seen by a given declaration.
Definition abg-ir.cc:9734
interned_string get_function_symbol_id(const function_decl *fn)
Get the ID of the symbol of a function or the linkage name of the function if it has no symbol.
Definition abg-ir.cc:10386
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:12031
bool is_anonymous_data_member(const decl_base &d)
Test if a decl is an anonymous data member.
Definition abg-ir.cc:6957
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:13446
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition abg-ir.h:924
change_kind
A bitfield that gives callers of abigail::ir::equals() some insight about how different two internal ...
Definition abg-ir.h:1332
@ LOCAL_TYPE_CHANGE_KIND
This means that a given IR artifact has a local type change.
Definition abg-ir.h:1336
@ ALL_LOCAL_CHANGES_MASK
Testing (anding) against this mask means that a given IR artifact has local differences,...
Definition abg-ir.h:1347
@ 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:1341
bool is_user_defined_type(const type_base *t)
Test if a type is user-defined.
Definition abg-ir.cc:6588
bool collect_non_anonymous_data_members(const class_or_union *cou, string_decl_base_sptr_map &dms)
Collect all the non-anonymous data members of a class or union type.
Definition abg-ir.cc:6899
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition abg-ir.cc:12395
shared_ptr< array_type_def > array_type_def_sptr
Convenience typedef for a shared pointer on a array_type_def.
Definition abg-fwd.h:245
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:10511
std::vector< elf_symbol_sptr > elf_symbols
Convenience typedef for a vector of elf_symbol.
Definition abg-ir.h:940
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:12626
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:6825
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition abg-fwd.h:194
string get_name(const type_or_decl_base *tod, bool qualified)
Build and return a copy of the name of an ABI artifact that is either a type or a decl.
Definition abg-ir.cc:9888
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition abg-fwd.h:211
shared_ptr< typedef_decl > typedef_decl_sptr
Convenience typedef for a shared pointer on a typedef_decl.
Definition abg-fwd.h:168
std::map< interned_string, functions_set_type > istring_functions_set_omap_type
An ordered map that associates an interned string with a set of hashed function decls.
Definition abg-corpus.h:87
const enum_type_decl * is_enum_type(const type_or_decl_base *d)
Test if a decl is an enum_type_decl.
Definition abg-ir.cc:12330
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:11874
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition abg-fwd.h:257
shared_ptr< ptr_to_mbr_type > ptr_to_mbr_type_sptr
Convenience typedef for a shared pointer to a ptr_to_mbr_type.
Definition abg-fwd.h:240
shared_ptr< scope_decl > scope_decl_sptr
Convenience typedef for a shared pointer on a scope_decl.
Definition abg-fwd.h:265
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:118
shared_ptr< translation_unit > translation_unit_sptr
Convenience typedef for a shared pointer on a translation_unit type.
Definition abg-fwd.h:137
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.
Definition abg-fwd.h:158
shared_ptr< pointer_type_def > pointer_type_def_sptr
Convenience typedef for a shared pointer on a pointer_type_def.
Definition abg-fwd.h:227
bool is_enumerator_present_in_enum(const enum_type_decl::enumerator &enr, const enum_type_decl &enom)
Test if a given enumerator is found present in an enum.
Definition abg-ir.cc:21248
uint64_t get_absolute_data_member_offset(const var_decl &m)
Get the absolute offset of a data member.
Definition abg-ir.cc:7359
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition abg-ir.cc:7454
var_decl * is_var_decl(const type_or_decl_base *tod)
Tests if a declaration is a variable declaration.
Definition abg-ir.cc:13289
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition abg-ir.cc:11971
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition abg-fwd.h:176
uint64_t get_data_member_offset(const var_decl &m)
Get the offset of a data member.
Definition abg-ir.cc:7270
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition abg-ir.cc:7742
class_or_union * anonymous_data_member_to_class_or_union(const var_decl *d)
Get the class_or_union type of a given anonymous data member.
Definition abg-ir.cc:7115
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:13148
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition abg-ir.cc:12675
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition abg-ir.cc:6722
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition abg-ir.cc:11414
unordered_map< interned_string, functions_set_type, hash_interned_string > istring_functions_set_map_type
A map that associates an interned string with a set of hashed function decls.
Definition abg-corpus.h:82
const var_decl * lookup_data_member(const type_base *type, const char *dm_name)
Look for a data member of a given class, struct or union type and return it.
Definition abg-ir.cc:30704
shared_ptr< type_decl > type_decl_sptr
Convenience typedef for a shared pointer on a type_decl.
Definition abg-fwd.h:162
bool is_unique_type(const type_base_sptr &t)
Test if a type is unique in the entire environment.
Definition abg-ir.cc:30242
bool types_are_compatible(const type_base_sptr type1, const type_base_sptr type2)
Test if two types are equal modulo a typedef or CV qualifiers.
Definition abg-ir.cc:11582
function_decl * is_function_decl(const type_or_decl_base *d)
Test whether a declaration is a function_decl.
Definition abg-ir.cc:11919
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:13118
bool class_or_union_types_of_same_kind(const class_or_union *first, const class_or_union *second)
Test if two class or union types are of the same kind.
Definition abg-ir.cc:12647
unordered_set< const function_decl *, c11d_decl_hasher< function_decl >, c11d_decl_eq< function_decl > > functions_set_type
A set of hashed function decls. The hash value is the canonical type of the function....
Definition abg-corpus.h:69
type_base * peel_qualified_or_typedef_type(const type_base *type)
Return the leaf underlying type of a qualified or typedef type.
Definition abg-ir.cc:8451
bool is_at_global_scope(const decl_base &decl)
Tests whether a given declaration is at global scope.
Definition abg-ir.cc:11765
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition abg-ir.cc:6514
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:1734
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_opaque_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:1731
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 try_build_diffs_from_deleted_and_added_fns(functions_set_type &deleted_fns, functions_set_type &added_fns)
This is a sub-routine of ensure_lookup_tables_populated.
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 ...
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.
const string_diff_sptr_map & changed_unreachable_types() const
Get the map of diff nodes representing changed unreachable types.
void add_function_to_deleted_functions(const function_decl *fn)
Add a function_decl* to the 'deleted_fns_' map in the current instance of corpus_diff::priv.
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...
void add_function_to_added_functions(const function_decl *fn)
Add a function_decl* to the 'added_fns_' map in the current instance of corpus_diff::priv.
void maybe_perform_change_categorization()
Apply the diff change categorization filters to the current ABI corpus. As a result,...
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 maybe_perform_redundant_node_categorization()
If diff_context::perform_change_categorization() is true, then perform the redundancy categorization ...
void apply_suppressions(corpus_diff *d)
Apply suppression specifications to a sub-tree of corpus_diff*.
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_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 compare_fns_vars_and_ensure_lookup_tables_populated()
If the lookup tables are not yet built, walk the differences and fill the lookup tables.
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 ...
bool deleted_variable_is_suppressed(const var_decl_sptr &var) const
Test if the change reports for a give given deleted variable has been deleted.
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_variable_is_suppressed(const var_decl_sptr &var) const
Test if the change reports for a given added variable have been suppressed.
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_filters_and_compute_diff_stats(corpus_diff *, corpus_diff::diff_stats &)
Compute the diff stats.
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 private data of the ptr_to_mbr_diff type.
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...
A functor to sort decls somewhat topologically. That is, types are sorted in a way that makes the one...
A comparison functor to compare pointer to instances of type_or_decl_base.
Definition abg-ir.h:3303
A deleter for shared pointers that ... doesn't delete the object managed by the shared pointer.