libabigail
abg-comparison.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2// -*- Mode: C++ -*-
3//
4// Copyright (C) 2013-2025 Red Hat, Inc.
5//
6// Author: Dodji Seketeli
7
8/// @file
9///
10/// This contains the implementation of the comparison engine of
11/// libabigail.
12
13#include <ctype.h>
14#include <libgen.h>
15#include <algorithm>
16#include <sstream>
17#include <set>
18
19#include "abg-comparison-priv.h"
20#include "abg-reporter-priv.h"
21#include "abg-tools-utils.h"
22
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
1017{return diff && is_fn_parm_diff(diff->parent_node());}
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
1026{return diff && is_base_diff(diff->parent_node());}
1027
1028/// The default traverse function.
1029///
1030/// @return true.
1031bool
1033{return true;}
1034
1035diff_context::diff_context()
1036 : priv_(new diff_context::priv)
1037{
1038 // Setup all the diff output filters we have.
1040
1042 add_diff_filter(f);
1043
1044 // f.reset(new filtering::harmless_filter);
1045 // add_diff_filter(f);
1046
1047 // f.reset(new filtering::harmful_filter);
1048 // add_diff_filter(f);
1049}
1050
1051diff_context::~diff_context() = default;
1052
1053/// Test if logging was requested.
1054///
1055/// @return true iff logging was requested.
1056bool
1058{return priv_->do_log_;}
1059
1060/// Set logging as requested.
1061///
1062/// @param f the flag
1063void
1065{priv_->do_log_ = f;}
1066
1067/// Set the corpus diff relevant to this context.
1068///
1069/// @param d the corpus_diff we are interested in.
1070void
1072{priv_->corpus_diff_ = d;}
1073
1074/// Get the corpus diff for the current context.
1075///
1076/// @return the corpus diff of this context.
1077const corpus_diff_sptr&
1079{return priv_->corpus_diff_;}
1080
1081/// Getter for the first corpus of the corpus diff of the current context.
1082///
1083/// @return the first corpus of the corpus diff of the current
1084/// context, if no corpus diff is associated to the context.
1085corpus_sptr
1087{
1088 if (priv_->corpus_diff_)
1089 return priv_->corpus_diff_->first_corpus();
1090 return corpus_sptr();
1091}
1092
1093/// Getter for the second corpus of the corpus diff of the current
1094/// context.
1095///
1096/// @return the second corpus of the corpus diff of the current
1097/// context, if no corpus diff is associated to the context.
1098corpus_sptr
1100{
1101 if (priv_->corpus_diff_)
1102 return priv_->corpus_diff_->second_corpus();
1103 return corpus_sptr();
1104}
1105
1106/// Getter of the reporter to be used in this context.
1107///
1108/// @return the reporter to be used in this context.
1111{
1112 if (!priv_->reporter_)
1113 {
1115 priv_->reporter_.reset(new leaf_reporter);
1116 else
1117 priv_->reporter_.reset(new default_reporter);
1118 }
1119 ABG_ASSERT(priv_->reporter_);
1120 return priv_->reporter_;
1121}
1122
1123/// Setter of the reporter to be used in this context.
1124///
1125/// @param r the reporter to be used in this context.
1126void
1128{priv_->reporter_ = r;}
1129
1130/// Tests if the current diff context already has a diff for two decls.
1131///
1132/// @param first the first decl to consider.
1133///
1134/// @param second the second decl to consider.
1135///
1136/// @return a pointer to the diff for @p first @p second if found,
1137/// null otherwise.
1139diff_context::has_diff_for(const type_or_decl_base_sptr first,
1140 const type_or_decl_base_sptr second) const
1141{
1142 types_or_decls_diff_map_type::const_iterator i =
1143 priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1144 if (i != priv_->types_or_decls_diff_map.end())
1145 return i->second;
1146 return diff_sptr();
1147}
1148
1149/// Tests if the current diff context already has a diff for two types.
1150///
1151/// @param first the first type to consider.
1152///
1153/// @param second the second type to consider.
1154///
1155/// @return a pointer to the diff for @p first @p second if found,
1156/// null otherwise.
1158diff_context::has_diff_for_types(const type_base_sptr first,
1159 const type_base_sptr second) const
1160{return has_diff_for(first, second);}
1161
1162/// Tests if the current diff context already has a given diff.
1163///
1164///@param d the diff to consider.
1165///
1166/// @return a pointer to the diff found for @p d
1167const diff*
1168diff_context::has_diff_for(const diff* d) const
1169{return has_diff_for(d->first_subject(), d->second_subject()).get();}
1170
1171/// Tests if the current diff context already has a given diff.
1172///
1173///@param d the diff to consider.
1174///
1175/// @return a pointer to the diff found for @p d
1177diff_context::has_diff_for(const diff_sptr d) const
1178{return has_diff_for(d->first_subject(), d->second_subject());}
1179
1180/// Getter for the bitmap that represents the set of categories that
1181/// the user wants to see reported.
1182///
1183/// @return a bitmap that represents the set of categories that the
1184/// user wants to see reported.
1187{return priv_->allowed_category_;}
1188
1189/// Setter for the bitmap that represents the set of categories that
1190/// the user wants to see reported.
1191///
1192/// @param c a bitmap that represents the set of categories that the
1193/// user wants to see represented.
1194void
1196{priv_->allowed_category_ = c;}
1197
1198/// Setter for the bitmap that represents the set of categories that
1199/// the user wants to see reported
1200///
1201/// This function perform a bitwise or between the new set of
1202/// categories and the current ones, and then sets the current
1203/// categories to the result of the or.
1204///
1205/// @param c a bitmap that represents the set of categories that the
1206/// user wants to see represented.
1207void
1209{priv_->allowed_category_ = priv_->allowed_category_ | c;}
1210
1211/// Setter for the bitmap that represents the set of categories that
1212/// the user wants to see reported
1213///
1214/// This function actually unsets bits from the current categories.
1215///
1216/// @param c a bitmap that represents the set of categories to unset
1217/// from the current categories.
1218void
1220{priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1221
1222/// Add a diff for two decls to the cache of the current diff_context.
1223///
1224/// Doing this allows to later find the added diff from its two
1225/// subject decls.
1226///
1227/// @param first the first decl to consider.
1228///
1229/// @param second the second decl to consider.
1230///
1231/// @param the diff to add.
1232void
1233diff_context::add_diff(type_or_decl_base_sptr first,
1235 const diff_sptr d)
1236{priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1237
1238/// Add a diff tree node to the cache of the current diff_context
1239///
1240/// @param d the diff tree node to add.
1241void
1242diff_context::add_diff(const diff* d)
1243{
1244 if (d)
1245 {
1246 diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1247 add_diff(d->first_subject(), d->second_subject(), dif);
1248 }
1249}
1250
1251/// Add a diff tree node to the cache of the current diff_context
1252///
1253/// @param d the diff tree node to add.
1254void
1255diff_context::add_diff(const diff_sptr d)
1256{
1257 if (d)
1258 add_diff(d->first_subject(), d->second_subject(), d);
1259}
1260
1261/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1262/// @ref diff represented by their two subjects.
1263///
1264/// @param first the first subject of the diff.
1265///
1266/// @param second the second subject of the diff.
1267///
1268/// @return the canonical diff for the diff node represented by the
1269/// two diff subjects @p first and @p second. If no canonical diff
1270/// node was registered for these subjects, then a nil node is
1271/// returned.
1274 const type_or_decl_base_sptr second) const
1275{return has_diff_for(first, second);}
1276
1277/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1278/// @ref diff represented by the two subjects of a given diff node.
1279///
1280/// @param d the diff node to get the canonical node for.
1281///
1282/// @return the canonical diff for the diff node represented by the
1283/// two diff subjects of @p d. If no canonical diff node was
1284/// registered for these subjects, then a nil node is returned.
1287{return has_diff_for(d);}
1288
1289/// Setter for the @ref CanonicalDiff "canonical diff node" for the
1290/// @ref diff represented by their two subjects.
1291///
1292/// @param first the first subject of the diff.
1293///
1294/// @param second the second subject of the diff.
1295///
1296/// @param d the new canonical diff.
1297void
1298diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1299 const type_or_decl_base_sptr second,
1300 const diff_sptr d)
1301{
1302 ABG_ASSERT(d);
1303 if (!has_diff_for(first, second))
1304 {
1305 add_diff(first, second, d);
1306 priv_->canonical_diffs.push_back(d);
1307 }
1308}
1309
1310/// If there is is a @ref CanonicalDiff "canonical diff node"
1311/// registered for two diff subjects, return it. Otherwise, register
1312/// a canonical diff node for these two diff subjects and return it.
1313///
1314/// @param first the first subject of the diff.
1315///
1316/// @param second the second subject of the diff.
1317///
1318/// @param d the new canonical diff node.
1319///
1320/// @return the canonical diff node.
1322diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1323 const type_or_decl_base_sptr second,
1324 const diff_sptr canonical_diff)
1325{
1326 ABG_ASSERT(canonical_diff);
1327
1328 diff_sptr canonical = get_canonical_diff_for(first, second);
1329 if (!canonical)
1330 {
1331 canonical = canonical_diff;
1332 set_canonical_diff_for(first, second, canonical);
1333 }
1334 return canonical;
1335}
1336
1337/// Set the canonical diff node property of a given diff node
1338/// appropriately.
1339///
1340/// For a given diff node that has no canonical diff node, retrieve
1341/// the canonical diff node (by looking at its diff subjects and at
1342/// the current context) and set the canonical diff node property of
1343/// the diff node to that canonical diff node. If no canonical diff
1344/// node has been registered to the diff context for the subjects of
1345/// the diff node then, register the canonical diff node as being the
1346/// diff node itself; and set its canonical diff node property as
1347/// such. Otherwise, if the diff node already has a canonical diff
1348/// node, do nothing.
1349///
1350/// @param diff the diff node to initialize the canonical diff node
1351/// property for.
1352void
1354{
1355 if (diff->get_canonical_diff() == 0)
1356 {
1357 diff_sptr canonical =
1358 set_or_get_canonical_diff_for(diff->first_subject(),
1360 diff);
1361 diff->set_canonical_diff(canonical.get());
1362 }
1363}
1364
1365/// Add a diff node to the set of diff nodes that are kept alive for
1366/// the life time of the current instance of diff_context.
1367///
1368/// Note that diff added to the diff cache are kept alive as well, and
1369/// don't need to be passed to this function to be kept alive.
1370///
1371/// @param d the diff node to be kept alive during the life time of
1372/// the current instance of @ref diff_context.
1373void
1375{priv_->live_diffs_.insert(d);}
1376
1377/// Test if a diff node has been traversed.
1378///
1379/// @param d the diff node to consider.
1380///
1381/// @return the first diff node against which @p d is redundant.
1382diff*
1384{
1385 const diff* canonical = d->get_canonical_diff();
1386 ABG_ASSERT(canonical);
1387
1388 size_t ptr_value = reinterpret_cast<size_t>(canonical);
1389 pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1390 if (it != priv_->visited_diff_nodes_.end())
1391 return reinterpret_cast<diff*>(it->second);
1392 else
1393 return 0;
1394}
1395
1396/// Test if a diff node has been traversed.
1397///
1398/// @param d the diff node to consider.
1399///
1400/// @return the first diff node against which @p d is redundant.
1403{
1405 return diff;
1406}
1407
1408/// Mark a diff node as traversed by a traversing algorithm.
1409///
1410/// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1411/// node that is marked as traversed.
1412///
1413/// Subsequent invocations of diff_has_been_visited() on the diff node
1414/// will yield true.
1415void
1417{
1418 if (diff_has_been_visited(d))
1419 return;
1420
1421 const diff* canonical = d->get_canonical_diff();
1422 ABG_ASSERT(canonical);
1423
1424 size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1425 size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1426 priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1427}
1428
1429/// Unmark all the diff nodes that were marked as being traversed.
1430void
1432{priv_->visited_diff_nodes_.clear();}
1433
1434/// This sets a flag that, if it's true, then during the traversing of
1435/// a diff nodes tree each node is visited at most once.
1436///
1437/// @param f if true then during the traversing of a diff nodes tree
1438/// each node is visited at most once.
1439///
1440void
1442{priv_->forbid_visiting_a_node_twice_ = f;}
1443
1444/// This function sets a flag os that if @ref
1445/// forbid_visiting_a_node_twice() returns true, then each time the
1446/// node visitor starts visiting a new interface, it resets the
1447/// memory the systems has about already visited node.
1448///
1449/// @param f the flag to set.
1450void
1452{priv_->reset_visited_diffs_for_each_interface_ = f;}
1453
1454/// Return a flag that, if true, then during the traversing of a diff
1455/// nodes tree each node is visited at most once.
1456///
1457/// @return the boolean flag.
1458bool
1460{return priv_->forbid_visiting_a_node_twice_;}
1461
1462/// Return a flag that, if true, then during the traversing of a diff
1463/// nodes tree each node is visited at most once, while visiting the
1464/// diff tree underneath a given interface (public function or
1465/// variable). Each time a new interface is visited, the nodes
1466/// visited while visiting previous interfaces can be visited again.
1467///
1468/// @return the boolean flag.
1469///
1470/// @return the boolean flag.
1471bool
1473{
1474 return (priv_->forbid_visiting_a_node_twice_
1475 && priv_->reset_visited_diffs_for_each_interface_);
1476}
1477
1478/// Getter for the diff tree nodes filters to apply to diff sub-trees.
1479///
1480/// @return the vector of tree filters to apply to diff sub-trees.
1481const filtering::filters&
1483{return priv_->filters_;}
1484
1485/// Setter for the diff filters to apply to a given diff sub-tree.
1486///
1487/// @param f the new diff filter to add to the vector of diff filters
1488/// to apply to diff sub-trees.
1489void
1491{priv_->filters_.push_back(f);}
1492
1493/// Apply the diff filters to a given diff sub-tree.
1494///
1495/// If the current context is instructed to filter out some categories
1496/// then this function walks the given sub-tree and categorizes its
1497/// nodes by using the filters held by the context.
1498///
1499/// @param diff the diff sub-tree to apply the filters to.
1500void
1502{
1503 if (!diff)
1504 return;
1505
1506 if (!diff->has_changes())
1507 return;
1508
1509 for (filtering::filters::const_iterator i = diff_filters().begin();
1510 i != diff_filters().end();
1511 ++i)
1512 {
1514 if (do_log())
1515 {
1516 std::cerr << "applying a filter to diff '"
1518 << "'...\n";
1519 t.start();
1520 }
1521
1523
1524 if (do_log())
1525 {
1526 t.stop();
1527 std::cerr << "filter applied!:" << t << "\n";
1528
1529 std::cerr << "propagating categories for the same diff node ... \n";
1530 t.start();
1531 }
1532
1534
1535 if (do_log())
1536 {
1537 t.stop();
1538 std::cerr << "category propagated!: " << t << "\n";
1539 }
1540 }
1541
1542 }
1543
1544/// Apply the diff filters to the diff nodes of a @ref corpus_diff
1545/// instance.
1546///
1547/// If the current context is instructed to filter out some categories
1548/// then this function walks the diff tree and categorizes its nodes
1549/// by using the filters held by the context.
1550///
1551/// @param diff the corpus diff to apply the filters to.
1552void
1554{
1555
1556 if (!diff || !diff->has_changes())
1557 return;
1558
1559 for (filtering::filters::const_iterator i = diff_filters().begin();
1560 i != diff_filters().end();
1561 ++i)
1562 {
1565 }
1566}
1567
1568/// Getter for the vector of suppressions that specify which diff node
1569/// reports should be dropped on the floor.
1570///
1571/// @return the set of suppressions.
1572const suppressions_type&
1574{return priv_->suppressions_;}
1575
1576/// Getter for the vector of suppressions that specify which diff node
1577/// reports should be dropped on the floor.
1578///
1579/// @return the set of suppressions.
1582{
1583 // Invalidate negated and direct suppressions caches that are built
1584 // from priv_->suppressions_;
1585 priv_->negated_suppressions_.clear();
1586 priv_->direct_suppressions_.clear();
1587 return priv_->suppressions_;
1588}
1589
1590/// Getter of the negated suppression specifications that are
1591/// comprised in the general vector of suppression specifications
1592/// returned by diff_context::suppressions().
1593///
1594/// Note that the first invocation of this function scans the vector
1595/// returned by diff_context::suppressions() and caches the negated
1596/// suppressions from there.
1597///
1598/// Subsequent invocations of this function just return the cached
1599/// negated suppressions.
1600///
1601/// @return the negated suppression specifications stored in this diff
1602/// context.
1605{
1606 if (priv_->negated_suppressions_.empty())
1607 for (auto s : suppressions())
1609 priv_->negated_suppressions_.push_back(s);
1610
1611 return priv_->negated_suppressions_;
1612}
1613
1614/// Getter of the direct suppression specification (those that are
1615/// not negated) comprised in the general vector of suppression
1616/// specifications returned by diff_context::suppression().
1617///
1618/// Note that the first invocation of this function scans the vector
1619/// returned by diff_context::suppressions() and caches the direct
1620/// suppressions from there.
1621///
1622/// Subsequent invocations of this function just return the cached
1623/// direct suppressions.
1624///
1625/// @return the direct suppression specifications.
1628{
1629 if (priv_->direct_suppressions_.empty())
1630 {
1631 for (auto s : suppressions())
1632 if (!is_negated_suppression(s))
1633 priv_->direct_suppressions_.push_back(s);
1634 }
1635 return priv_->direct_suppressions_;
1636}
1637
1638/// Add a new suppression specification that specifies which diff node
1639/// reports should be dropped on the floor.
1640///
1641/// @param suppr the new suppression specification to add to the
1642/// existing set of suppressions specifications of the diff context.
1643void
1645{
1646 priv_->suppressions_.push_back(suppr);
1647 // Invalidate negated and direct suppressions caches that are built
1648 // from priv_->suppressions_;
1649 priv_->negated_suppressions_.clear();
1650 priv_->direct_suppressions_.clear();
1651}
1652
1653/// Add new suppression specifications that specify which diff node
1654/// reports should be dropped on the floor.
1655///
1656/// @param supprs the new suppression specifications to add to the
1657/// existing set of suppression specifications of the diff context.
1658void
1660{
1661 priv_->suppressions_.insert(priv_->suppressions_.end(),
1662 supprs.begin(), supprs.end());
1663}
1664
1665/// Test if it's requested to perform diff node categorization.
1666///
1667/// @return true iff it's requested to perform diff node
1668/// categorization.
1669bool
1671{return priv_->perform_change_categorization_;}
1672
1673/// Request change categorization or not.
1674///
1675/// @param f true iff change categorization is requested.
1676void
1678{priv_->perform_change_categorization_ = f;}
1679
1680/// Set the flag that indicates if the diff using this context should
1681/// show only leaf changes or not.
1682///
1683/// @param f the new value of the flag that indicates if the diff
1684/// using this context should show only leaf changes or not.
1685void
1687{
1688 // This function can be called only if the reporter hasn't yet been
1689 // created. Once it's been created, we are supposed to live with
1690 // it.
1691 ABG_ASSERT(priv_->reporter_ == 0);
1692 priv_->leaf_changes_only_ = f;
1693}
1694
1695/// Get the flag that indicates if the diff using this context should
1696/// show only leaf changes or not.
1697///
1698/// @return the value of the flag that indicates if the diff using
1699/// this context should show only leaf changes or not.
1700bool
1702{return priv_->leaf_changes_only_;}
1703
1704/// Get the flag that indicates if the diff reports using this context
1705/// should show sizes and offsets in an hexadecimal base or not. If
1706/// not, then they are to be shown in a decimal base.
1707///
1708/// @return true iff sizes and offsets are to be shown in an
1709/// hexadecimal base.
1710bool
1712{return priv_->hex_values_;}
1713
1714/// Set the flag that indicates if diff reports using this context
1715/// should show sizes and offsets in an hexadecimal base or not. If
1716/// not, then they are to be shown in a decimal base.
1717///
1718/// @param f if true then sizes and offsets are to be shown in an
1719/// hexadecimal base.
1720void
1722{priv_->hex_values_ = f;}
1723
1724/// Get the flag that indicates if diff reports using this context
1725/// should show sizes and offsets in bits, rather than bytes.
1726///
1727/// @return true iff sizes and offsets are to be shown in bits.
1728/// Otherwise they are to be shown in bytes.
1729bool
1731{return priv_->show_offsets_sizes_in_bits_;}
1732
1733/// Set the flag that indicates if diff reports using this context
1734/// should show sizes and offsets in bits, rather than bytes.
1735///
1736/// @param f if true then sizes and offsets are to be shown in bits.
1737/// Otherwise they are to be shown in bytes.
1738void
1740{priv_->show_offsets_sizes_in_bits_ = f;}
1741
1742/// Set a flag saying if offset changes should be reported in a
1743/// relative way. That is, if the report should say how of many bits
1744/// a class/struct data member did move.
1745///
1746/// @param f the new boolean value of the flag.
1747void
1749{priv_->show_relative_offset_changes_ = f;}
1750
1751/// Get the flag saying if offset changes should be reported in a
1752/// relative way. That is, if the report should say how of many bits
1753/// a class/struct data member did move.
1754///
1755/// @return the boolean value of the flag.
1756bool
1758{return priv_->show_relative_offset_changes_;}
1759
1760/// Set a flag saying if the comparison module should only show the
1761/// diff stats.
1762///
1763/// @param f the flag to set.
1764void
1766{priv_->show_stats_only_ = f;}
1767
1768/// Test if the comparison module should only show the diff stats.
1769///
1770/// @return true if the comparison module should only show the diff
1771/// stats, false otherwise.
1772bool
1774{return priv_->show_stats_only_;}
1775
1776/// Setter for the property that says if the comparison module should
1777/// show the soname changes in its report.
1778///
1779/// @param f the new value of the property.
1780void
1782{priv_->show_soname_change_ = f;}
1783
1784/// Getter for the property that says if the comparison module should
1785/// show the soname changes in its report.
1786///
1787/// @return the value of the property.
1788bool
1790{return priv_->show_soname_change_;}
1791
1792/// Setter for the property that says if the comparison module should
1793/// show the architecture changes in its report.
1794///
1795/// @param f the new value of the property.
1796void
1798{priv_->show_architecture_change_ = f;}
1799
1800/// Getter for the property that says if the comparison module should
1801/// show the architecture changes in its report.
1802///
1803/// @return the value of the property.
1804bool
1806{return priv_->show_architecture_change_;}
1807
1808/// Set a flag saying to show the deleted functions.
1809///
1810/// @param f true to show deleted functions.
1811void
1813{priv_->show_deleted_fns_ = f;}
1814
1815/// @return true if we want to show the deleted functions, false
1816/// otherwise.
1817bool
1819{return priv_->show_deleted_fns_;}
1820
1821/// Set a flag saying to show the changed functions.
1822///
1823/// @param f true to show the changed functions.
1824void
1826{priv_->show_changed_fns_ = f;}
1827
1828/// @return true if we want to show the changed functions, false otherwise.
1829bool
1831{return priv_->show_changed_fns_;}
1832
1833/// Set a flag saying to show the added functions.
1834///
1835/// @param f true to show the added functions.
1836void
1838{priv_->show_added_fns_ = f;}
1839
1840/// @return true if we want to show the added functions, false
1841/// otherwise.
1842bool
1844{return priv_->show_added_fns_;}
1845
1846/// Set a flag saying to show the deleted variables.
1847///
1848/// @param f true to show the deleted variables.
1849void
1851{priv_->show_deleted_vars_ = f;}
1852
1853/// @return true if we want to show the deleted variables, false
1854/// otherwise.
1855bool
1857{return priv_->show_deleted_vars_;}
1858
1859/// Set a flag saying to show the changed variables.
1860///
1861/// @param f true to show the changed variables.
1862void
1864{priv_->show_changed_vars_ = f;}
1865
1866/// @return true if we want to show the changed variables, false otherwise.
1867bool
1869{return priv_->show_changed_vars_;}
1870
1871/// Set a flag saying to show the added variables.
1872///
1873/// @param f true to show the added variables.
1874void
1876{priv_->show_added_vars_ = f;}
1877
1878/// @return true if we want to show the added variables, false
1879/// otherwise.
1880bool
1882{return priv_->show_added_vars_;}
1883
1884bool
1885diff_context::show_linkage_names() const
1886{return priv_->show_linkage_names_;}
1887
1888void
1889diff_context::show_linkage_names(bool f)
1890{priv_->show_linkage_names_= f;}
1891
1892/// Set a flag saying to show location information.
1893///
1894/// @param f true to show location information.
1895void
1897{priv_->show_locs_= f;}
1898
1899/// @return true if we want to show location information, false
1900/// otherwise.
1901bool
1903{return priv_->show_locs_;}
1904
1905/// A getter for the flag that says if we should report about
1906/// functions or variables diff nodes that have *exclusively*
1907/// redundant diff tree children nodes.
1908///
1909/// @return the flag.
1910bool
1912{return priv_->show_redundant_changes_;}
1913
1914/// A setter for the flag that says if we should report about
1915/// functions or variables diff nodes that have *exclusively*
1916/// redundant diff tree children nodes.
1917///
1918/// @param f the flag to set.
1919void
1921{priv_->show_redundant_changes_ = f;}
1922
1923/// Getter for the flag that indicates if symbols not referenced by
1924/// any debug info are to be compared and reported about.
1925///
1926/// @return the boolean flag.
1927bool
1929{return priv_->show_syms_unreferenced_by_di_;}
1930
1931/// Setter for the flag that indicates if symbols not referenced by
1932/// any debug info are to be compared and reported about.
1933///
1934/// @param f the new flag to set.
1935void
1937{priv_->show_syms_unreferenced_by_di_ = f;}
1938
1939/// Getter for the flag that indicates if symbols not referenced by
1940/// any debug info and that got added are to be reported about.
1941///
1942/// @return true iff symbols not referenced by any debug info and that
1943/// got added are to be reported about.
1944bool
1946{return priv_->show_added_syms_unreferenced_by_di_;}
1947
1948/// Setter for the flag that indicates if symbols not referenced by
1949/// any debug info and that got added are to be reported about.
1950///
1951/// @param f the new flag that says if symbols not referenced by any
1952/// debug info and that got added are to be reported about.
1953void
1955{priv_->show_added_syms_unreferenced_by_di_ = f;}
1956
1957/// Setter for the flag that indicates if changes on types unreachable
1958/// from global functions and variables are to be reported.
1959///
1960/// @param f if true, then changes on types unreachable from global
1961/// functions and variables are to be reported.
1962void
1964{priv_->show_unreachable_types_ = f;}
1965
1966/// Getter for the flag that indicates if changes on types unreachable
1967/// from global functions and variables are to be reported.
1968///
1969/// @return true iff changes on types unreachable from global
1970/// functions and variables are to be reported.
1971bool
1973{return priv_->show_unreachable_types_;}
1974
1975/// Getter of the flag that indicates if the leaf reporter should
1976/// display a summary of the interfaces impacted by a given leaf
1977/// change or not.
1978///
1979/// @return the flag that indicates if the leaf reporter should
1980/// display a summary of the interfaces impacted by a given leaf
1981/// change or not.
1982bool
1984{return priv_->show_impacted_interfaces_;}
1985
1986/// Setter of the flag that indicates if the leaf reporter should
1987/// display a summary of the interfaces impacted by a given leaf
1988/// change or not.
1989///
1990/// @param f the new value of the flag that indicates if the leaf
1991/// reporter should display a summary of the interfaces impacted by a
1992/// given leaf change or not.
1993void
1995{priv_->show_impacted_interfaces_ = f;}
1996
1997/// Setter for the default output stream used by code of the
1998/// comparison engine. By default the default output stream is a NULL
1999/// pointer.
2000///
2001/// @param o a pointer to the default output stream.
2002void
2004{priv_->default_output_stream_ = o;}
2005
2006/// Getter for the default output stream used by code of the
2007/// comparison engine. By default the default output stream is a NULL
2008/// pointer.
2009///
2010/// @return a pointer to the default output stream.
2011ostream*
2013{return priv_->default_output_stream_;}
2014
2015/// Setter for the errror output stream used by code of the comparison
2016/// engine. By default the error output stream is a NULL pointer.
2017///
2018/// @param o a pointer to the error output stream.
2019void
2021{priv_->error_output_stream_ = o;}
2022
2023/// Getter for the errror output stream used by code of the comparison
2024/// engine. By default the error output stream is a NULL pointer.
2025///
2026/// @return a pointer to the error output stream.
2027ostream*
2029{return priv_->error_output_stream_;}
2030
2031/// Test if the comparison engine should dump the diff tree for the
2032/// changed functions and variables it has.
2033///
2034/// @return true if after the comparison, the engine should dump the
2035/// diff tree for the changed functions and variables it has.
2036bool
2038{return priv_->dump_diff_tree_;}
2039
2040/// Set if the comparison engine should dump the diff tree for the
2041/// changed functions and variables it has.
2042///
2043/// @param f true if after the comparison, the engine should dump the
2044/// diff tree for the changed functions and variables it has.
2045void
2047{priv_->dump_diff_tree_ = f;}
2048
2049/// Emit a textual representation of a diff tree to the error output
2050/// stream of the current context, for debugging purposes.
2051///
2052/// @param d the diff tree to serialize to the error output associated
2053/// to the current instance of @ref diff_context.
2054void
2056{
2057 if (error_output_stream())
2059}
2060
2061/// Emit a textual representation of a @ref corpus_diff tree to the error
2062/// output stream of the current context, for debugging purposes.
2063///
2064/// @param d the @ref corpus_diff tree to serialize to the error
2065/// output associated to the current instance of @ref diff_context.
2066void
2068{
2069 if (error_output_stream())
2071}
2072// </diff_context stuff>
2073
2074// <diff stuff>
2075
2076/// Constructor for the @ref diff type.
2077///
2078/// This constructs a diff between two subjects that are actually
2079/// declarations; the first and the second one.
2080///
2081/// @param first_subject the first decl (subject) of the diff.
2082///
2083/// @param second_subject the second decl (subject) of the diff.
2084diff::diff(type_or_decl_base_sptr first_subject,
2085 type_or_decl_base_sptr second_subject)
2086 : priv_(new priv(first_subject, second_subject,
2089 /*reported_once=*/false,
2090 /*currently_reporting=*/false))
2091{}
2092
2093/// Constructor for the @ref diff type.
2094///
2095/// This constructs a diff between two subjects that are actually
2096/// declarations; the first and the second one.
2097///
2098/// @param first_subject the first decl (subject) of the diff.
2099///
2100/// @param second_subject the second decl (subject) of the diff.
2101///
2102/// @param ctxt the context of the diff. Note that this context
2103/// object must stay alive during the entire life time of the current
2104/// instance of @ref diff. Otherwise, memory corruption issues occur.
2105diff::diff(type_or_decl_base_sptr first_subject,
2106 type_or_decl_base_sptr second_subject,
2107 diff_context_sptr ctxt)
2108 : priv_(new priv(first_subject, second_subject,
2109 ctxt, NO_CHANGE_CATEGORY,
2110 /*reported_once=*/false,
2111 /*currently_reporting=*/false))
2112{}
2113
2114/// Test if logging was requested
2115///
2116/// @return true iff logging was requested.
2117bool
2119{return context()->do_log();}
2120
2121/// Request logging (or not)
2122///
2123/// @param f true iff logging is to be requested.
2124void
2126{context()->do_log(f);}
2127
2128/// Flag a given diff node as being traversed.
2129///
2130/// For certain diff nodes like @ref class_diff, it's important to
2131/// avoid traversing the node again while it's already being
2132/// traversed; otherwise this leads to infinite loops. So the
2133/// diff::begin_traversing() and diff::end_traversing() methods flag a
2134/// given node as being traversed (or not), so that
2135/// diff::is_traversing() can tell if the node is being traversed.
2136///
2137/// Note that traversing a node means visiting it *and* visiting its
2138/// children nodes.
2139///
2140/// The canonical node is marked as being traversed too.
2141///
2142/// These functions are called by the traversing code.
2143void
2145{
2147 if (priv_->canonical_diff_)
2148 priv_->canonical_diff_->priv_->traversing_ = true;
2149 priv_->traversing_ = true;
2150}
2151
2152/// Tell if a given node is being traversed or not.
2153///
2154/// Note that traversing a node means visiting it *and* visiting its
2155/// children nodes.
2156///
2157/// It's the canonical node which is looked at, actually.
2158///
2159/// Please read the comments for the diff::begin_traversing() for mode
2160/// context.
2161///
2162/// @return true if the current instance of @diff is being traversed.
2163bool
2165{
2166 if (priv_->canonical_diff_)
2167 return priv_->canonical_diff_->priv_->traversing_;
2168 return priv_->traversing_;
2169}
2170
2171/// Flag a given diff node as not being traversed anymore.
2172///
2173/// Note that traversing a node means visiting it *and* visiting its
2174/// children nodes.
2175///
2176/// Please read the comments of the function diff::begin_traversing()
2177/// for mode context.
2178void
2180{
2182 if (priv_->canonical_diff_)
2183 priv_->canonical_diff_->priv_->traversing_ = false;
2184 priv_->traversing_ = false;
2185}
2186
2187/// Finish the insertion of a diff tree node into the diff graph.
2188///
2189/// This function might be called several times. It must perform the
2190/// insertion only once.
2191///
2192/// For instance, certain kinds of diff tree node have specific
2193/// children nodes that are populated after the constructor of the
2194/// diff tree node has been called. In that case, calling overloads
2195/// of this method ensures that these children nodes are properly
2196/// gathered and setup.
2197void
2199{
2200 if (diff::priv_->finished_)
2201 return;
2203 diff::priv_->finished_ = true;
2204}
2205
2206/// Getter of the first subject of the diff.
2207///
2208/// @return the first subject of the diff.
2211{return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2212
2213/// Getter of the second subject of the diff.
2214///
2215/// @return the second subject of the diff.
2218{return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2219
2220/// Getter for the children nodes of the current @ref diff node.
2221///
2222/// @return a vector of the children nodes.
2223const vector<diff*>&
2225{return priv_->children_;}
2226
2227/// Getter for the parent node of the current @ref diff node.
2228///
2229/// @return the parent node of the current @ref diff node.
2230const diff*
2232{return priv_->parent_;}
2233
2234/// Getter for the canonical diff of the current instance of @ref
2235/// diff.
2236///
2237/// Note that the canonical diff node for the current instanc eof diff
2238/// node must have been set by invoking
2239/// class_diff::initialize_canonical_diff() on the current instance of
2240/// diff node.
2241///
2242/// @return the canonical diff node or null if none was set.
2243diff*
2245{return priv_->canonical_diff_;}
2246
2247/// Setter for the canonical diff of the current instance of @ref
2248/// diff.
2249///
2250/// @param d the new canonical node to set.
2251void
2253{priv_->canonical_diff_ = d;}
2254
2255/// Add a new child node to the vector of children nodes for the
2256/// current @ref diff node.
2257///
2258/// @param d the new child node to add to the children nodes.
2259void
2261{
2262 ABG_ASSERT(d);
2263
2264 // Ensure 'd' is kept alive for the life time of the context of this
2265 // diff.
2266 context()->keep_diff_alive(d);
2267
2268 // Add the underlying pointer of 'd' to the vector of children.
2269 // Note that this vector holds no reference to 'd'. This is to avoid
2270 // reference cycles. The reference to 'd' is held by the context of
2271 // this diff, thanks to the call to context()->keep_diff_alive(d)
2272 // above.
2273 priv_->children_.push_back(d.get());
2274
2275 d->priv_->parent_ = this;
2276}
2277
2278/// Getter of the context of the current diff.
2279///
2280/// @return the context of the current diff.
2283{return priv_->get_context();}
2284
2285/// Setter of the context of the current diff.
2286///
2287/// @param c the new context to set.
2288void
2290{priv_->ctxt_ = c;}
2291
2292/// Tests if we are currently in the middle of emitting a report for
2293/// this diff.
2294///
2295/// @return true if we are currently emitting a report for the
2296/// current diff, false otherwise.
2297bool
2299{
2300 if (priv_->canonical_diff_)
2301 return priv_->canonical_diff_->priv_->currently_reporting_;
2302 return priv_->currently_reporting_;
2303}
2304
2305/// Sets a flag saying if we are currently in the middle of emitting
2306/// a report for this diff.
2307///
2308/// @param f true if we are currently emitting a report for the
2309/// current diff, false otherwise.
2310void
2312{
2313 if (priv_->canonical_diff_)
2314 priv_->canonical_diff_->priv_->currently_reporting_ = f;
2315 priv_->currently_reporting_ = f;
2316}
2317
2318/// Tests if a report has already been emitted for the current diff.
2319///
2320/// @return true if a report has already been emitted for the
2321/// current diff, false otherwise.
2322bool
2324{
2325 ABG_ASSERT(priv_->canonical_diff_);
2326 return priv_->canonical_diff_->priv_->reported_once_;
2327}
2328
2329/// The generic traversing code that walks a given diff sub-tree.
2330///
2331/// Note that there is a difference between traversing a diff node and
2332/// visiting it. Basically, traversing a diff node means visiting it
2333/// and visiting its children nodes too. So one can visit a node
2334/// without traversing it. But traversing a node without visiting it
2335/// is not possible.
2336///
2337/// Note that the insertion of the "generic view" of the diff node
2338/// into the graph being traversed is done "on the fly". The
2339/// insertion of the "typed view" of the diff node into the graph is
2340/// done implicitely. To learn more about the generic and typed view
2341/// of the diff node, please read the introductory comments of the
2342/// @ref diff class.
2343///
2344/// Note that by default this traversing code visits a given class of
2345/// equivalence of a diff node only once. This behaviour can been
2346/// changed by calling
2347/// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2348/// very risky as it might create endless loops while visiting a diff
2349/// tree graph that has changes that refer to themselves; that is,
2350/// diff tree graphs with cycles.
2351///
2352/// When a diff node is encountered, the
2353/// diff_node_visitor::visit_begin() method is invoked on the diff
2354/// node first.
2355///
2356/// If the diff node has already been visited, then
2357/// node_visitor::visit_end() is called on it and the node traversing
2358/// is done; the children of the diff node are not visited in this
2359/// case.
2360///
2361/// If the diff node has *NOT* been visited yet, then the
2362/// diff_node_visitor::visit() method is invoked with it's 'pre'
2363/// argument set to true. Then if the diff_node_visitor::visit()
2364/// returns true, then the children nodes of the diff node are
2365/// visited. Otherwise, no children nodes of the diff node is
2366/// visited and the diff_node_visitor::visit_end() is called.
2367
2368/// After the children nodes are visited (and only if they are
2369/// visited) the diff_node_visitor::visit() method is invoked with
2370/// it's 'pre' argument set to false. And then the
2371/// diff_node_visitor::visit_end() is called.
2372///
2373/// @param v the entity that visits each node of the diff sub-tree.
2374///
2375/// @return true to tell the caller that all of the sub-tree could be
2376/// walked. This instructs the caller to keep walking the rest of the
2377/// tree. Return false otherwise.
2378bool
2380{
2381 // Insert the "generic view" of the diff node into its graph.
2383
2384 v.visit_begin(this);
2385
2386 bool already_visited = false;
2387 if (context()->visiting_a_node_twice_is_forbidden()
2388 && context()->diff_has_been_visited(this))
2389 already_visited = true;
2390
2391 bool mark_visited_nodes_as_traversed =
2393
2394 if (!already_visited && !v.visit(this, /*pre=*/true))
2395 {
2396 v.visit_end(this);
2397 if (mark_visited_nodes_as_traversed)
2398 context()->mark_diff_as_visited(this);
2399 return false;
2400 }
2401
2403 && !is_traversing()
2404 && !already_visited)
2405 {
2407 for (vector<diff*>::const_iterator i = children_nodes().begin();
2408 i != children_nodes().end();
2409 ++i)
2410 {
2411 if (!(*i)->traverse(v))
2412 {
2413 v.visit_end(this);
2414 if (mark_visited_nodes_as_traversed)
2415 context()->mark_diff_as_visited(this);
2417 return false;
2418 }
2419 }
2421 }
2422
2423 if (!v.visit(this, /*pref=*/false))
2424 {
2425 v.visit_end(this);
2426 if (mark_visited_nodes_as_traversed)
2427 context()->mark_diff_as_visited(this);
2428 return false;
2429 }
2430
2431 v.visit_end(this);
2432 if (!already_visited && mark_visited_nodes_as_traversed)
2433 context()->mark_diff_as_visited(this);
2434
2435 return true;
2436}
2437
2438/// Sets a flag saying if a report has already been emitted for the
2439/// current diff.
2440///
2441/// @param f true if a report has already been emitted for the
2442/// current diff, false otherwise.
2443void
2445{
2446 ABG_ASSERT(priv_->canonical_diff_);
2447 priv_->canonical_diff_->priv_->reported_once_ = f;
2448 priv_->reported_once_ = f;
2449}
2450
2451/// Getter for the local category of the current diff tree node.
2452///
2453/// The local category represents the set of categories of a diff
2454/// node, not taking in account the categories inherited from its
2455/// children nodes.
2456///
2457/// @return the local category of the current diff tree node.
2460{return priv_->local_category_;}
2461
2462/// Getter of the category of the class of equivalence of the current
2463/// diff tree node.
2464///
2465/// That is, if the current diff tree node has a canonical node,
2466/// return the category of that canonical node. Otherwise, return the
2467/// category of the current node.
2468///
2469/// @return the category of the class of equivalence of the current
2470/// tree node.
2473{
2474 diff* canonical = get_canonical_diff();
2475 return canonical ? canonical->get_category() : get_category();
2476}
2477
2478/// Getter for the category of the current diff tree node.
2479///
2480/// This category represents the union of the local category and the
2481/// categories inherited from the children diff nodes.
2482///
2483/// @return the category of the current diff tree node.
2486{return priv_->category_;}
2487
2488/// Adds the current diff tree node to an additional set of
2489/// categories. Note that the categories include thoses inherited
2490/// from the children nodes of this diff node.
2491///
2492/// @param c a bit-map representing the set of categories to add the
2493/// current diff tree node to.
2494///
2495/// @return the resulting bit-map representing the categories this
2496/// current diff tree node belongs to, including those inherited from
2497/// its children nodes.
2500{
2501 priv_->category_ = priv_->category_ | c;
2502 return priv_->category_;
2503}
2504
2505/// Adds the current diff tree node to the categories resulting from
2506/// the local changes of the current diff node.
2507///
2508/// @param c a bit-map representing the set of categories to add the
2509/// current diff tree node to.
2510///
2511/// @return the resulting bit-map representing the categories this
2512/// current diff tree node belongs to.
2515{
2516 priv_->local_category_ = priv_->local_category_ | c;
2517 return priv_->local_category_;
2518}
2519
2520/// Adds the current diff tree node to the categories resulting from
2521/// the local and inherited changes of the current diff node.
2522///
2523/// @param c a bit-map representing the set of categories to add the
2524/// current diff tree node to.
2525void
2527{
2529 add_to_category(c);
2530}
2531
2532/// Remove the current diff tree node from an a existing sef of
2533/// categories. The categories include those inherited from the
2534/// children nodes of the current diff node.
2535///
2536/// @param c a bit-map representing the set of categories to add the
2537/// current diff tree node to.
2538///
2539/// @return the resulting bit-map representing the categories this
2540/// current diff tree onde belongs to, including the categories
2541/// inherited from the children nodes of the current diff node.
2544{
2545 priv_->category_ = priv_->category_ & ~c;
2546 return priv_->category_;
2547}
2548
2549/// Remove the current diff tree node from the categories resulting
2550/// from the local changes.
2551///
2552/// @param c a bit-map representing the set of categories to add the
2553/// current diff tree node to.
2554///
2555/// @return the resulting bit-map representing the categories this
2556/// current diff tree onde belongs to.
2559{
2560 priv_->local_category_ = priv_->local_category_ & ~c;
2561 return priv_->local_category_;
2562}
2563
2564/// Set the category of the current @ref diff node. This category
2565/// includes the categories inherited from the children nodes of the
2566/// current diff node.
2567///
2568/// @param c the new category for the current diff node.
2569void
2571{priv_->category_ = c;}
2572
2573/// Set the local category of the current @ref diff node.
2574///
2575/// @param c the new category for the current diff node.
2576void
2578{priv_->local_category_ = c;}
2579
2580/// Test if this diff tree node is to be filtered out for reporting
2581/// purposes.
2582///
2583/// There is a difference between a diff node being filtered out and
2584/// being suppressed. Being suppressed means that there is a
2585/// suppression specification that suppresses the diff node
2586/// specifically. Being filtered out mean the node is either
2587/// suppressed, or it's filtered out because the suppression of a set
2588/// of (children) nodes caused this node to be filtered out as well.
2589/// For instance, if a function diff has all its children diff nodes
2590/// suppressed and if the function diff node carries no local change,
2591/// then the function diff node itself is going to be filtered out.
2592///
2593/// The function tests if the categories of the diff tree node are
2594/// "forbidden" by the context or not.
2595///
2596/// @return true iff the current diff node should NOT be reported.
2597bool
2599{
2600 if (diff * canonical = get_canonical_diff())
2601 if ((canonical->get_category() & SUPPRESSED_CATEGORY
2602 || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2603 && !canonical->is_allowed_by_specific_negated_suppression()
2604 && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2605 && !canonical->has_parent_allowed_by_specific_negated_suppression())
2606 // The canonical type was suppressed either by a user-provided
2607 // suppression specification or by a "private-type" suppression
2608 // specification.. This means all the classes of equivalence of
2609 // that canonical type were suppressed. So this node should be
2610 // filtered out.
2611 return true;
2612 return priv_->is_filtered_out(get_category());
2613}
2614
2615/// Test if this diff tree node is to be filtered out for reporting
2616/// purposes, but by considering only the categories that were *NOT*
2617/// inherited from its children nodes.
2618///
2619/// The function tests if the local categories of the diff tree node
2620/// are "forbidden" by the context or not.
2621///
2622/// @return true iff the current diff node should NOT be reported,
2623/// with respect to its local categories.
2624bool
2626{return priv_->is_filtered_out(get_local_category());}
2627
2628/// Test if this diff tree node is to be filtered out for reporting
2629/// purposes, but without considering the categories that can /force/
2630/// the node to be unfiltered.
2631///
2632/// The function tests if the categories of the diff tree node are
2633/// "forbidden" by the context or not.
2634///
2635/// @return true iff the current diff node should should NOT be
2636/// reported, with respect to the categories that might filter it out
2637/// only.
2638bool
2640{
2645
2646 return priv_->is_filtered_out(c);
2647}
2648
2649/// Test if the current diff node has been suppressed by a
2650/// user-provided suppression specification.
2651///
2652/// @return true if the current diff node has been suppressed by a
2653/// user-provided suppression list.
2654bool
2656{
2657 bool is_private = false;
2658 return is_suppressed(is_private);
2659}
2660
2661/// Test if the current diff node has been suppressed by a
2662/// user-provided suppression specification or by an auto-generated
2663/// "private type" suppression specification.
2664///
2665/// Note that private type suppressions are auto-generated from the
2666/// path to where public headers are, as given by the user.
2667///
2668/// Here is the current algorithm:
2669///
2670/// First, suppress this diff node if it's not matched by any
2671/// negated suppression specifications. If it's not
2672/// suppressed, then suppress it if it's matched by direct
2673/// suppression specifications.
2674///
2675/// @param is_private_type out parameter if the current diff node was
2676/// suppressed because it's a private type then this parameter is set
2677/// to true.
2678///
2679/// @return true if the current diff node has been suppressed by a
2680/// user-provided suppression list.
2681bool
2682diff::is_suppressed(bool &is_private_type) const
2683{
2684 // If there is at least one negated suppression, then suppress the
2685 // current diff node by default ...
2686 bool do_suppress = !context()->negated_suppressions().empty();
2687
2688 // ... unless there is at least one negated suppression that
2689 // specifically asks to keep this diff node around (un-suppressed).
2690 for (auto n : context()->negated_suppressions())
2691 if (!n->suppresses_diff(this))
2692 {
2693 do_suppress = false;
2694 break;
2695 }
2696
2697 // Then walk the set of non-negated, AKA direct, suppressions. If at
2698 // least one suppression suppresses the current diff node then the
2699 // diff node must be suppressed.
2700 for (auto d : context()->direct_suppressions())
2701 if (d->suppresses_diff(this))
2702 {
2703 do_suppress = true;
2705 is_private_type = true;
2706 break;
2707 }
2708
2709 return do_suppress;
2710}
2711
2712/// Test if the current diff node has been suppressed by a suppression
2713/// specification or it has been categorized as suppressed due to
2714/// category propagation.
2715///
2716/// @return true iff the current diff node has been suppressed by a
2717/// suppression specification or it has been categorized as suppressed
2718/// due to category propagation.
2719bool
2721{
2724}
2725
2726/// Test if this diff tree node should be reported.
2727///
2728/// @return true iff the current node should be reported.
2729bool
2731{
2732 if (has_changes() && !is_filtered_out())
2733 return true;
2734 return false;
2735}
2736
2737/// Test if this diff tree node should be reported when considering
2738/// the categories that were *NOT* inherited from its children nodes.
2739///
2740/// @return true iff the current node should be reported.
2741bool
2743{
2744 if (has_local_changes()
2746 return true;
2747 return false;
2748}
2749
2750/// Test if this diff node is allowed (prevented from being
2751/// suppressed) by at least one negated suppression specification.
2752///
2753/// @return true if this diff node is meant to be allowed by at least
2754/// one negated suppression specification.
2755bool
2757{
2758 const suppressions_type& suppressions = context()->suppressions();
2759 for (suppressions_type::const_iterator i = suppressions.begin();
2760 i != suppressions.end();
2761 ++i)
2762 {
2764 && !(*i)->suppresses_diff(this))
2765 return true;
2766 }
2767 return false;
2768}
2769
2770/// Test if the current diff node has a descendant node which is
2771/// specifically allowed by a negated suppression specification.
2772///
2773/// @return true iff the current diff node has a descendant node
2774/// which is specifically allowed by a negated suppression
2775/// specification.
2776bool
2778{
2780 return result;
2781}
2782
2783/// Test if the current diff node has a parent node which is
2784/// specifically allowed by a negated suppression specification.
2785///
2786/// @return true iff the current diff node has a parent node which is
2787/// specifically allowed by a negated suppression specification.
2788bool
2790{
2792 return result;
2793}
2794
2795/// Get a pretty representation of the current @ref diff node.
2796///
2797/// This is suitable for e.g. emitting debugging traces for the diff
2798/// tree nodes.
2799///
2800/// @return the pretty representation of the diff node.
2801const string&
2803{
2804 if (priv_->pretty_representation_.empty())
2805 priv_->pretty_representation_ = "empty_diff";
2806 return priv_->pretty_representation_;
2807}
2808
2809/// Default implementation of the hierachy chaining virtual function.
2810///
2811/// There are several types of diff nodes that have logical children
2812/// nodes; for instance, a typedef_diff has the diff of the underlying
2813/// type as a child node. A var_diff has the diff of the types of the
2814/// variables as a child node, etc.
2815///
2816/// But because the @ref diff base has a generic representation for
2817/// children nodes of the all the types of @ref diff nodes (regardless
2818/// of the specific most-derived type of diff node) that one can get
2819/// using the method diff::children_nodes(), one need to populate that
2820/// vector of children node.
2821///
2822/// Populating that vector of children node is done by this function;
2823/// it must be overloaded by each most-derived type of diff node that
2824/// extends the @ref diff type.
2825void
2827{}
2828
2829// </diff stuff>
2830
2831// <type_diff_base stuff>
2832
2833type_diff_base::type_diff_base(type_base_sptr first_subject,
2834 type_base_sptr second_subject,
2835 diff_context_sptr ctxt)
2836 : diff(first_subject, second_subject, ctxt),
2837 priv_(new priv)
2838{}
2839
2840type_diff_base::~type_diff_base()
2841{}
2842// </type_diff_base stuff>
2843
2844// <decl_diff_base stuff>
2845
2846/// Constructor of @ref decl_diff_base.
2847///
2848/// @param first_subject the first subject of the diff.
2849///
2850/// @param second_subject the second subject of the diff.
2851///
2852/// @param ctxt the context of the diff. This object must stay alive
2853/// at least during the life time of the current instance of @ref
2854/// decl_diff_base, otherwise, memory corruption issues occur.
2855decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2856 decl_base_sptr second_subject,
2857 diff_context_sptr ctxt)
2858 : diff(first_subject, second_subject, ctxt),
2859 priv_(new priv)
2860{}
2861
2862decl_diff_base::~decl_diff_base()
2863{}
2864
2865// </decl_diff_base stuff>
2866
2867// <distinct_diff stuff>
2868
2869/// @return a pretty representation for the @ref distinct_diff node.
2870const string&
2872{
2873 if (diff::priv_->pretty_representation_.empty())
2874 {
2875 std::ostringstream o;
2876 o << "distinct_diff[";
2877 if (first_subject())
2878 o << first_subject()->get_pretty_representation();
2879 else
2880 o << "null";
2881 o << ", ";
2882 if (second_subject())
2883 o << second_subject()->get_pretty_representation() ;
2884 else
2885 o << "null";
2886 o << "]" ;
2887 diff::priv_->pretty_representation_ = o.str();
2888 }
2889 return diff::priv_->pretty_representation_;
2890}
2891
2892/// Populate the vector of children node of the @ref diff base type
2893/// sub-object of this instance of @distinct_diff.
2894///
2895/// The children nodes can then later be retrieved using
2896/// diff::children_nodes().
2897void
2899{
2901
2904}
2905
2906/// Constructor for @ref distinct_diff.
2907///
2908/// Note that the two entities considered for the diff (and passed in
2909/// parameter) must be of different kinds.
2910///
2911/// @param first the first entity to consider for the diff.
2912///
2913/// @param second the second entity to consider for the diff.
2914///
2915/// @param ctxt the context of the diff. Note that this context
2916/// object must stay alive at least during the life time of the
2917/// current instance of @ref distinct_diff. Otherwise memory
2918/// corruption issues occur.
2921 diff_context_sptr ctxt)
2922 : diff(first, second, ctxt),
2923 priv_(new priv)
2925
2926/// Getter for the first subject of the diff.
2927///
2928/// @return the first subject of the diff.
2931{return first_subject();}
2932
2933/// Getter for the second subject of the diff.
2934///
2935/// @return the second subject of the diff.
2938{return second_subject();}
2939
2940/// Getter for the child diff of this distinct_diff instance.
2941///
2942/// When a distinct_diff has two subjects that are different but
2943/// compatible, then the distinct_diff instance has a child diff node
2944/// (named the compatible child diff) that is the diff between the two
2945/// subjects stripped from their typedefs. Otherwise, the compatible
2946/// child diff is nul.
2947///
2948/// Note that two diff subjects (that compare different) are
2949/// considered compatible if stripping typedefs out of them makes them
2950/// comparing equal.
2951///
2952/// @return the compatible child diff node, if any. Otherwise, null.
2953const diff_sptr
2955{
2956 if (!priv_->compatible_child_diff)
2957 {
2960 {
2961 type_base_sptr fs = peel_qualified_or_typedef_type(is_type(first())),
2963
2964 priv_->compatible_child_diff =
2967 context());
2968 }
2969 }
2970 return priv_->compatible_child_diff;
2971}
2972
2973/// Test if the two arguments are of different kind, or that are both
2974/// NULL.
2975///
2976/// @param first the first argument to test for similarity in kind.
2977///
2978/// @param second the second argument to test for similarity in kind.
2979///
2980/// @return true iff the two arguments are of different kind.
2981bool
2984{
2985 if (!!first != !!second)
2986 return true;
2987 if (!first && !second)
2988 // We do consider diffs of two empty decls as a diff of distinct
2989 // kinds, for now.
2990 return true;
2991 if (first == second)
2992 return false;
2993
2994 const type_or_decl_base &f = *first, &s = *second;
2995 return typeid(f) != typeid(s);
2996}
2997
2998/// @return true if the two subjects of the diff are different, false
2999/// otherwise.
3000bool
3002{return first() != second();}
3003
3004/// @return the kind of local change carried by the current diff node.
3005/// The value returned is zero if the current node carries no local
3006/// change.
3007enum change_kind
3009{
3010 // Changes on a distinct_diff are all local.
3011 if (has_changes())
3013 return NO_CHANGE_KIND;
3014}
3015
3016/// Emit a report about the current diff instance.
3017///
3018/// @param out the output stream to send the diff report to.
3019///
3020/// @param indent the indentation string to use in the report.
3021void
3022distinct_diff::report(ostream& out, const string& indent) const
3023{
3024 context()->get_reporter()->report(*this, out, indent);
3025}
3026
3027/// Try to diff entities that are of distinct kinds.
3028///
3029/// @param first the first entity to consider for the diff.
3030///
3031/// @param second the second entity to consider for the diff.
3032///
3033/// @param ctxt the context of the diff.
3034///
3035/// @return a non-null diff if a diff object could be built, null
3036/// otherwise.
3039 const type_or_decl_base_sptr second,
3040 diff_context_sptr ctxt)
3041{
3043 return distinct_diff_sptr();
3044
3045 distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
3046
3047 ctxt->initialize_canonical_diff(result);
3048
3049 return result;
3050}
3051
3052/// </distinct_diff stuff>
3053
3054/// Try to compute a diff on two instances of DiffType representation.
3055///
3056/// The function template performs the diff if and only if the decl
3057/// representations are of a DiffType.
3058///
3059/// @tparm DiffType the type of instances to diff.
3060///
3061/// @param first the first representation of decl to consider in the
3062/// diff computation.
3063///
3064/// @param second the second representation of decl to consider in the
3065/// diff computation.
3066///
3067/// @param ctxt the diff context to use.
3068///
3069///@return the diff of the two types @p first and @p second if and
3070///only if they represent the parametrized type DiffType. Otherwise,
3071///returns a NULL pointer value.
3072template<typename DiffType>
3075 const type_or_decl_base_sptr second,
3076 diff_context_sptr ctxt)
3077{
3078 if (shared_ptr<DiffType> f =
3079 dynamic_pointer_cast<DiffType>(first))
3080 {
3081 shared_ptr<DiffType> s =
3082 dynamic_pointer_cast<DiffType>(second);
3083 if (!s)
3084 return diff_sptr();
3085 return compute_diff(f, s, ctxt);
3086 }
3087 return diff_sptr();
3088}
3089
3090
3091/// This is a specialization of @ref try_to_diff() template to diff
3092/// instances of @ref class_decl.
3093///
3094/// @param first the first representation of decl to consider in the
3095/// diff computation.
3096///
3097/// @param second the second representation of decl to consider in the
3098/// diff computation.
3099///
3100/// @param ctxt the diff context to use.
3101template<>
3104 const type_or_decl_base_sptr second,
3105 diff_context_sptr ctxt)
3106{
3107 if (class_decl_sptr f =
3108 dynamic_pointer_cast<class_decl>(first))
3109 {
3110 class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
3111 if (!s)
3112 return diff_sptr();
3113
3114 if (f->get_is_declaration_only())
3115 {
3116 class_decl_sptr f2 =
3117 is_class_type (f->get_definition_of_declaration());
3118 if (f2)
3119 f = f2;
3120 }
3121 if (s->get_is_declaration_only())
3122 {
3123 class_decl_sptr s2 =
3124 is_class_type(s->get_definition_of_declaration());
3125 if (s2)
3126 s = s2;
3127 }
3128 return compute_diff(f, s, ctxt);
3129 }
3130 return diff_sptr();
3131}
3132
3133/// Try to diff entities that are of distinct kinds.
3134///
3135/// @param first the first entity to consider for the diff.
3136///
3137/// @param second the second entity to consider for the diff.
3138///
3139/// @param ctxt the context of the diff.
3140///
3141/// @return a non-null diff if a diff object could be built, null
3142/// otherwise.
3143static diff_sptr
3144try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3145 const type_or_decl_base_sptr second,
3146 diff_context_sptr ctxt)
3147{return compute_diff_for_distinct_kinds(first, second, ctxt);}
3148
3149/// Compute the difference between two types.
3150///
3151/// The function considers every possible types known to libabigail
3152/// and runs the appropriate diff function on them.
3153///
3154/// Whenever a new kind of type decl is supported by abigail, if we
3155/// want to be able to diff two instances of it, we need to update
3156/// this function to support it.
3157///
3158/// @param first the first type decl to consider for the diff
3159///
3160/// @param second the second type decl to consider for the diff.
3161///
3162/// @param ctxt the diff context to use.
3163///
3164/// @return the resulting diff. It's a pointer to a descendent of
3165/// abigail::comparison::diff.
3166static diff_sptr
3167compute_diff_for_types(const type_or_decl_base_sptr& first,
3168 const type_or_decl_base_sptr& second,
3169 const diff_context_sptr& ctxt)
3170{
3171 type_or_decl_base_sptr f = first;
3172 type_or_decl_base_sptr s = second;
3173
3174 diff_sptr d;
3175
3176 ((d = try_to_diff<type_decl>(f, s, ctxt))
3177 ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3178 ||(d = try_to_diff<union_decl>(f, s,ctxt))
3179 ||(d = try_to_diff<class_decl>(f, s,ctxt))
3180 ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3181 ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3182 ||(d = try_to_diff<ptr_to_mbr_type>(f, s, ctxt))
3183 ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3184 ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3185 ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3186 ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3187 ||(d = try_to_diff<function_type>(f, s, ctxt))
3188 ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3189
3190 ABG_ASSERT(d);
3191
3192 return d;
3193}
3194
3197{return static_cast<diff_category>(static_cast<unsigned>(c1)
3198 | static_cast<unsigned>(c2));}
3199
3201operator|=(diff_category& c1, diff_category c2)
3202{
3203 c1 = c1 | c2;
3204 return c1;
3205}
3206
3208operator&=(diff_category& c1, diff_category c2)
3209{
3210 c1 = c1 & c2;
3211 return c1;
3212}
3213
3215operator^(diff_category c1, diff_category c2)
3216{return static_cast<diff_category>(static_cast<unsigned>(c1)
3217 ^ static_cast<unsigned>(c2));}
3218
3221{return static_cast<diff_category>(static_cast<unsigned>(c1)
3222 & static_cast<unsigned>(c2));}
3223
3226{return static_cast<diff_category>(~static_cast<unsigned>(c));}
3227
3228
3229/// Getter of a bitmap made of the set of change categories that are
3230/// considered harmless.
3231///
3232/// @return the bitmap made of the set of change categories that are
3233/// considered harmless.
3236{
3253}
3254
3255/// Getter of a bitmap made of the set of change categories that are
3256/// considered harmful.
3257///
3258/// @return the bitmap made of the set of change categories that are
3259/// considered harmful.
3262{
3265 | abigail::comparison::REFERENCE_LVALUENESS_CHANGE_CATEGORY
3269}
3270
3271/// Test if an instance of @ref diff_category (a category bit-field)
3272/// is harmful or not.
3273///
3274/// A harmful change is a change that is not harmless. OK, that
3275/// smells bit like a tasteless tautology, but bear with me please.
3276///
3277/// A harmless change is a change that should be filtered out by
3278/// default to avoid unnecessarily cluttering the change report.
3279///
3280/// A harmful change is thus a change that SHOULD NOT be filtered out
3281/// by default because it CAN represent an incompatible ABI change.
3282///
3283/// An incompatbile ABI change is a harmful change that makes the new
3284/// ABI incompatible with the previous one.
3285///
3286/// @param c the instance of @ref diff_category to consider. It is a
3287/// bit-field of the categories of a given diff node.
3288///
3289/// @return true
3290bool
3292{
3294 return c & dc;
3295}
3296
3297/// Serialize an instance of @ref diff_category to an output stream.
3298///
3299/// @param o the output stream to serialize @p c to.
3300///
3301/// @param c the instance of diff_category to serialize.
3302///
3303/// @return the output stream to serialize @p c to.
3304ostream&
3305operator<<(ostream& o, diff_category c)
3306{
3307 bool emitted_a_category = false;
3308
3309 if (c == NO_CHANGE_CATEGORY)
3310 {
3311 o << "NO_CHANGE_CATEGORY";
3312 emitted_a_category = true;
3313 }
3314
3315 if (c & ACCESS_CHANGE_CATEGORY)
3316 {
3317 if (emitted_a_category)
3318 o << "|";
3319 o << "ACCESS_CHANGE_CATEGORY";
3320 emitted_a_category |= true;
3321 }
3322
3324 {
3325 if (emitted_a_category)
3326 o << "|";
3327 o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3328 emitted_a_category |= true;
3329 }
3330
3332 {
3333 if (emitted_a_category)
3334 o << "|";
3335 o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3336 emitted_a_category |= true;
3337 }
3338
3340 {
3341 if (emitted_a_category)
3342 o << "|";
3343 o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3344 emitted_a_category |= true;
3345 }
3346
3348 {
3349 if (emitted_a_category)
3350 o << "|";
3351 o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3352 emitted_a_category |= true;
3353 }
3354
3356 {
3357 if (emitted_a_category)
3358 o << "|";
3359 o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3360 emitted_a_category |= true;
3361 }
3362
3364 {
3365 if (emitted_a_category)
3366 o << "|";
3367 o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3368 emitted_a_category |= true;
3369 }
3370
3372 {
3373 if (emitted_a_category)
3374 o << "|";
3375 o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3376 emitted_a_category |= true;
3377 }
3378
3380 {
3381 if (emitted_a_category)
3382 o << "|";
3383 o << "HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY";
3384 emitted_a_category |= true;
3385 }
3386
3387 if (c & SUPPRESSED_CATEGORY)
3388 {
3389 if (emitted_a_category)
3390 o << "|";
3391 o << "SUPPRESSED_CATEGORY";
3392 emitted_a_category |= true;
3393 }
3394
3395 if (c & PRIVATE_TYPE_CATEGORY)
3396 {
3397 if (emitted_a_category)
3398 o << "|";
3399 o << "PRIVATE_TYPE_CATEGORY";
3400 emitted_a_category |= true;
3401 }
3402
3404 {
3405 if (emitted_a_category)
3406 o << "|";
3407 o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3408 emitted_a_category |= true;
3409 }
3410
3412 {
3413 if (emitted_a_category)
3414 o << "|";
3415 o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3416 emitted_a_category |= true;
3417 }
3418
3419 if (c & REFERENCE_LVALUENESS_CHANGE_CATEGORY)
3420 {
3421 if (emitted_a_category)
3422 o << "|";
3423 o << "REFERENCE_LVALUENESS_CHANGE_CATEGORY";
3424 emitted_a_category |= true;
3425 }
3426
3428 {
3429 if (emitted_a_category)
3430 o << "|";
3431 o << "NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY";
3432 emitted_a_category |= true;
3433 }
3434
3436 {
3437 if (emitted_a_category)
3438 o << "|";
3439 o << "NON_COMPATIBLE_NAME_CHANGE_CATEGORY";
3440 emitted_a_category |= true;
3441 }
3442
3443 if (c & REDUNDANT_CATEGORY)
3444 {
3445 if (emitted_a_category)
3446 o << "|";
3447 o << "REDUNDANT_CATEGORY";
3448 emitted_a_category |= true;
3449 }
3450
3452 {
3453 if (emitted_a_category)
3454 o << "|";
3455 o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3456 emitted_a_category |= true;
3457 }
3458
3460 {
3461 if (emitted_a_category)
3462 o << "|";
3463 o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3464 emitted_a_category |= true;
3465 }
3466
3468 {
3469 if (emitted_a_category)
3470 o << "|";
3471 o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3472 emitted_a_category |= true;
3473 }
3474
3476 {
3477 if (emitted_a_category)
3478 o << "|";
3479 o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3480 emitted_a_category |= true;
3481 }
3482
3484 {
3485 if (emitted_a_category)
3486 o << "|";
3487 o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3488 emitted_a_category |= true;
3489 }
3490
3492 {
3493 if (emitted_a_category)
3494 o << "|";
3495 o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3496 emitted_a_category |= true;
3497 }
3498
3500 {
3501 if (emitted_a_category)
3502 o << "|";
3503 o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3504 emitted_a_category |= true;
3505 }
3506
3508 {
3509 if (emitted_a_category)
3510 o << "|";
3511 o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3512 emitted_a_category |= true;
3513 }
3514
3516 {
3517 if (emitted_a_category)
3518 o << "|";
3519 o << "HAS_ALLOWED_CHANGE_CATEGORY";
3520 emitted_a_category |= true;
3521 }
3522
3524 {
3525 if (emitted_a_category)
3526 o << "|";
3527 o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3528 emitted_a_category |= true;
3529 }
3530
3532 {
3533 if (emitted_a_category)
3534 o << "|";
3535 o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3536 emitted_a_category |= true;
3537 }
3538
3539 return o;
3540}
3541
3542/// Compute the difference between two decls.
3543///
3544/// The function consider every possible decls known to libabigail and
3545/// runs the appropriate diff function on them.
3546///
3547/// Whenever a new kind of non-type decl is supported by abigail, if
3548/// we want to be able to diff two instances of it, we need to update
3549/// this function to support it.
3550///
3551/// @param first the first decl to consider for the diff
3552///
3553/// @param second the second decl to consider for the diff.
3554///
3555/// @param ctxt the diff context to use.
3556///
3557/// @return the resulting diff.
3558static diff_sptr
3559compute_diff_for_decls(const decl_base_sptr first,
3560 const decl_base_sptr second,
3561 diff_context_sptr ctxt)
3562{
3563
3564 diff_sptr d;
3565
3566 ((d = try_to_diff<function_decl>(first, second, ctxt))
3567 || (d = try_to_diff<var_decl>(first, second, ctxt))
3568 || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3569
3570 ABG_ASSERT(d);
3571
3572 return d;
3573}
3574
3575/// Compute the difference between two decls. The decls can represent
3576/// either type declarations, or non-type declaration.
3577///
3578/// Note that the two decls must have been created in the same @ref
3579/// environment, otherwise, this function aborts.
3580///
3581/// @param first the first decl to consider.
3582///
3583/// @param second the second decl to consider.
3584///
3585/// @param ctxt the diff context to use.
3586///
3587/// @return the resulting diff, or NULL if the diff could not be
3588/// computed.
3590compute_diff(const decl_base_sptr first,
3591 const decl_base_sptr second,
3592 diff_context_sptr ctxt)
3593{
3594 if (!first || !second)
3595 return diff_sptr();
3596
3597 diff_sptr d;
3598 if (is_type(first) && is_type(second))
3599 d = compute_diff_for_types(first, second, ctxt);
3600 else
3601 d = compute_diff_for_decls(first, second, ctxt);
3602 ABG_ASSERT(d);
3603 return d;
3604}
3605
3606/// Compute the difference between two types.
3607///
3608/// Note that the two types must have been created in the same @ref
3609/// environment, otherwise, this function aborts.
3610///
3611/// @param first the first type to consider.
3612///
3613/// @param second the second type to consider.
3614///
3615/// @param ctxt the diff context to use.
3616///
3617/// @return the resulting diff, or NULL if the diff couldn't be
3618/// computed.
3620compute_diff(const type_base_sptr first,
3621 const type_base_sptr second,
3622 diff_context_sptr ctxt)
3623{
3624 decl_base_sptr f = get_type_declaration(first),
3625 s = get_type_declaration(second);
3626
3627 diff_sptr d = compute_diff_for_types(f,s, ctxt);
3628 ABG_ASSERT(d);
3629 return d;
3630}
3631
3632/// Get a copy of the pretty representation of a diff node.
3633///
3634/// @param d the diff node to consider.
3635///
3636/// @return the pretty representation string.
3637string
3639{
3640 if (!d)
3641 return "";
3642 string prefix= "diff of ";
3643 return prefix + get_pretty_representation(d->first_subject());
3644}
3645
3646// <var_diff stuff>
3647
3648/// Populate the vector of children node of the @ref diff base type
3649/// sub-object of this instance of @ref var_diff.
3650///
3651/// The children node can then later be retrieved using
3652/// diff::children_node().
3653void
3656
3657/// @return the pretty representation for this current instance of
3658/// @ref var_diff.
3659const string&
3661{
3662 if (diff::priv_->pretty_representation_.empty())
3663 {
3664 std::ostringstream o;
3665 o << "var_diff["
3666 << first_subject()->get_pretty_representation()
3667 << ", "
3668 << second_subject()->get_pretty_representation()
3669 << "]";
3670 diff::priv_->pretty_representation_ = o.str();
3671 }
3672 return diff::priv_->pretty_representation_;
3673}
3674/// Constructor for @ref var_diff.
3675///
3676/// @param first the first instance of @ref var_decl to consider in
3677/// the diff.
3678///
3679/// @param second the second instance of @ref var_decl to consider in
3680/// the diff.
3681///
3682/// @param type_diff the diff between types of the instances of
3683/// var_decl.
3684///
3685/// @param ctxt the diff context to use.
3687 var_decl_sptr second,
3688 diff_sptr type_diff,
3689 diff_context_sptr ctxt)
3690 : decl_diff_base(first, second, ctxt),
3691 priv_(new priv)
3692{priv_->type_diff_ = type_diff;}
3693
3694/// Getter for the first @ref var_decl of the diff.
3695///
3696/// @return the first @ref var_decl of the diff.
3699{return dynamic_pointer_cast<var_decl>(first_subject());}
3700
3701/// Getter for the second @ref var_decl of the diff.
3702///
3703/// @return the second @ref var_decl of the diff.
3706{return dynamic_pointer_cast<var_decl>(second_subject());}
3707
3708/// Getter for the diff of the types of the instances of @ref
3709/// var_decl.
3710///
3711/// @return the diff of the types of the instances of @ref var_decl.
3714{
3715 if (diff_sptr result = priv_->type_diff_.lock())
3716 return result;
3717 else
3718 {
3719 result = compute_diff(first_var()->get_type(),
3720 second_var()->get_type(),
3721 context());
3722 context()->keep_diff_alive(result);
3723 priv_->type_diff_ = result;
3724 return result;
3725 }
3726}
3727
3728/// Return true iff the diff node has a change.
3729///
3730/// @return true iff the diff node has a change.
3731bool
3733{return *first_var() != *second_var();}
3734
3735/// @return the kind of local change carried by the current diff node.
3736/// The value returned is zero if the current node carries no local
3737/// change.
3738enum change_kind
3740{
3741 ir::change_kind k = ir::NO_CHANGE_KIND;
3742 if (!equals(*first_var(), *second_var(), &k))
3743 return k & ir::ALL_LOCAL_CHANGES_MASK;
3744 return ir::NO_CHANGE_KIND;
3745}
3746
3747/// Report the diff in a serialized form.
3748///
3749/// @param out the stream to serialize the diff to.
3750///
3751/// @param indent the prefix to use for the indentation of this
3752/// serialization.
3753void
3754var_diff::report(ostream& out, const string& indent) const
3755{
3756 context()->get_reporter()->report(*this, out, indent);
3757}
3758
3759/// Compute the diff between two instances of @ref var_decl.
3760///
3761/// Note that the two decls must have been created in the same @ref
3762/// environment, otherwise, this function aborts.
3763///
3764/// @param first the first @ref var_decl to consider for the diff.
3765///
3766/// @param second the second @ref var_decl to consider for the diff.
3767///
3768/// @param ctxt the diff context to use.
3769///
3770/// @return the resulting diff between the two @ref var_decl.
3773 const var_decl_sptr second,
3774 diff_context_sptr ctxt)
3775{
3776 var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3777 ctxt->initialize_canonical_diff(d);
3778
3779 return d;
3780}
3781
3782// </var_diff stuff>
3783
3784// <pointer_type_def stuff>
3785
3786/// Populate the vector of children node of the @ref diff base type
3787/// sub-object of this instance of @ref pointer_diff.
3788///
3789/// The children node can then later be retrieved using
3790/// diff::children_node().
3791void
3794
3795/// Constructor for a pointer_diff.
3796///
3797/// @param first the first pointer to consider for the diff.
3798///
3799/// @param second the secon pointer to consider for the diff.
3800///
3801/// @param ctxt the diff context to use.
3803 pointer_type_def_sptr second,
3804 diff_sptr underlying,
3805 diff_context_sptr ctxt)
3806 : type_diff_base(first, second, ctxt),
3807 priv_(new priv(underlying))
3808{}
3809
3810/// Getter for the first subject of a pointer diff
3811///
3812/// @return the first pointer considered in this pointer diff.
3815{return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3816
3817/// Getter for the second subject of a pointer diff
3818///
3819/// @return the second pointer considered in this pointer diff.
3822{return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3823
3824/// @return the pretty represenation for the current instance of @ref
3825/// pointer_diff.
3826const string&
3828{
3829 if (diff::priv_->pretty_representation_.empty())
3830 {
3831 std::ostringstream o;
3832 o << "pointer_diff["
3833 << first_subject()->get_pretty_representation()
3834 << ", "
3835 << second_subject()->get_pretty_representation()
3836 << "]";
3837 diff::priv_->pretty_representation_ = o.str();
3838 }
3839 return diff::priv_->pretty_representation_;
3840}
3841
3842/// Return true iff the current diff node carries a change.
3843///
3844/// @return true iff the current diff node carries a change.
3845bool
3847{return first_pointer() != second_pointer();}
3848
3849/// @return the kind of local change carried by the current diff node.
3850/// The value returned is zero if the current node carries no local
3851/// change.
3852enum change_kind
3854{
3855 ir::change_kind k = ir::NO_CHANGE_KIND;
3856 if (!equals(*first_pointer(), *second_pointer(), &k))
3857 return k & ir::ALL_LOCAL_CHANGES_MASK;
3858 return ir::NO_CHANGE_KIND;
3859}
3860
3861/// Getter for the diff between the pointed-to types of the pointers
3862/// of this diff.
3863///
3864/// @return the diff between the pointed-to types.
3867{return priv_->underlying_type_diff_;}
3868
3869/// Setter for the diff between the pointed-to types of the pointers
3870/// of this diff.
3871///
3872/// @param d the new diff between the pointed-to types of the pointers
3873/// of this diff.
3874void
3876{priv_->underlying_type_diff_ = d;}
3877
3878/// Report the diff in a serialized form.
3879///
3880/// @param out the stream to serialize the diff to.
3881///
3882/// @param indent the prefix to use for the indentation of this
3883/// serialization.
3884void
3885pointer_diff::report(ostream& out, const string& indent) const
3886{
3887 context()->get_reporter()->report(*this, out, indent);
3888}
3889
3890/// Compute the diff between between two pointers.
3891///
3892/// Note that the two types must have been created in the same @ref
3893/// environment, otherwise, this function aborts.
3894///
3895/// @param first the pointer to consider for the diff.
3896///
3897/// @param second the pointer to consider for the diff.
3898///
3899/// @return the resulting diff between the two pointers.
3900///
3901/// @param ctxt the diff context to use.
3904 pointer_type_def_sptr second,
3905 diff_context_sptr ctxt)
3906{
3907 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3908 second->get_pointed_to_type(),
3909 ctxt);
3910 pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3911 ctxt->initialize_canonical_diff(result);
3912
3913 return result;
3914}
3915
3916// </pointer_type_def>
3917
3918// <subrange_diff >
3919
3920/// Constructor of the @ref subrange_diff diff node type.
3921///
3922/// @param first the first subrange type to consider for the diff.
3923///
3924/// @param second the second subrange type to consider for the diff.
3925///
3926/// @param underlying_type_diff the underlying type diff between @p
3927/// first and @p second.
3928///
3929/// @param ctxt the diff context to use.
3931(const array_type_def::subrange_sptr& first,
3932 const array_type_def::subrange_sptr& second,
3933 const diff_sptr& underlying_type_diff,
3934 const diff_context_sptr ctxt)
3935 : type_diff_base(first, second, ctxt),
3936 priv_(new priv(underlying_type_diff))
3937{}
3938
3939
3940/// Getter of the first subrange of the current instance @ref
3941/// subrange_diff.
3942///
3943/// @return The first subrange of the current instance @ref subrange_diff.
3947
3948/// Getter of the second subrange of the current instance @ref
3949/// subrange_diff.
3950///
3951/// @return The second subrange of the current instance @ref
3952/// subrange_diff.
3956
3957/// Getter of the diff node of the underlying types of the current
3958/// @ref subrange_diff diff node.
3959///
3960/// @return The diff node of the underlying types of the current @ref
3961/// subrange_diff diff node.
3962const diff_sptr
3964{return priv_->underlying_type_diff_;}
3965
3966/// Getter the pretty representation of the @ref subrange_diff diff
3967/// node.
3968///
3969/// @return The pretty representation of the @ref subrange_diff diff node.
3970const string&
3972{
3973 if (diff::priv_->pretty_representation_.empty())
3974 {
3975 std::ostringstream o;
3976 o << "subrange_diff["
3977 << first_subject()->get_pretty_representation()
3978 << ","
3979 << second_subject()->get_pretty_representation()
3980 << "]";
3981 diff::priv_->pretty_representation_ = o.str();
3982 }
3983 return diff::priv_->pretty_representation_;
3984}
3985
3986/// Test if the current @ref subrange_diff node carries any change.
3987///
3988/// @return true iff the current @ref subrange_diff node carries any
3989/// change.
3990bool
3992{return *first_subrange() != *second_subrange();}
3993
3994/// Test if the current @ref subrange_diff node carries any local
3995/// change.
3996///
3997/// @return true iff the current @ref subrange_diff node carries any
3998/// local change.
3999enum change_kind
4001{
4002 ir::change_kind k = ir::NO_CHANGE_KIND;
4003 if (!equals(*first_subrange(), *second_subrange(), &k))
4004 return k & ir::ALL_LOCAL_CHANGES_MASK;
4005 return ir::NO_CHANGE_KIND;
4006}
4007
4008/// Report about the changes carried by this node.
4009///
4010/// @param out the output stream to send the report to.
4011///
4012/// @param indent the indentation string to use.
4013void
4014subrange_diff::report(ostream& out, const string& indent) const
4015{context()->get_reporter()->report(*this, out, indent);}
4016
4017/// Populate the vector of children node of the @ref diff base type
4018/// sub-object of this instance of @ref subrange_diff.
4019///
4020/// The children node can then later be retrieved using
4021/// diff::children_node().
4022void
4025
4026/// Compute the diff between two instances of @ref subrange_diff.
4027///
4028/// Note that the two decls must have been created in the same @ref
4029/// environment, otherwise, this function aborts.
4030///
4031/// @param first the first @ref subrange_diff to consider for the diff.
4032///
4033/// @param second the second @ref subrange_diff to consider for the diff.
4034///
4035/// @param ctxt the diff context to use.
4036///
4037/// @return the resulting diff between the two @ref subrange_diff.
4041 diff_context_sptr ctxt)
4042{
4043 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4044 second->get_underlying_type(),
4045 ctxt);
4046
4047 subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
4048 ctxt->initialize_canonical_diff(result);
4049 return result;
4050}
4051
4052//</subrange_diff >
4053
4054
4055// <array_type_def>
4056
4057/// Populate the vector of children node of the @ref diff base type
4058/// sub-object of this instance of @ref array_diff.
4059///
4060/// The children node can then later be retrieved using
4061/// diff::children_node().
4062void
4064{
4066 for (const auto& subrange_diff : subrange_diffs())
4068}
4069
4070/// Constructor for array_diff
4071///
4072/// @param first the first array_type of the diff.
4073///
4074/// @param second the second array_type of the diff.
4075///
4076/// @param element_type_diff the diff between the two array element
4077/// types.
4078///
4079/// @param ctxt the diff context to use.
4081 const array_type_def_sptr second,
4082 diff_sptr element_type_diff,
4083 vector<subrange_diff_sptr>& subrange_diffs,
4084 diff_context_sptr ctxt)
4085 : type_diff_base(first, second, ctxt),
4086 priv_(new priv(element_type_diff, subrange_diffs))
4087{}
4088
4089/// Getter for the first array of the diff.
4090///
4091/// @return the first array of the diff.
4094{return dynamic_pointer_cast<array_type_def>(first_subject());}
4095
4096/// Getter for the second array of the diff.
4097///
4098/// @return for the second array of the diff.
4101{return dynamic_pointer_cast<array_type_def>(second_subject());}
4102
4103/// Getter for the diff between the two types of array elements.
4104///
4105/// @return the diff between the two types of array elements.
4106const diff_sptr&
4108{return priv_->element_type_diff_;}
4109
4110/// Getter for the diffs between the array subranges.
4111///
4112/// @return the diffs between the array subranges.
4113const vector<subrange_diff_sptr>&
4115{return priv_->subrange_diffs_;}
4116
4117/// Test if any subrange diff is to be reported.
4118///
4119/// @return true if any subrange diff is to be reported, false
4120/// otherwise.
4121bool
4123{
4124 for (const auto& diff: subrange_diffs())
4125 if (diff->to_be_reported())
4126 return true;
4127
4128 return false;
4129}
4130
4131/// Setter for the diff between the two array element types.
4132///
4133/// @param d the new diff between the two array element types.
4134void
4136{priv_->element_type_diff_ = d;}
4137
4138/// Setter for the diff between the two sets of array sub-ranges.
4139///
4140/// @param d the new diff between the two sets of array sub-ranges.
4141void
4142array_diff::subrange_diffs(const vector<subrange_diff_sptr>& d)
4143{priv_->subrange_diffs_ = d;}
4144
4145/// @return the pretty representation for the current instance of @ref
4146/// array_diff.
4147const string&
4149{
4150 if (diff::priv_->pretty_representation_.empty())
4151 {
4152 std::ostringstream o;
4153 o << "array_diff["
4154 << first_subject()->get_pretty_representation()
4155 << ", "
4156 << second_subject()->get_pretty_representation()
4157 << "]";
4158 diff::priv_->pretty_representation_ = o.str();
4159 }
4160 return diff::priv_->pretty_representation_;
4161}
4162
4163/// Return true iff the current diff node carries a change.
4164///
4165/// @return true iff the current diff node carries a change.
4166bool
4168{
4169 bool l = false;
4170
4171 // the array element types match check for differing dimensions
4172 // etc...
4174 f = dynamic_pointer_cast<array_type_def>(first_subject()),
4175 s = dynamic_pointer_cast<array_type_def>(second_subject());
4176
4177 if (f->get_name() != s->get_name())
4178 l |= true;
4179 if (f->get_size_in_bits() != s->get_size_in_bits())
4180 l |= true;
4181 if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
4182 l |= true;
4183
4184 l |= element_type_diff()
4185 ? element_type_diff()->has_changes()
4186 : false;
4187
4188 for (const auto& subrange_diff : subrange_diffs())
4189 l |= subrange_diff->has_changes();
4190
4191 return l;
4192}
4193
4194
4195/// @return the kind of local change carried by the current diff node.
4196/// The value returned is zero if the current node carries no local
4197/// change.
4198enum change_kind
4200{
4201 ir::change_kind k = ir::NO_CHANGE_KIND;
4202 if (!equals(*first_array(), *second_array(), &k))
4203 return k & ir::ALL_LOCAL_CHANGES_MASK;
4204 return ir::NO_CHANGE_KIND;
4205}
4206
4207/// Report the diff in a serialized form.
4208///
4209/// @param out the output stream to serialize the dif to.
4210///
4211/// @param indent the string to use for indenting the report.
4212void
4213array_diff::report(ostream& out, const string& indent) const
4214{
4215 context()->get_reporter()->report(*this, out, indent);
4216}
4217
4218/// Compute the diff between two arrays.
4219///
4220/// Note that the two types must have been created in the same @ref
4221/// environment, otherwise, this function aborts.
4222///
4223/// @param first the first array to consider for the diff.
4224///
4225/// @param second the second array to consider for the diff.
4226///
4227/// @param ctxt the diff context to use.
4230 array_type_def_sptr second,
4231 diff_context_sptr ctxt)
4232{
4233 diff_sptr element_diff = compute_diff_for_types(first->get_element_type(),
4234 second->get_element_type(),
4235 ctxt);
4236 vector<subrange_diff_sptr> subrange_diffs;
4237 if (first->get_subranges().size() == first->get_subranges().size())
4238 {
4239 for (unsigned i = 0; i < first->get_subranges().size(); ++i)
4240 {
4242 compute_diff(first->get_subranges()[i],
4243 second->get_subranges()[i],
4244 ctxt);
4245 subrange_diffs.push_back(subrange_diff);
4246 }
4247 }
4248 array_diff_sptr result(new array_diff(first, second,
4249 element_diff,
4250 subrange_diffs,
4251 ctxt));
4252 ctxt->initialize_canonical_diff(result);
4253 return result;
4254}
4255// </array_type_def>
4256
4257// <reference_type_def>
4258
4259/// Populate the vector of children node of the @ref diff base type
4260/// sub-object of this instance of @ref reference_diff.
4261///
4262/// The children node can then later be retrieved using
4263/// diff::children_node().
4264void
4267
4268/// Constructor for reference_diff
4269///
4270/// @param first the first reference_type of the diff.
4271///
4272/// @param second the second reference_type of the diff.
4273///
4274/// @param ctxt the diff context to use.
4276 const reference_type_def_sptr second,
4277 diff_sptr underlying,
4278 diff_context_sptr ctxt)
4279 : type_diff_base(first, second, ctxt),
4280 priv_(new priv(underlying))
4281{}
4282
4283/// Getter for the first reference of the diff.
4284///
4285/// @return the first reference of the diff.
4288{return dynamic_pointer_cast<reference_type_def>(first_subject());}
4289
4290/// Getter for the second reference of the diff.
4291///
4292/// @return for the second reference of the diff.
4295{return dynamic_pointer_cast<reference_type_def>(second_subject());}
4296
4297
4298/// Getter for the diff between the two referred-to types.
4299///
4300/// @return the diff between the two referred-to types.
4301const diff_sptr&
4303{return priv_->underlying_type_diff_;}
4304
4305/// Setter for the diff between the two referred-to types.
4306///
4307/// @param d the new diff betweend the two referred-to types.
4308diff_sptr&
4310{
4311 priv_->underlying_type_diff_ = d;
4312 return priv_->underlying_type_diff_;
4313}
4314
4315/// @return the pretty representation for the current instance of @ref
4316/// reference_diff.
4317const string&
4319{
4320 if (diff::priv_->pretty_representation_.empty())
4321 {
4322 std::ostringstream o;
4323 o << "reference_diff["
4324 << first_subject()->get_pretty_representation()
4325 << ", "
4326 << second_subject()->get_pretty_representation()
4327 << "]";
4328 diff::priv_->pretty_representation_ = o.str();
4329 }
4330 return diff::priv_->pretty_representation_;
4331}
4332
4333/// Return true iff the current diff node carries a change.
4334///
4335/// @return true iff the current diff node carries a change.
4336bool
4338{
4339 return first_reference() != second_reference();
4340}
4341
4342/// @return the kind of local change carried by the current diff node.
4343/// The value returned is zero if the current node carries no local
4344/// change.
4345enum change_kind
4347{
4348 ir::change_kind k = ir::NO_CHANGE_KIND;
4349 if (!equals(*first_reference(), *second_reference(), &k))
4350 return k & ir::ALL_LOCAL_CHANGES_MASK;
4351 return ir::NO_CHANGE_KIND;
4352}
4353
4354/// Report the diff in a serialized form.
4355///
4356/// @param out the output stream to serialize the dif to.
4357///
4358/// @param indent the string to use for indenting the report.
4359void
4360reference_diff::report(ostream& out, const string& indent) const
4361{
4362 context()->get_reporter()->report(*this, out, indent);
4363}
4364
4365/// Compute the diff between two references.
4366///
4367/// Note that the two types must have been created in the same @ref
4368/// environment, otherwise, this function aborts.
4369///
4370/// @param first the first reference to consider for the diff.
4371///
4372/// @param second the second reference to consider for the diff.
4373///
4374/// @param ctxt the diff context to use.
4378 diff_context_sptr ctxt)
4379{
4380 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4381 second->get_pointed_to_type(),
4382 ctxt);
4383 reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4384 ctxt->initialize_canonical_diff(result);
4385 return result;
4386}
4387// </reference_type_def>
4388
4389// <ptr_to_mbr_diff stuff>
4390
4391
4392/// Constructor of @ref ptr_to_mbr_diff.
4393///
4394/// @param first the first pointer-to-member subject of the diff.
4395///
4396/// @param second the second pointer-to-member subject of the diff.
4397///
4398/// @param member_type_diff the diff node carrying changes to the
4399/// member type of the pointer-to-member we are considering.
4400///
4401/// @param containing_type_diff the diff node carrying changes to the
4402/// containing type of the pointer-to-member we are considering.
4403///
4404/// @param ctxt the context of the diff we are considering.
4405ptr_to_mbr_diff::ptr_to_mbr_diff(const ptr_to_mbr_type_sptr& first,
4406 const ptr_to_mbr_type_sptr& second,
4407 const diff_sptr& member_type_diff,
4408 const diff_sptr& containing_type_diff,
4409 diff_context_sptr ctxt)
4410 : type_diff_base(first, second, ctxt),
4411 priv_(new priv(member_type_diff, containing_type_diff))
4412{}
4413
4414/// Getter of the first pointer-to-member subject of the current diff
4415/// node.
4416///
4417/// @return the first pointer-to-member subject of the current diff
4418/// node.
4421{return dynamic_pointer_cast<ptr_to_mbr_type>(first_subject());}
4422
4423/// Getter of the second pointer-to-member subject of the current diff
4424/// node.
4425///
4426/// @return the second pointer-to-member subject of the current diff
4427/// node.
4430{return dynamic_pointer_cast<ptr_to_mbr_type>(second_subject());}
4431
4432/// Getter of the diff node carrying changes to the member type of
4433/// first subject of the current diff node.
4434///
4435/// @return The diff node carrying changes to the member type of first
4436/// subject of the current diff node.
4437const diff_sptr
4439{return priv_->member_type_diff_;}
4440
4441/// Getter of the diff node carrying changes to the containing type of
4442/// first subject of the current diff node.
4443///
4444/// @return The diff node carrying changes to the containing type of
4445/// first subject of the current diff node.
4446const diff_sptr
4448{return priv_->containing_type_diff_;}
4449
4450/// Test whether the current diff node carries any change.
4451///
4452/// @return true iff the current diff node carries any change.
4453bool
4455{
4457}
4458
4459/// Test whether the current diff node carries any local change.
4460///
4461/// @return true iff the current diff node carries any local change.
4462enum change_kind
4464{
4465 ir::change_kind k = ir::NO_CHANGE_KIND;
4467 return k & ir::ALL_LOCAL_CHANGES_MASK;
4468 return ir::NO_CHANGE_KIND;
4469}
4470
4471/// Get the pretty representation of the current @ref ptr_to_mbr_diff
4472/// node.
4473///
4474/// @return the pretty representation of the current diff node.
4475const string&
4477{
4478 if (diff::priv_->pretty_representation_.empty())
4479 {
4480 std::ostringstream o;
4481 o << "ptr_to_mbr_diff["
4482 << first_subject()->get_pretty_representation()
4483 << ", "
4484 << second_subject()->get_pretty_representation()
4485 << "]";
4486 diff::priv_->pretty_representation_ = o.str();
4487 }
4488 return diff::priv_->pretty_representation_;
4489}
4490
4491void
4492ptr_to_mbr_diff::report(ostream& out, const string& indent) const
4493{
4494 context()->get_reporter()->report(*this, out, indent);
4495}
4496
4497/// Populate the vector of children node of the @ref diff base type
4498/// sub-object of this instance of @ref ptr_to_mbr_diff.
4499///
4500/// The children node can then later be retrieved using
4501/// diff::children_node().
4502void
4504{
4507}
4508
4509/// Destructor of @ref ptr_to_mbr_diff.
4511{
4512}
4513
4514/// Compute the diff between two @ref ptr_to_mbr_type types.
4515///
4516/// Note that the two types must have been created in the same @ref
4517/// environment, otherwise, this function aborts.
4518///
4519/// @param first the first pointer-to-member type to consider for the diff.
4520///
4521/// @param second the second pointer-to-member type to consider for the diff.
4522///
4523/// @param ctxt the diff context to use.
4526 const ptr_to_mbr_type_sptr& second,
4527 diff_context_sptr& ctxt)
4528{
4529 diff_sptr member_type_diff =
4530 compute_diff(is_type(first->get_member_type()),
4531 is_type(second->get_member_type()),
4532 ctxt);
4533
4534 diff_sptr containing_type_diff =
4535 compute_diff(is_type(first->get_containing_type()),
4536 is_type(second->get_containing_type()),
4537 ctxt);
4538
4539 ptr_to_mbr_diff_sptr result(new ptr_to_mbr_diff(first, second,
4540 member_type_diff,
4541 containing_type_diff,
4542 ctxt));
4543 ctxt->initialize_canonical_diff(result);
4544 return result;
4545}
4546
4547// </ptr_to_mbr_diff stuff>
4548
4549// <qualified_type_diff stuff>
4550
4551/// Populate the vector of children node of the @ref diff base type
4552/// sub-object of this instance of @ref qualified_type_diff.
4553///
4554/// The children node can then later be retrieved using
4555/// diff::children_node().
4556void
4559
4560/// Constructor for qualified_type_diff.
4561///
4562/// @param first the first qualified type of the diff.
4563///
4564/// @param second the second qualified type of the diff.
4565///
4566/// @param ctxt the diff context to use.
4567qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4568 qualified_type_def_sptr second,
4569 diff_sptr under,
4570 diff_context_sptr ctxt)
4571 : type_diff_base(first, second, ctxt),
4572 priv_(new priv(under))
4573{}
4574
4575/// Getter for the first qualified type of the diff.
4576///
4577/// @return the first qualified type of the diff.
4578const qualified_type_def_sptr
4580{return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4581
4582/// Getter for the second qualified type of the diff.
4583///
4584/// @return the second qualified type of the diff.
4585const qualified_type_def_sptr
4587{return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4588
4589/// Getter for the diff between the underlying types of the two
4590/// qualified types.
4591///
4592/// @return the diff between the underlying types of the two qualified
4593/// types.
4596{return priv_->underlying_type_diff;}
4597
4598/// Getter for the diff between the most underlying non-qualified
4599/// types of two qualified types.
4600///
4601/// @return the diff between the most underlying non-qualified types
4602/// of two qualified types.
4605{
4606 if (!priv_->leaf_underlying_type_diff)
4607 priv_->leaf_underlying_type_diff
4608 = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4610 context());
4611
4612 return priv_->leaf_underlying_type_diff;
4613}
4614
4615/// Setter for the diff between the underlying types of the two
4616/// qualified types.
4617///
4618/// @return the diff between the underlying types of the two qualified
4619/// types.
4620void
4622{priv_->underlying_type_diff = d;}
4623
4624/// @return the pretty representation of the current instance of @ref
4625/// qualified_type_diff.
4626const string&
4628{
4629 if (diff::priv_->pretty_representation_.empty())
4630 {
4631 std::ostringstream o;
4632 o << "qualified_type_diff["
4633 << first_subject()->get_pretty_representation()
4634 << ", "
4635 << second_subject()->get_pretty_representation()
4636 << "]";
4637 diff::priv_->pretty_representation_ = o.str();
4638 }
4639 return diff::priv_->pretty_representation_;
4640}
4641
4642/// Return true iff the current diff node carries a change.
4643///
4644/// @return true iff the current diff node carries a change.
4645bool
4648
4649/// @return the kind of local change carried by the current diff node.
4650/// The value returned is zero if the current node carries no local
4651/// change.
4652enum change_kind
4654{
4655 ir::change_kind k = ir::NO_CHANGE_KIND;
4657 return k & ir::ALL_LOCAL_CHANGES_MASK;
4658 return ir::NO_CHANGE_KIND;
4659}
4660
4661/// Report the diff in a serialized form.
4662///
4663/// @param out the output stream to serialize to.
4664///
4665/// @param indent the string to use to indent the lines of the report.
4666void
4667qualified_type_diff::report(ostream& out, const string& indent) const
4668{
4669 context()->get_reporter()->report(*this, out, indent);
4670}
4671
4672/// Compute the diff between two qualified types.
4673///
4674/// Note that the two types must have been created in the same @ref
4675/// environment, otherwise, this function aborts.
4676///
4677/// @param first the first qualified type to consider for the diff.
4678///
4679/// @param second the second qualified type to consider for the diff.
4680///
4681/// @param ctxt the diff context to use.
4682qualified_type_diff_sptr
4683compute_diff(const qualified_type_def_sptr first,
4684 const qualified_type_def_sptr second,
4685 diff_context_sptr ctxt)
4686{
4687 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4688 second->get_underlying_type(),
4689 ctxt);
4690 qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4691 d, ctxt));
4692 ctxt->initialize_canonical_diff(result);
4693 return result;
4694}
4695
4696// </qualified_type_diff stuff>
4697
4698// <enum_diff stuff>
4699
4700/// Clear the lookup tables useful for reporting an enum_diff.
4701///
4702/// This function must be updated each time a lookup table is added or
4703/// removed from the class_diff::priv.
4704void
4705enum_diff::clear_lookup_tables()
4706{
4707 priv_->deleted_enumerators_.clear();
4708 priv_->inserted_enumerators_.clear();
4709 priv_->changed_enumerators_.clear();
4710}
4711
4712/// Tests if the lookup tables are empty.
4713///
4714/// @return true if the lookup tables are empty, false otherwise.
4715bool
4716enum_diff::lookup_tables_empty() const
4717{
4718 return (priv_->deleted_enumerators_.empty()
4719 && priv_->inserted_enumerators_.empty()
4720 && priv_->changed_enumerators_.empty());
4721}
4722
4723/// If the lookup tables are not yet built, walk the differences and
4724/// fill the lookup tables.
4725void
4726enum_diff::ensure_lookup_tables_populated()
4727{
4728 if (!lookup_tables_empty())
4729 return;
4730
4731 {
4732 edit_script e = priv_->enumerators_changes_;
4733
4734 for (vector<deletion>::const_iterator it = e.deletions().begin();
4735 it != e.deletions().end();
4736 ++it)
4737 {
4738 unsigned i = it->index();
4739 const enum_type_decl::enumerator& n =
4740 first_enum()->get_enumerators()[i];
4741 const string& name = n.get_name();
4742 ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4743 == priv_->deleted_enumerators_.end());
4744 priv_->deleted_enumerators_[name] = n;
4745 }
4746
4747 for (vector<insertion>::const_iterator it = e.insertions().begin();
4748 it != e.insertions().end();
4749 ++it)
4750 {
4751 for (vector<unsigned>::const_iterator iit =
4752 it->inserted_indexes().begin();
4753 iit != it->inserted_indexes().end();
4754 ++iit)
4755 {
4756 unsigned i = *iit;
4757 const enum_type_decl::enumerator& n =
4758 second_enum()->get_enumerators()[i];
4759 const string& name = n.get_name();
4760 ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4761 == priv_->inserted_enumerators_.end());
4762 string_enumerator_map::const_iterator j =
4763 priv_->deleted_enumerators_.find(name);
4764 if (j == priv_->deleted_enumerators_.end())
4765 priv_->inserted_enumerators_[name] = n;
4766 else
4767 {
4768 if (j->second != n)
4769 priv_->changed_enumerators_[j->first] =
4770 std::make_pair(j->second, n);
4771 priv_->deleted_enumerators_.erase(j);
4772 }
4773 }
4774 }
4775
4776 // If a new enumerator is added with a value that already existed
4777 // in the old enum but with a new name, then populate the
4778 // enum_diff::priv_::changed_enumerators_ data member with a
4779 // change that represents a change to an enumerator name. The
4780 // enum_diff::priv_::inserted_enumerators_ is adjusted accordingly
4781 // an the 'new' enumerator is removed in this case.
4782
4783 enum_type_decl::enumerators enums_to_erase;
4784 for (auto& entry : priv_->inserted_enumerators_)
4785 {
4786 enum_type_decl::enumerator& final_enumerator = entry.second;
4787 enum_type_decl::enumerator initial_enumerator;
4788 if (first_enum()->find_enumerator_by_value(entry.second.get_value(),
4789 initial_enumerator))
4790 {
4791 enum_type_decl::enumerator foo;
4792 if (!second_enum()->
4793 find_enumerator_by_name(initial_enumerator.get_name(),
4794 foo))
4795 {
4796 priv_->changed_enumerators_[initial_enumerator.get_name()] =
4797 std::make_pair(initial_enumerator, final_enumerator);
4798 enums_to_erase.push_back(final_enumerator);
4799 }
4800 }
4801 }
4802
4803 for (auto& enomerator : enums_to_erase)
4804 priv_->inserted_enumerators_.erase(enomerator.get_name());
4805
4806 // If an enumerator is deleted yet its value (with a new name) is
4807 // still present among enumerators of the newer enum then populate
4808 // the enum_diff::priv_::changed_enumerators_ data member with a
4809 // change that represents a change to an enumerator name. The
4810 // enum_diff::priv_::deleted_enumerators_ is adjusted accordingly
4811 // an the 'new' enumerator is removed in this case.
4812
4813 enums_to_erase.clear();
4814 for (auto& entry : priv_->deleted_enumerators_)
4815 {
4816 enum_type_decl::enumerator& initial_enumerator = entry.second;
4817 enum_type_decl::enumerator final_enumerator;
4818 if (second_enum()->find_enumerator_by_value(entry.second.get_value(),
4819 final_enumerator))
4820 {
4821 enum_type_decl::enumerator foo;
4822 if (!first_enum()->
4823 find_enumerator_by_name(final_enumerator.get_name(),
4824 foo))
4825 {
4826 priv_->changed_enumerators_[initial_enumerator.get_name()] =
4827 std::make_pair(initial_enumerator, final_enumerator);
4828 enums_to_erase.push_back(initial_enumerator);
4829 }
4830 }
4831 }
4832
4833 for (auto& enomerator : enums_to_erase)
4834 priv_->deleted_enumerators_.erase(enomerator.get_name());
4835 }
4836}
4837
4838/// Populate the vector of children node of the @ref diff base type
4839/// sub-object of this instance of @ref enum_diff.
4840///
4841/// The children node can then later be retrieved using
4842/// diff::children_node().
4843void
4846
4847/// Constructor for enum_diff.
4848///
4849/// @param first the first enum type of the diff.
4850///
4851/// @param second the second enum type of the diff.
4852///
4853/// @param underlying_type_diff the diff of the two underlying types
4854/// of the two enum types.
4855///
4856/// @param ctxt the diff context to use.
4858 const enum_type_decl_sptr second,
4859 const diff_sptr underlying_type_diff,
4860 const diff_context_sptr ctxt)
4861 : type_diff_base(first, second, ctxt),
4862 priv_(new priv(underlying_type_diff))
4863{}
4864
4865/// @return the first enum of the diff.
4868{return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4869
4870/// @return the second enum of the diff.
4873{return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4874
4875/// @return the diff of the two underlying enum types.
4878{return priv_->underlying_type_diff_;}
4879
4880/// @return a map of the enumerators that were deleted.
4883{return priv_->deleted_enumerators_;}
4884
4885/// @return a map of the enumerators that were inserted
4888{return priv_->inserted_enumerators_;}
4889
4890/// @return a map of the enumerators that were changed
4893{return priv_->changed_enumerators_;}
4894
4895/// @return the pretty representation of the current instance of @ref
4896/// enum_diff.
4897const string&
4899{
4900 if (diff::priv_->pretty_representation_.empty())
4901 {
4902 std::ostringstream o;
4903 o << "enum_diff["
4904 << first_subject()->get_pretty_representation()
4905 << ", "
4906 << second_subject()->get_pretty_representation()
4907 << "]";
4908 diff::priv_->pretty_representation_ = o.str();
4909 }
4910 return diff::priv_->pretty_representation_;
4911}
4912
4913/// Return true iff the current diff node carries a change.
4914///
4915/// @return true iff the current diff node carries a change.
4916bool
4918{return first_enum() != second_enum();}
4919
4920/// @return the kind of local change carried by the current diff node.
4921/// The value returned is zero if the current node carries no local
4922/// change.
4923enum change_kind
4925{
4926 ir::change_kind k = ir::NO_CHANGE_KIND;
4927 if (!equals(*first_enum(), *second_enum(), &k))
4928 return k & ir::ALL_LOCAL_CHANGES_MASK;
4929 return ir::NO_CHANGE_KIND;
4930}
4931
4932/// Report the differences between the two enums.
4933///
4934/// @param out the output stream to send the report to.
4935///
4936/// @param indent the string to use for indentation.
4937void
4938enum_diff::report(ostream& out, const string& indent) const
4939{
4940 context()->get_reporter()->report(*this, out, indent);
4941}
4942
4943/// Compute the set of changes between two instances of @ref
4944/// enum_type_decl.
4945///
4946/// Note that the two types must have been created in the same @ref
4947/// environment, otherwise, this function aborts.
4948///
4949/// @param first a pointer to the first enum_type_decl to consider.
4950///
4951/// @param second a pointer to the second enum_type_decl to consider.
4952///
4953/// @return the resulting diff of the two enums @p first and @p
4954/// second.
4955///
4956/// @param ctxt the diff context to use.
4957enum_diff_sptr
4959 const enum_type_decl_sptr second,
4960 diff_context_sptr ctxt)
4961{
4962 diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4963 second->get_underlying_type(),
4964 ctxt);
4965 enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4966 if (first != second)
4967 {
4968 compute_diff(first->get_enumerators().begin(),
4969 first->get_enumerators().end(),
4970 second->get_enumerators().begin(),
4971 second->get_enumerators().end(),
4972 d->priv_->enumerators_changes_);
4973 d->ensure_lookup_tables_populated();
4974 }
4975 ctxt->initialize_canonical_diff(d);
4976
4977 return d;
4978}
4979// </enum_diff stuff>
4980
4981// <class_or_union_diff stuff>
4982
4983/// Test if the current diff node carries a member type change for a
4984/// member type which name is the same as the name of a given type
4985/// declaration.
4986///
4987/// @param d the type declaration which name should be equal to the
4988/// name of the member type that might have changed.
4989///
4990/// @return the member type that has changed, iff there were a member
4991/// type (which name is the same as the name of @p d) that changed.
4992/// Note that the member type that is returned is the new value of the
4993/// member type that changed.
4996{
4997 string qname = d->get_qualified_name();
4998 string_diff_sptr_map::const_iterator it =
4999 changed_member_types_.find(qname);
5000
5001 return ((it == changed_member_types_.end())
5003 : it->second->second_subject());
5004}
5005
5006/// Test if the current diff node carries a data member change for a
5007/// data member which name is the same as the name of a given type
5008/// declaration.
5009///
5010/// @param d the type declaration which name should be equal to the
5011/// name of the data member that might have changed.
5012///
5013/// @return the data member that has changed, iff there were a data
5014/// member type (which name is the same as the name of @p d) that
5015/// changed. Note that the data member that is returned is the new
5016/// value of the data member that changed.
5017decl_base_sptr
5019{
5020 string qname = d->get_qualified_name();
5021 string_var_diff_sptr_map::const_iterator it =
5022 subtype_changed_dm_.find(qname);
5023
5024 if (it == subtype_changed_dm_.end())
5025 return decl_base_sptr();
5026 return it->second->second_var();
5027}
5028
5029/// Test if the current diff node carries a member class template
5030/// change for a member class template which name is the same as the
5031/// name of a given type declaration.
5032///
5033/// @param d the type declaration which name should be equal to the
5034/// name of the member class template that might have changed.
5035///
5036/// @return the member class template that has changed, iff there were
5037/// a member class template (which name is the same as the name of @p
5038/// d) that changed. Note that the member class template that is
5039/// returned is the new value of the member class template that
5040/// changed.
5041decl_base_sptr
5043{
5044 string qname = d->get_qualified_name();
5045 string_diff_sptr_map::const_iterator it =
5046 changed_member_class_tmpls_.find(qname);
5047
5048 return ((it == changed_member_class_tmpls_.end())
5049 ? decl_base_sptr()
5050 : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
5051}
5052
5053/// Get the number of non static data members that were deleted.
5054///
5055/// @return the number of non static data members that were deleted.
5056size_t
5058{
5059 size_t result = 0;
5060
5061 for (string_decl_base_sptr_map::const_iterator i =
5062 deleted_data_members_.begin();
5063 i != deleted_data_members_.end();
5064 ++i)
5065 if (is_member_decl(i->second)
5066 && !get_member_is_static(i->second))
5067 ++result;
5068
5069 return result;
5070}
5071
5072/// Get the number of non static data members that were inserted.
5073///
5074/// @return the number of non static data members that were inserted.
5075size_t
5077{
5078 size_t result = 0;
5079
5080 for (string_decl_base_sptr_map::const_iterator i =
5081 inserted_data_members_.begin();
5082 i != inserted_data_members_.end();
5083 ++i)
5084 if (is_member_decl(i->second)
5085 && !get_member_is_static(i->second))
5086 ++result;
5087
5088 return result;
5089}
5090
5091/// Get the number of data member sub-type changes carried by the
5092/// current diff node that were filtered out.
5093///
5094/// @param local_only if true, it means that only (filtered) local
5095/// changes are considered.
5096///
5097/// @return the number of data member sub-type changes carried by the
5098/// current diff node that were filtered out.
5099size_t
5101{
5102 size_t num_filtered= 0;
5103 for (var_diff_sptrs_type::const_iterator i =
5104 sorted_subtype_changed_dm_.begin();
5105 i != sorted_subtype_changed_dm_.end();
5106 ++i)
5107 {
5108 if (local_only)
5109 {
5110 if ((*i)->has_local_changes() && (*i)->is_filtered_out())
5111 ++num_filtered;
5112 }
5113 else
5114 {
5115 if ((*i)->is_filtered_out())
5116 ++num_filtered;
5117 }
5118 }
5119 return num_filtered;
5120}
5121
5122/// Get the number of data member changes carried by the current diff
5123/// node that were filtered out.
5124///
5125/// @param local_only if true, it means that only (filtered) local
5126/// changes are considered.
5127///
5128/// @return the number of data member changes carried by the current
5129/// diff node that were filtered out.
5130size_t
5132{
5133 size_t num_filtered= 0;
5134
5135 for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
5136 i != changed_dm_.end();
5137 ++i)
5138 {
5139 diff_sptr diff = i->second;
5140 if (local_only)
5141 {
5142 if (diff->has_changes() && diff->is_filtered_out())
5143 ++num_filtered;
5144 }
5145 else
5146 {
5147 if (diff->is_filtered_out())
5148 ++num_filtered;
5149 }
5150 }
5151 return num_filtered;
5152}
5153
5154/// Skip the processing of the current member function if its
5155/// virtual-ness is disallowed by the user.
5156///
5157/// This is to be used in the member functions below that are used to
5158/// count the number of filtered inserted, deleted and changed member
5159/// functions.
5160#define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
5161 do { \
5162 if (get_member_function_is_virtual(f) \
5163 || get_member_function_is_virtual(s)) \
5164 { \
5165 if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
5166 continue; \
5167 } \
5168 else \
5169 { \
5170 if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
5171 continue; \
5172 } \
5173 } while (false)
5174
5175/// Get the number of member functions changes carried by the current
5176/// diff node that were filtered out.
5177///
5178/// @return the number of member functions changes carried by the
5179/// current diff node that were filtered out.
5180size_t
5182(const diff_context_sptr& ctxt)
5183{
5184 size_t count = 0;
5185 diff_category allowed_category = ctxt->get_allowed_category();
5186
5187 for (function_decl_diff_sptrs_type::const_iterator i =
5188 sorted_changed_member_functions_.begin();
5189 i != sorted_changed_member_functions_.end();
5190 ++i)
5191 {
5192 method_decl_sptr f =
5193 dynamic_pointer_cast<method_decl>
5194 ((*i)->first_function_decl());
5195 ABG_ASSERT(f);
5196
5197 method_decl_sptr s =
5198 dynamic_pointer_cast<method_decl>
5199 ((*i)->second_function_decl());
5200 ABG_ASSERT(s);
5201
5203
5204 diff_sptr diff = *i;
5205 ctxt->maybe_apply_filters(diff);
5206
5207 if (diff->is_filtered_out())
5208 ++count;
5209 }
5210
5211 return count;
5212}
5213
5214/// Get the number of member functions insertions carried by the current
5215/// diff node that were filtered out.
5216///
5217/// @return the number of member functions insertions carried by the
5218/// current diff node that were filtered out.
5219size_t
5221(const diff_context_sptr& ctxt)
5222{
5223 size_t count = 0;
5224 diff_category allowed_category = ctxt->get_allowed_category();
5225
5226 for (string_member_function_sptr_map::const_iterator i =
5227 inserted_member_functions_.begin();
5228 i != inserted_member_functions_.end();
5229 ++i)
5230 {
5231 method_decl_sptr f = i->second,
5232 s = i->second;
5233
5235
5236 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5237 ctxt->maybe_apply_filters(diff);
5238
5240 && diff->is_filtered_out())
5241 ++count;
5242 }
5243
5244 return count;
5245}
5246
5247/// Get the number of member functions deletions carried by the current
5248/// diff node that were filtered out.
5249///
5250/// @return the number of member functions deletions carried by the
5251/// current diff node that were filtered out.
5252size_t
5254(const diff_context_sptr& ctxt)
5255{
5256 size_t count = 0;
5257 diff_category allowed_category = ctxt->get_allowed_category();
5258
5259 for (string_member_function_sptr_map::const_iterator i =
5260 deleted_member_functions_.begin();
5261 i != deleted_member_functions_.end();
5262 ++i)
5263 {
5264 method_decl_sptr f = i->second,
5265 s = i->second;
5266
5268
5269 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5270 ctxt->maybe_apply_filters(diff);
5271
5273 && diff->is_filtered_out())
5274 ++count;
5275 }
5276
5277 return count;
5278}
5279
5280/// Clear the lookup tables useful for reporting.
5281///
5282/// This function must be updated each time a lookup table is added or
5283/// removed from the class_or_union_diff::priv.
5284void
5286{
5287 priv_->deleted_member_types_.clear();
5288 priv_->inserted_member_types_.clear();
5289 priv_->changed_member_types_.clear();
5290 priv_->deleted_data_members_.clear();
5291 priv_->inserted_data_members_.clear();
5292 priv_->subtype_changed_dm_.clear();
5293 priv_->deleted_member_functions_.clear();
5294 priv_->inserted_member_functions_.clear();
5295 priv_->changed_member_functions_.clear();
5296 priv_->deleted_member_class_tmpls_.clear();
5297 priv_->inserted_member_class_tmpls_.clear();
5298 priv_->changed_member_class_tmpls_.clear();
5299}
5300
5301/// Tests if the lookup tables are empty.
5302///
5303/// @return true if the lookup tables are empty, false otherwise.
5304bool
5306{
5307 return (priv_->deleted_member_types_.empty()
5308 && priv_->inserted_member_types_.empty()
5309 && priv_->changed_member_types_.empty()
5310 && priv_->deleted_data_members_.empty()
5311 && priv_->inserted_data_members_.empty()
5312 && priv_->subtype_changed_dm_.empty()
5313 && priv_->inserted_member_functions_.empty()
5314 && priv_->deleted_member_functions_.empty()
5315 && priv_->changed_member_functions_.empty()
5316 && priv_->deleted_member_class_tmpls_.empty()
5317 && priv_->inserted_member_class_tmpls_.empty()
5318 && priv_->changed_member_class_tmpls_.empty());
5319}
5320
5321/// If the lookup tables are not yet built, walk the differences and
5322/// fill them.
5323void
5325{
5326 {
5327 edit_script& e = priv_->member_types_changes_;
5328
5329 for (vector<deletion>::const_iterator it = e.deletions().begin();
5330 it != e.deletions().end();
5331 ++it)
5332 {
5333 unsigned i = it->index();
5334 decl_base_sptr d =
5335 get_type_declaration(first_class_or_union()->get_member_types()[i]);
5336 class_or_union_sptr record_type = is_class_or_union_type(d);
5337 if (record_type && record_type->get_is_declaration_only())
5338 continue;
5339 string name = d->get_name();
5340 priv_->deleted_member_types_[name] = d;
5341 }
5342
5343 for (vector<insertion>::const_iterator it = e.insertions().begin();
5344 it != e.insertions().end();
5345 ++it)
5346 {
5347 for (vector<unsigned>::const_iterator iit =
5348 it->inserted_indexes().begin();
5349 iit != it->inserted_indexes().end();
5350 ++iit)
5351 {
5352 unsigned i = *iit;
5353 decl_base_sptr d =
5354 get_type_declaration(second_class_or_union()->get_member_types()[i]);
5355 class_or_union_sptr record_type = is_class_or_union_type(d);
5356 if (record_type && record_type->get_is_declaration_only())
5357 continue;
5358 string name = d->get_name();
5359 string_decl_base_sptr_map::const_iterator j =
5360 priv_->deleted_member_types_.find(name);
5361 if (j != priv_->deleted_member_types_.end())
5362 {
5363 if (*j->second != *d)
5364 priv_->changed_member_types_[name] =
5365 compute_diff(j->second, d, context());
5366
5367 priv_->deleted_member_types_.erase(j);
5368 }
5369 else
5370 priv_->inserted_member_types_[name] = d;
5371 }
5372 }
5373 }
5374
5375 {
5376 edit_script& e = priv_->data_members_changes_;
5377
5378 for (vector<deletion>::const_iterator it = e.deletions().begin();
5379 it != e.deletions().end();
5380 ++it)
5381 {
5382 unsigned i = it->index();
5383 var_decl_sptr data_member =
5384 is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
5385 string name = data_member->get_anon_dm_reliable_name();
5386
5387 ABG_ASSERT(priv_->deleted_data_members_.find(name)
5388 == priv_->deleted_data_members_.end());
5389 priv_->deleted_data_members_[name] = data_member;
5390 }
5391
5392 for (vector<insertion>::const_iterator it = e.insertions().begin();
5393 it != e.insertions().end();
5394 ++it)
5395 {
5396 for (vector<unsigned>::const_iterator iit =
5397 it->inserted_indexes().begin();
5398 iit != it->inserted_indexes().end();
5399 ++iit)
5400 {
5401 unsigned i = *iit;
5402 decl_base_sptr d =
5403 second_class_or_union()->get_non_static_data_members()[i];
5404 var_decl_sptr added_dm = is_var_decl(d);
5405 string name = added_dm->get_anon_dm_reliable_name();
5406 ABG_ASSERT(priv_->inserted_data_members_.find(name)
5407 == priv_->inserted_data_members_.end());
5408
5409 bool ignore_added_anonymous_data_member = false;
5410 if (is_anonymous_data_member(added_dm))
5411 {
5412 //
5413 // Handle insertion of anonymous data member to
5414 // replace existing data members.
5415 //
5416 // For instance consider this:
5417 // struct S
5418 // {
5419 // int a;
5420 // int b;
5421 // int c;
5422 // };// end struct S
5423 //
5424 // Where the data members 'a' and 'b' are replaced
5425 // by an anonymous data member without changing the
5426 // effective bit layout of the structure:
5427 //
5428 // struct S
5429 // {
5430 // struct
5431 // {
5432 // union
5433 // {
5434 // int a;
5435 // char a_1;
5436 // };
5437 // union
5438 // {
5439 // int b;
5440 // char b_1;
5441 // };
5442 // };
5443 // int c;
5444 // }; // end struct S
5445 //
5446 var_decl_sptr replaced_dm, replacing_dm;
5447 bool added_anon_dm_changes_dm = false;
5448 // The vector of data members replaced by anonymous
5449 // data members.
5450 vector<var_decl_sptr> dms_replaced_by_anon_dm;
5451
5452 //
5453 // Let's start collecting the set of data members
5454 // which have been replaced by anonymous types in a
5455 // harmless way. These are going to be collected into
5456 // dms_replaced_by_anon_dm and, ultimately, into
5457 // priv_->dms_replaced_by_adms_
5458 //
5459 for (string_decl_base_sptr_map::const_iterator it =
5460 priv_->deleted_data_members_.begin();
5461 it != priv_->deleted_data_members_.end();
5462 ++it)
5463 {
5464 // We don't support this pattern for anonymous
5465 // data members themselves being replaced. If
5466 // that occurs then we'll just report it verbatim.
5467 if (is_anonymous_data_member(it->second))
5468 continue;
5469
5470 string deleted_dm_name = it->second->get_name();
5471 if ((replacing_dm =
5473 deleted_dm_name)))
5474 {
5475 // So it looks like replacing_dm might have
5476 // replaced the data member which name is
5477 // 'deleted_dm_name'. Let's look deeper to be
5478 // sure.
5479 //
5480 // Note that replacing_dm is part (member) of
5481 // an anonymous data member that might replace
5482 // replaced_dm.
5483
5484 // So let's get that replaced data member.
5485 replaced_dm = is_var_decl(it->second);
5486 size_t replaced_dm_offset =
5487 get_data_member_offset(replaced_dm),
5488 replacing_dm_offset =
5489 get_absolute_data_member_offset(replacing_dm);
5490
5491 if (replaced_dm_offset != replacing_dm_offset)
5492 {
5493 // So the replacing data member and the
5494 // replaced data member don't have the
5495 // same offset. This is not the pattern we
5496 // are looking for. Rather, it looks like
5497 // the anonymous data member has *changed*
5498 // the data member.
5499 added_anon_dm_changes_dm = true;
5500 break;
5501 }
5502
5503 if (replaced_dm->get_type()->get_size_in_bits()
5504 == replaced_dm->get_type()->get_size_in_bits())
5505 dms_replaced_by_anon_dm.push_back(replaced_dm);
5506 else
5507 {
5508 added_anon_dm_changes_dm = true;
5509 break;
5510 }
5511 }
5512 }
5513
5514 // Now walk dms_replaced_by_anon_dm to fill up
5515 // priv_->dms_replaced_by_adms_ with the set of data
5516 // members replaced by anonymous data members.
5517 if (!added_anon_dm_changes_dm
5518 && !dms_replaced_by_anon_dm.empty())
5519 {
5520 // See if the added data member isn't too big.
5521 type_base_sptr added_dm_type = added_dm->get_type();
5522 ABG_ASSERT(added_dm_type);
5523 var_decl_sptr new_next_dm =
5525 added_dm);
5526 var_decl_sptr old_next_dm =
5527 first_class_or_union()->find_data_member(new_next_dm);
5528
5529 if (!old_next_dm
5530 || (old_next_dm
5531 && (get_absolute_data_member_offset(old_next_dm)
5532 == get_absolute_data_member_offset(new_next_dm))))
5533 {
5534 // None of the data members that are replaced
5535 // by the added union should be considered as
5536 // having been deleted.
5537 ignore_added_anonymous_data_member = true;
5538 for (vector<var_decl_sptr>::const_iterator i =
5539 dms_replaced_by_anon_dm.begin();
5540 i != dms_replaced_by_anon_dm.end();
5541 ++i)
5542 {
5543 string n = (*i)->get_name();
5544 priv_->dms_replaced_by_adms_[n] =
5545 added_dm;
5546 priv_->deleted_data_members_.erase(n);
5547 }
5548 }
5549 }
5550 }
5551
5552 if (!ignore_added_anonymous_data_member)
5553 {
5554 // Detect changed data members.
5555 //
5556 // A changed data member (that we shall name D) is a data
5557 // member that satisfies the conditions below:
5558 //
5559 // 1/ It must have been added.
5560 //
5561 // 2/ It must have been deleted as well.
5562 //
5563 // 3/ There must be a non-empty difference between the
5564 // deleted D and the added D.
5565 string_decl_base_sptr_map::const_iterator j =
5566 priv_->deleted_data_members_.find(name);
5567 if (j != priv_->deleted_data_members_.end())
5568 {
5569 if (*j->second != *d)
5570 {
5571 var_decl_sptr old_dm = is_var_decl(j->second);
5572 priv_->subtype_changed_dm_[name]=
5573 compute_diff(old_dm, added_dm, context());
5574 }
5575 priv_->deleted_data_members_.erase(j);
5576 }
5577 else
5578 priv_->inserted_data_members_[name] = d;
5579 }
5580 }
5581 }
5582
5583 // Now detect when a data member is deleted from offset N and
5584 // another one is added to offset N. In that case, we want to be
5585 // able to say that the data member at offset N changed.
5586 for (string_decl_base_sptr_map::const_iterator i =
5587 priv_->deleted_data_members_.begin();
5588 i != priv_->deleted_data_members_.end();
5589 ++i)
5590 {
5591 unsigned offset = get_data_member_offset(i->second);
5592 priv_->deleted_dm_by_offset_[offset] = i->second;
5593 }
5594
5595 for (string_decl_base_sptr_map::const_iterator i =
5596 priv_->inserted_data_members_.begin();
5597 i != priv_->inserted_data_members_.end();
5598 ++i)
5599 {
5600 unsigned offset = get_data_member_offset(i->second);
5601 priv_->inserted_dm_by_offset_[offset] = i->second;
5602 }
5603
5604 for (unsigned_decl_base_sptr_map::const_iterator i =
5605 priv_->inserted_dm_by_offset_.begin();
5606 i != priv_->inserted_dm_by_offset_.end();
5607 ++i)
5608 {
5609 unsigned_decl_base_sptr_map::const_iterator j =
5610 priv_->deleted_dm_by_offset_.find(i->first);
5611 if (j != priv_->deleted_dm_by_offset_.end())
5612 {
5613 var_decl_sptr old_dm = is_var_decl(j->second);
5614 var_decl_sptr new_dm = is_var_decl(i->second);
5615 priv_->changed_dm_[i->first] =
5616 compute_diff(old_dm, new_dm, context());
5617 }
5618 }
5619
5620 for (unsigned_var_diff_sptr_map::const_iterator i =
5621 priv_->changed_dm_.begin();
5622 i != priv_->changed_dm_.end();
5623 ++i)
5624 {
5625 priv_->deleted_dm_by_offset_.erase(i->first);
5626 priv_->inserted_dm_by_offset_.erase(i->first);
5627 priv_->deleted_data_members_.erase
5628 (i->second->first_var()->get_anon_dm_reliable_name());
5629 priv_->inserted_data_members_.erase
5630 (i->second->second_var()->get_anon_dm_reliable_name());
5631 }
5632
5633 // Now detect anonymous data members that might appear as deleted
5634 // even though all their data members are still present. Consider
5635 // these as being non-deleted.
5636 string_decl_base_sptr_map non_anonymous_dms_in_second_class;
5638 non_anonymous_dms_in_second_class);
5639 vector<string> deleted_data_members_to_delete;
5640 // Walk data members considered deleted ...
5641 for (auto& entry : priv_->deleted_data_members_)
5642 {
5643 var_decl_sptr data_member = is_var_decl(entry.second);
5644 ABG_ASSERT(data_member);
5645 if (is_anonymous_data_member(data_member))
5646 {
5647 // Let's look at this anonymous data member that is
5648 // considered deleted because it's moved from where it was
5649 // initially, at very least. If its leaf data members are
5650 // still present in the second class then, we won't
5651 // consider it as deleted.
5652 class_or_union_sptr cou = anonymous_data_member_to_class_or_union(data_member);
5653 ABG_ASSERT(cou);
5654 string_decl_base_sptr_map non_anonymous_data_members;
5655 // Lets collect the leaf data members of the anonymous
5656 // data member.
5657 collect_non_anonymous_data_members(cou, non_anonymous_data_members);
5658 bool anonymous_dm_members_present = true;
5659 // Let's see if at least one of the leaf members of the
5660 // anonymous data member is NOT present in the second
5661 // version of the class.
5662 for (auto& e : non_anonymous_data_members)
5663 {
5664 if (non_anonymous_dms_in_second_class.find(e.first)
5665 == non_anonymous_dms_in_second_class.end())
5666 // Grrr, OK, it looks like at least one leaf data
5667 // member of the original anonymous data member was
5668 // removed from the class, so yeah, the anonymous
5669 // data member might have been removed after all.
5670 anonymous_dm_members_present = false;
5671 }
5672 if (anonymous_dm_members_present)
5673 // All leaf data members of the anonymous data member
5674 // are still present in the second version of the class.
5675 // So let's mark that anonymous data member as NOT being
5676 // deleted.
5677 deleted_data_members_to_delete.push_back(data_member->get_anon_dm_reliable_name());
5678 }
5679 }
5680 // All anonymous data members that were recognized as being NOT
5681 // deleted should be removed from the set of deleted data members
5682 // now.
5683 for (string& name_of_dm_to_delete: deleted_data_members_to_delete)
5684 priv_->deleted_data_members_.erase(name_of_dm_to_delete);
5685 }
5686 sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5687 priv_->sorted_subtype_changed_dm_);
5688 sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5689 priv_->sorted_changed_dm_);
5690
5691 {
5692 edit_script& e = priv_->member_class_tmpls_changes_;
5693
5694 for (vector<deletion>::const_iterator it = e.deletions().begin();
5695 it != e.deletions().end();
5696 ++it)
5697 {
5698 unsigned i = it->index();
5699 decl_base_sptr d =
5700 first_class_or_union()->get_member_class_templates()[i]->
5701 as_class_tdecl();
5702 string name = d->get_name();
5703 ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5704 == priv_->deleted_member_class_tmpls_.end());
5705 priv_->deleted_member_class_tmpls_[name] = d;
5706 }
5707
5708 for (vector<insertion>::const_iterator it = e.insertions().begin();
5709 it != e.insertions().end();
5710 ++it)
5711 {
5712 for (vector<unsigned>::const_iterator iit =
5713 it->inserted_indexes().begin();
5714 iit != it->inserted_indexes().end();
5715 ++iit)
5716 {
5717 unsigned i = *iit;
5718 decl_base_sptr d =
5719 second_class_or_union()->get_member_class_templates()[i]->
5720 as_class_tdecl();
5721 string name = d->get_name();
5722 ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5723 == priv_->inserted_member_class_tmpls_.end());
5724 string_decl_base_sptr_map::const_iterator j =
5725 priv_->deleted_member_class_tmpls_.find(name);
5726 if (j != priv_->deleted_member_class_tmpls_.end())
5727 {
5728 if (*j->second != *d)
5729 priv_->changed_member_types_[name]=
5730 compute_diff(j->second, d, context());
5731 priv_->deleted_member_class_tmpls_.erase(j);
5732 }
5733 else
5734 priv_->inserted_member_class_tmpls_[name] = d;
5735 }
5736 }
5737 }
5738 sort_string_diff_sptr_map(priv_->changed_member_types_,
5739 priv_->sorted_changed_member_types_);
5740}
5741
5742/// Allocate the memory for the priv_ pimpl data member of the @ref
5743/// class_or_union_diff class.
5744void
5746{
5747 if (!priv_)
5748 priv_.reset(new priv);
5749}
5750
5751/// Constructor for the @ref class_or_union_diff class.
5752///
5753/// @param first_scope the first @ref class_or_union of the diff node.
5754///
5755/// @param second_scope the second @ref class_or_union of the diff node.
5756///
5757/// @param ctxt the context of the diff.
5758class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5759 class_or_union_sptr second_scope,
5760 diff_context_sptr ctxt)
5761 : type_diff_base(first_scope, second_scope, ctxt)
5762 //priv_(new priv)
5763{}
5764
5765/// Getter of the private data of the @ref class_or_union_diff type.
5766///
5767/// Note that due to an optimization, the private data of @ref
5768/// class_or_union_diff can be shared among several instances of
5769/// class_or_union_diff, so you should never try to access
5770/// class_or_union_diff::priv directly.
5771///
5772/// When class_or_union_diff::priv is shared, this function returns
5773/// the correct shared one.
5774///
5775/// @return the (possibly) shared private data of the current instance
5776/// of @ref class_or_union_diff.
5777const class_or_union_diff::priv_ptr&
5779{
5780 if (priv_)
5781 return priv_;
5782
5783 // If the current class_or_union_diff::priv member is empty, then look for
5784 // the shared one, from the canonical type.
5785 class_or_union_diff *canonical =
5786 dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5787 ABG_ASSERT(canonical);
5788 ABG_ASSERT(canonical->priv_);
5789
5790 return canonical->priv_;
5791}
5792
5793/// Destructor of class_or_union_diff.
5795{
5796}
5797
5798/// @return the first @ref class_or_union involved in the diff.
5799class_or_union_sptr
5802
5803/// @return the second @ref class_or_union involved in the diff.
5804class_or_union_sptr
5807
5808/// @return the edit script of the member types of the two @ref
5809/// class_or_union.
5810const edit_script&
5812{return get_priv()->member_types_changes_;}
5813
5814/// @return the edit script of the member types of the two @ref
5815/// class_or_union.
5818{return get_priv()->member_types_changes_;}
5819
5820/// @return the edit script of the data members of the two @ref
5821/// class_or_union.
5822const edit_script&
5824{return get_priv()->data_members_changes_;}
5825
5826/// @return the edit script of the data members of the two @ref
5827/// class_or_union.
5830{return get_priv()->data_members_changes_;}
5831
5832/// Getter for the data members that got inserted.
5833///
5834/// @return a map of data members that got inserted.
5837{return get_priv()->inserted_data_members_;}
5838
5839/// Getter for the data members that got deleted.
5840///
5841/// @return a map of data members that got deleted.
5844{return get_priv()->deleted_data_members_;}
5845
5846/// @return the edit script of the member functions of the two @ref
5847/// class_or_union.
5848const edit_script&
5850{return get_priv()->member_fns_changes_;}
5851
5852/// Getter for the virtual members functions that have had a change in
5853/// a sub-type, without having a change in their symbol name.
5854///
5855/// @return a sorted vector of virtual member functions that have a
5856/// sub-type change.
5859{return get_priv()->sorted_changed_member_functions_;}
5860
5861/// @return the edit script of the member functions of the two
5862/// classes.
5865{return get_priv()->member_fns_changes_;}
5866
5867/// @return a map of member functions that got deleted.
5870{return get_priv()->deleted_member_functions_;}
5871
5872/// @return a map of member functions that got inserted.
5875{return get_priv()->inserted_member_functions_;}
5876
5877/// Getter of the map of data members that got replaced by another
5878/// data member. The key of the map is the offset at which the
5879/// element got replaced and the value is a pointer to the @ref
5880/// var_diff representing the replacement of the data member.
5881///
5882/// @return sorted vector of changed data member.
5885{return get_priv()->changed_dm_;}
5886
5887/// Getter of the sorted vector of data members that got replaced by
5888/// another data member.
5889///
5890/// @return sorted vector of changed data member.
5893{return get_priv()->sorted_changed_dm_;}
5894
5895/// Count the number of /filtered/ data members that got replaced by
5896/// another data member.
5897///
5898/// @return the number of changed data member that got filtered out.
5899size_t
5901{return get_priv()->count_filtered_changed_dm(local);}
5902
5903/// Getter of the sorted vector of data members with a (sub-)type change.
5904///
5905/// @return sorted vector of changed data member.
5908{return get_priv()->sorted_subtype_changed_dm_;}
5909
5910/// Count the number of /filtered/ data members with a sub-type change.
5911///
5912/// @return the number of changed data member that got filtered out.
5913size_t
5915{return get_priv()->count_filtered_subtype_changed_dm(local);}
5916
5917/// Get the map of data members that got replaced by anonymous data
5918/// members.
5919///
5920/// The key of a map entry is the name of the replaced data member and
5921/// the value is the anonymous data member that replaces it.
5922///
5923/// @return the map of data members replaced by anonymous data
5924/// members.
5927{return get_priv()->dms_replaced_by_adms_;}
5928
5929/// Get an ordered vector of of data members that got replaced by
5930/// anonymous data members.
5931///
5932/// This returns a vector of pair of two data members: the one that
5933/// was replaced, and the anonymous data member that replaced it.
5934///
5935/// @return the sorted vector data members replaced by anonymous data members.
5938{
5939 if (priv_->dms_replaced_by_adms_ordered_.empty())
5940 {
5941 for (string_decl_base_sptr_map::const_iterator it =
5942 priv_->dms_replaced_by_adms_.begin();
5943 it != priv_->dms_replaced_by_adms_.end();
5944 ++it)
5945 {
5946 const var_decl_sptr dm =
5947 first_class_or_union()->find_data_member(it->first);
5948 ABG_ASSERT(dm);
5949 changed_var_sptr changed_dm(dm, is_data_member(it->second));
5950 priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5951 }
5952 sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5953 }
5954
5955 return priv_->dms_replaced_by_adms_ordered_;
5956}
5957
5958/// @return the edit script of the member function templates of the two
5959/// @ref class_or_union.
5960const edit_script&
5962{return get_priv()->member_fn_tmpls_changes_;}
5963
5964/// @return the edit script of the member function templates of the
5965/// two @ref class_or_union.
5968{return get_priv()->member_fn_tmpls_changes_;}
5969
5970/// @return the edit script of the member class templates of the two
5971/// @ref class_or_union.
5972const edit_script&
5974{return get_priv()->member_class_tmpls_changes_;}
5975
5976/// @return the edit script of the member class templates of the two
5977/// @ref class_or_union.
5980{return get_priv()->member_class_tmpls_changes_;}
5981
5982/// Test if the current diff node carries a change.
5983bool
5986
5987/// @return the kind of local change carried by the current diff node.
5988/// The value returned is zero if the current node carries no local
5989/// change.
5990enum change_kind
5992{
5993 ir::change_kind k = ir::NO_CHANGE_KIND;
5995 return k & ir::ALL_LOCAL_CHANGES_MASK;
5996 return ir::NO_CHANGE_KIND;
5997}
5998
5999
6000/// Report the changes carried by the current @ref class_or_union_diff
6001/// node in a textual format.
6002///
6003/// @param out the output stream to write the textual report to.
6004///
6005/// @param indent the number of white space to use as indentation.
6006void
6007class_or_union_diff::report(ostream& out, const string& indent) const
6008{
6009 context()->get_reporter()->report(*this, out, indent);
6010}
6011
6012/// Populate the vector of children node of the @ref diff base type
6013/// sub-object of this instance of @ref class_or_union_diff.
6014///
6015/// The children node can then later be retrieved using
6016/// diff::children_node().
6017void
6019{
6020 // data member changes
6021 for (var_diff_sptrs_type::const_iterator i =
6022 get_priv()->sorted_subtype_changed_dm_.begin();
6023 i != get_priv()->sorted_subtype_changed_dm_.end();
6024 ++i)
6025 if (diff_sptr d = *i)
6027
6028 for (var_diff_sptrs_type::const_iterator i =
6029 get_priv()->sorted_changed_dm_.begin();
6030 i != get_priv()->sorted_changed_dm_.end();
6031 ++i)
6032 if (diff_sptr d = *i)
6034
6035 // member types changes
6036 for (diff_sptrs_type::const_iterator i =
6037 get_priv()->sorted_changed_member_types_.begin();
6038 i != get_priv()->sorted_changed_member_types_.end();
6039 ++i)
6040 if (diff_sptr d = *i)
6042
6043 // member function changes
6044 for (function_decl_diff_sptrs_type::const_iterator i =
6045 get_priv()->sorted_changed_member_functions_.begin();
6046 i != get_priv()->sorted_changed_member_functions_.end();
6047 ++i)
6048 if (diff_sptr d = *i)
6050}
6051
6052// </class_or_union_diff stuff>
6053
6054//<class_diff stuff>
6055
6056/// Clear the lookup tables useful for reporting.
6057///
6058/// This function must be updated each time a lookup table is added or
6059/// removed from the class_diff::priv.
6060void
6061class_diff::clear_lookup_tables(void)
6062{
6063 priv_->deleted_bases_.clear();
6064 priv_->inserted_bases_.clear();
6065 priv_->changed_bases_.clear();
6066}
6067
6068/// Tests if the lookup tables are empty.
6069///
6070/// @return true if the lookup tables are empty, false otherwise.
6071bool
6072class_diff::lookup_tables_empty(void) const
6073{
6074 return (priv_->deleted_bases_.empty()
6075 && priv_->inserted_bases_.empty()
6076 && priv_->changed_bases_.empty());
6077}
6078
6079/// Find a virtual destructor in a map of member functions
6080///
6081/// @param map the map of member functions. Note that the key of the
6082/// map is the member function name. The key is the member function.
6083///
6084/// @return an iterator to the destructor found or, if no virtual destructor
6085/// was found, return map.end()
6086static string_member_function_sptr_map::const_iterator
6087find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
6088{
6089 for (string_member_function_sptr_map::const_iterator i = map.begin();
6090 i !=map.end();
6091 ++i)
6092 {
6093 if (get_member_function_is_dtor(i->second)
6094 && get_member_function_is_virtual(i->second))
6095 return i;
6096 }
6097 return map.end();
6098}
6099
6100/// If the lookup tables are not yet built, walk the differences and
6101/// fill them.
6102void
6103class_diff::ensure_lookup_tables_populated(void) const
6104{
6106
6107 if (!lookup_tables_empty())
6108 return;
6109
6110 {
6111 edit_script& e = get_priv()->base_changes_;
6112
6113 for (vector<deletion>::const_iterator it = e.deletions().begin();
6114 it != e.deletions().end();
6115 ++it)
6116 {
6117 unsigned i = it->index();
6119 first_class_decl()->get_base_specifiers()[i];
6120 string name = b->get_base_class()->get_qualified_name();
6121 ABG_ASSERT(get_priv()->deleted_bases_.find(name)
6122 == get_priv()->deleted_bases_.end());
6123 get_priv()->deleted_bases_[name] = b;
6124 }
6125
6126 for (vector<insertion>::const_iterator it = e.insertions().begin();
6127 it != e.insertions().end();
6128 ++it)
6129 {
6130 for (vector<unsigned>::const_iterator iit =
6131 it->inserted_indexes().begin();
6132 iit != it->inserted_indexes().end();
6133 ++iit)
6134 {
6135 unsigned i = *iit;
6137 second_class_decl()->get_base_specifiers()[i];
6138 string name = b->get_base_class()->get_qualified_name();
6139 ABG_ASSERT(get_priv()->inserted_bases_.find(name)
6140 == get_priv()->inserted_bases_.end());
6141 string_base_sptr_map::const_iterator j =
6142 get_priv()->deleted_bases_.find(name);
6143 if (j != get_priv()->deleted_bases_.end())
6144 {
6145 if (j->second != b)
6146 get_priv()->changed_bases_[name] =
6147 compute_diff(j->second, b, context());
6148 else
6149 // The base class changed place. IOW, the base
6150 // classes got re-arranged. Let's keep track of the
6151 // base classes that moved.
6152 get_priv()->moved_bases_.push_back(b);
6153 get_priv()->deleted_bases_.erase(j);
6154 }
6155 else
6156 get_priv()->inserted_bases_[name] = b;
6157 }
6158 }
6159
6160 // ===============================================================
6161 // Detect when a data member is deleted from the class but is now
6162 // present in one of the bases at the same offset. In that case,
6163 // the data member should not be considered as removed.
6164 // ===============================================================
6166 class_or_union_diff::priv_->deleted_data_members_;
6167
6168 vector<var_decl_sptr> deleted_data_members_present_in_bases;
6169 for (auto entry : deleted_data_members)
6170 {
6171 var_decl_sptr deleted_member = is_var_decl(entry.second);
6172 ABG_ASSERT(deleted_member);
6173 for (class_decl::base_spec_sptr base : second_class_decl()->get_base_specifiers())
6174 {
6175 class_decl_sptr klass = base->get_base_class();
6176 var_decl_sptr member = klass->find_data_member(deleted_member->get_name());
6177 if (member)
6178 deleted_data_members_present_in_bases.push_back(member);
6179 }
6180 }
6181 // Walk the deleted data members that are now in one of the bases,
6182 // of the new type, at the same offset, and let's see if they have
6183 // sub-type changes. In any cases, these should not be considered
6184 // as being deleted.
6185 for (var_decl_sptr m : deleted_data_members_present_in_bases)
6186 {
6187 string name = m->get_name();
6188 auto it = deleted_data_members.find(name);
6189 ABG_ASSERT(it != deleted_data_members.end());
6190 var_decl_sptr deleted_member = is_var_decl(it->second);
6191 if (*deleted_member != *m)
6192 {
6193 var_diff_sptr dif = compute_diff(deleted_member, m, context());
6194 ABG_ASSERT(dif);
6195 class_or_union_diff::priv_->subtype_changed_dm_[name]= dif;
6196 }
6197 deleted_data_members.erase(name);
6198 }
6199 }
6200
6201 sort_string_base_sptr_map(get_priv()->deleted_bases_,
6202 get_priv()->sorted_deleted_bases_);
6203 sort_string_base_sptr_map(get_priv()->inserted_bases_,
6204 get_priv()->sorted_inserted_bases_);
6205 sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
6206 get_priv()->sorted_changed_bases_);
6207
6208 {
6209 const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
6210
6211 edit_script& e = p->member_fns_changes_;
6212
6213 for (vector<deletion>::const_iterator it = e.deletions().begin();
6214 it != e.deletions().end();
6215 ++it)
6216 {
6217 unsigned i = it->index();
6218 method_decl_sptr mem_fn =
6219 first_class_decl()->get_virtual_mem_fns()[i];
6220 string name = mem_fn->get_linkage_name();
6221 if (name.empty())
6222 name = mem_fn->get_pretty_representation();
6223 ABG_ASSERT(!name.empty());
6224 if (p->deleted_member_functions_.find(name)
6225 != p->deleted_member_functions_.end())
6226 continue;
6227 p->deleted_member_functions_[name] = mem_fn;
6228 }
6229
6230 for (vector<insertion>::const_iterator it = e.insertions().begin();
6231 it != e.insertions().end();
6232 ++it)
6233 {
6234 for (vector<unsigned>::const_iterator iit =
6235 it->inserted_indexes().begin();
6236 iit != it->inserted_indexes().end();
6237 ++iit)
6238 {
6239 unsigned i = *iit;
6240
6241 method_decl_sptr mem_fn =
6242 second_class_decl()->get_virtual_mem_fns()[i];
6243 string name = mem_fn->get_linkage_name();
6244 if (name.empty())
6245 name = mem_fn->get_pretty_representation();
6246 ABG_ASSERT(!name.empty());
6247 if (p->inserted_member_functions_.find(name)
6248 != p->inserted_member_functions_.end())
6249 continue;
6250 string_member_function_sptr_map::const_iterator j =
6251 p->deleted_member_functions_.find(name);
6252
6253 if (j != p->deleted_member_functions_.end())
6254 {
6255 if (*j->second != *mem_fn)
6256 p->changed_member_functions_[name] =
6257 compute_diff(static_pointer_cast<function_decl>(j->second),
6258 static_pointer_cast<function_decl>(mem_fn),
6259 context());
6260 p->deleted_member_functions_.erase(j);
6261 }
6262 else
6263 p->inserted_member_functions_[name] = mem_fn;
6264 }
6265 }
6266
6267 // Now walk the allegedly deleted member functions; check if their
6268 // underlying symbols are deleted as well; otherwise, consider
6269 // that the member function in question hasn't been deleted.
6270
6271 // Also, while walking the deleted member functions, we attend at
6272 // a particular cleanup business related to (virtual) C++
6273 // destructors:
6274 //
6275 // In the binary, there can be at least three types of
6276 // destructors, defined in the document
6277 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
6278 //
6279 // 1/ Base object destructor (aka D2 destructor):
6280 //
6281 // "A function that runs the destructors for non-static data
6282 // members of T and non-virtual direct base classes of T. "
6283 //
6284 // 2/ Complete object destructor (aka D1 destructor):
6285 //
6286 // "A function that, in addition to the actions required of a
6287 // base object destructor, runs the destructors for the
6288 // virtual base classes of T."
6289 //
6290 // 3/ Deleting destructor (aka D0 destructor):
6291 //
6292 // "A function that, in addition to the actions required of a
6293 // complete object destructor, calls the appropriate
6294 // deallocation function (i.e,. operator delete) for T."
6295 //
6296 // With binaries generated by GCC, these destructors might be ELF
6297 // clones of each others, meaning, their ELF symbols can be
6298 // aliases.
6299 //
6300 // Also, note that because the actual destructor invoked by user
6301 // code is virtual, it's invoked through the vtable. So the
6302 // presence of the underlying D0, D1, D2 in the binary might vary
6303 // without that variation being an ABI issue, provided that the
6304 // destructor invoked through the vtable is present.
6305 //
6306 // So, a particular virtual destructor implementation for a class
6307 // might disapear and be replaced by another one in a subsequent
6308 // version of the binary. If all versions of the binary have an
6309 // actual virtual destructor, things might be considered fine.
6310 vector<string> to_delete;
6311 corpus_sptr f = context()->get_first_corpus(),
6312 s = context()->get_second_corpus();
6313 if (s)
6314 for (string_member_function_sptr_map::const_iterator i =
6315 deleted_member_fns().begin();
6316 i != deleted_member_fns().end();
6317 ++i)
6318 {
6319 if (get_member_function_is_virtual(i->second))
6320 {
6321 if (get_member_function_is_dtor(i->second))
6322 {
6323 // If a particular virtual destructor is deleted,
6324 // but the new binary still have a virtual
6325 // destructor for that class we consider that things
6326 // are fine. For instance, in the
6327 // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
6328 // test, a new D4 destructor replaces the old ones.
6329 // But because the virtual destructor is still
6330 // there, this is not an ABI issue. So let's detect
6331 // this case.
6332 auto it =
6333 find_virtual_dtor_in_map(p->inserted_member_functions_);
6334 if (it != p->inserted_member_functions_.end())
6335 {
6336 // So the deleted virtual destructor is not
6337 // really deleted, because a proper virtual
6338 // destructor was added to the new version.
6339 // Let's remove the deleted/added virtual
6340 // destructor then.
6341 string name =
6342 (!i->second->get_linkage_name().empty())
6343 ? i->second->get_linkage_name()
6344 : i->second->get_pretty_representation();
6345 to_delete.push_back(name);
6346 p->inserted_member_functions_.erase(it);
6347 }
6348 }
6349 continue;
6350 }
6351 // We assume that all non-virtual member functions functions
6352 // we look at here have ELF symbols.
6353 if (!i->second->get_symbol()
6354 || s->lookup_function_symbol(*i->second->get_symbol()))
6355 to_delete.push_back(i->first);
6356 }
6357
6358
6359 for (vector<string>::const_iterator i = to_delete.begin();
6360 i != to_delete.end();
6361 ++i)
6362 p->deleted_member_functions_.erase(*i);
6363
6364 // Do something similar for added functions.
6365 to_delete.clear();
6366 if (f)
6367 for (string_member_function_sptr_map::const_iterator i =
6368 inserted_member_fns().begin();
6369 i != inserted_member_fns().end();
6370 ++i)
6371 {
6372 if (get_member_function_is_virtual(i->second))
6373 continue;
6374 // We assume that all non-virtual member functions functions
6375 // we look at here have ELF symbols.
6376 if (!i->second->get_symbol()
6377 || f->lookup_function_symbol(*i->second->get_symbol()))
6378 to_delete.push_back(i->first);
6379 }
6380
6381 for (vector<string>::const_iterator i = to_delete.begin();
6382 i != to_delete.end();
6383 ++i)
6384 p->inserted_member_functions_.erase(*i);
6385
6386 sort_string_member_function_sptr_map(p->deleted_member_functions_,
6387 p->sorted_deleted_member_functions_);
6388
6389 sort_string_member_function_sptr_map(p->inserted_member_functions_,
6390 p->sorted_inserted_member_functions_);
6391
6393 (p->changed_member_functions_,
6394 p->sorted_changed_member_functions_);
6395 }
6396}
6397
6398/// Allocate the memory for the priv_ pimpl data member of the @ref
6399/// class_diff class.
6400void
6401class_diff::allocate_priv_data()
6402{
6404 if (!priv_)
6405 priv_.reset(new priv);
6406}
6407
6408/// Test whether a given base class has changed. A base class has
6409/// changed if it's in both in deleted *and* inserted bases.
6410///
6411///@param d the declaration for the base class to consider.
6412///
6413/// @return the new base class if the given base class has changed, or
6414/// NULL if it hasn't.
6417{
6418 string qname = d->get_base_class()->get_qualified_name();
6419 string_base_diff_sptr_map::const_iterator it =
6420 changed_bases_.find(qname);
6421
6422 return (it == changed_bases_.end())
6424 : it->second->second_base();
6425
6426}
6427
6428/// Count the number of bases classes whose changes got filtered out.
6429///
6430/// @return the number of bases classes whose changes got filtered
6431/// out.
6432size_t
6434{
6435 size_t num_filtered = 0;
6436 for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
6437 i != sorted_changed_bases_.end();
6438 ++i)
6439 {
6440 diff_sptr diff = *i;
6441 if (diff && diff->is_filtered_out())
6442 ++num_filtered;
6443 }
6444 return num_filtered;
6445}
6446
6447/// Populate the vector of children node of the @ref diff base type
6448/// sub-object of this instance of @ref class_diff.
6449///
6450/// The children node can then later be retrieved using
6451/// diff::children_node().
6452void
6454{
6456
6457 // base class changes.
6458 for (base_diff_sptrs_type::const_iterator i =
6459 get_priv()->sorted_changed_bases_.begin();
6460 i != get_priv()->sorted_changed_bases_.end();
6461 ++i)
6462 if (diff_sptr d = *i)
6464}
6465
6466/// Constructor of class_diff
6467///
6468/// @param first_scope the first class of the diff.
6469///
6470/// @param second_scope the second class of the diff.
6471///
6472/// @param ctxt the diff context to use.
6474 class_decl_sptr second_scope,
6475 diff_context_sptr ctxt)
6476 : class_or_union_diff(first_scope, second_scope, ctxt)
6477 // We don't initialize the priv_ data member here. This is an
6478 // optimization to reduce memory consumption (and also execution
6479 // time) for cases where there are a lot of instances of
6480 // class_diff in the same equivalence class. In compute_diff(),
6481 // the priv_ is set to the priv_ of the canonical diff node.
6482 // See PR libabigail/17948.
6483{}
6484
6485class_diff::~class_diff()
6486{}
6487
6488/// Getter of the private data of the @ref class_diff type.
6489///
6490/// Note that due to an optimization, the private data of @ref
6491/// class_diff can be shared among several instances of class_diff, so
6492/// you should never try to access class_diff::priv directly.
6493///
6494/// When class_diff::priv is shared, this function returns the correct
6495/// shared one.
6496///
6497/// @return the (possibly) shared private data of the current instance
6498/// of class_diff.
6499const class_diff::priv_ptr&
6500class_diff::get_priv() const
6501{
6502 if (priv_)
6503 return priv_;
6504
6505 // If the current class_diff::priv member is empty, then look for
6506 // the shared one, from the canonical type.
6507 class_diff *canonical =
6508 dynamic_cast<class_diff*>(get_canonical_diff());
6509 ABG_ASSERT(canonical);
6510 ABG_ASSERT(canonical->priv_);
6511
6512 return canonical->priv_;
6513}
6514
6515/// @return the pretty representation of the current instance of @ref
6516/// class_diff.
6517const string&
6519{
6520 if (diff::priv_->pretty_representation_.empty())
6521 {
6522 std::ostringstream o;
6523 o << "class_diff["
6524 << first_subject()->get_pretty_representation()
6525 << ", "
6526 << second_subject()->get_pretty_representation()
6527 << "]";
6528 diff::priv_->pretty_representation_ = o.str();
6529 }
6530 return diff::priv_->pretty_representation_;
6531}
6532
6533/// Return true iff the current diff node carries a change.
6534///
6535/// @return true iff the current diff node carries a change.
6536bool
6538{return (first_class_decl() != second_class_decl());}
6539
6540/// @return the kind of local change carried by the current diff node.
6541/// The value returned is zero if the current node carries no local
6542/// change.
6543enum change_kind
6545{
6546 ir::change_kind k = ir::NO_CHANGE_KIND;
6547 if (!equals(*first_class_decl(), *second_class_decl(), &k))
6548 return k & ir::ALL_LOCAL_CHANGES_MASK;
6549 return ir::NO_CHANGE_KIND;
6550}
6551
6552/// @return the first class invoveld in the diff.
6553shared_ptr<class_decl>
6555{return dynamic_pointer_cast<class_decl>(first_subject());}
6556
6557/// Getter of the second class involved in the diff.
6558///
6559/// @return the second class invoveld in the diff
6560shared_ptr<class_decl>
6562{return dynamic_pointer_cast<class_decl>(second_subject());}
6563
6564/// @return the edit script of the bases of the two classes.
6565const edit_script&
6567{return get_priv()->base_changes_;}
6568
6569/// Getter for the deleted base classes of the diff.
6570///
6571/// @return a map containing the deleted base classes, keyed with
6572/// their pretty representation.
6575{return get_priv()->deleted_bases_;}
6576
6577/// Getter for the inserted base classes of the diff.
6578///
6579/// @return a map containing the inserted base classes, keyed with
6580/// their pretty representation.
6583{return get_priv()->inserted_bases_;}
6584
6585/// Getter for the changed base classes of the diff.
6586///
6587/// @return a sorted vector containing the changed base classes
6590{return get_priv()->sorted_changed_bases_;}
6591
6592/// Getter for the vector of bases that "moved".
6593/// That is, the vector of base types which position changed. If this
6594/// vector is not empty, it means the bases of the underlying class
6595/// type got re-ordered.
6596///
6597/// @return the vector of bases that moved.
6598const vector<class_decl::base_spec_sptr>&
6600{return get_priv()->moved_bases_;}
6601
6602/// @return the edit script of the bases of the two classes.
6605{return get_priv()->base_changes_;}
6606
6607/// Produce a basic report about the changes between two class_decl.
6608///
6609/// @param out the output stream to report the changes to.
6610///
6611/// @param indent the string to use as an indentation prefix in the
6612/// report.
6613void
6614class_diff::report(ostream& out, const string& indent) const
6615{
6616 context()->get_reporter()->report(*this, out, indent);
6617}
6618
6619/// Compute the set of changes between two instances of class_decl.
6620///
6621/// Note that the two types must have been created in the same @ref
6622/// environment, otherwise, this function aborts.
6623///
6624/// @param first the first class_decl to consider.
6625///
6626/// @param second the second class_decl to consider.
6627///
6628/// @return changes the resulting changes.
6629///
6630/// @param ctxt the diff context to use.
6633 const class_decl_sptr second,
6634 diff_context_sptr ctxt)
6635{
6638
6639 class_diff_sptr changes(new class_diff(f, s, ctxt));
6640
6641 ctxt->initialize_canonical_diff(changes);
6642 ABG_ASSERT(changes->get_canonical_diff());
6643
6644 if (!ctxt->get_canonical_diff_for(first, second))
6645 {
6646 // Either first or second is a decl-only class; let's set the
6647 // canonical diff here in that case.
6648 diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6649 ABG_ASSERT(canonical_diff);
6650 ctxt->set_canonical_diff_for(first, second, canonical_diff);
6651 }
6652
6653 // Ok, so this is an optimization. Do not freak out if it looks
6654 // weird, because, well, it does look weird. This speeds up
6655 // greatly, for instance, the test case given at PR
6656 // libabigail/17948.
6657 //
6658 // We are setting the private data of the new instance of class_diff
6659 // (which is 'changes') to the private data of its canonical
6660 // instance. That is, we are sharing the private data of 'changes'
6661 // with the private data of its canonical instance to consume less
6662 // memory in cases where the equivalence class of 'changes' is huge.
6663 //
6664 // But if changes is its own canonical instance, then we initialize
6665 // its private data properly
6666 if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6667 // changes is its own canonical instance, so it gets a brand new
6668 // private data.
6669 changes->allocate_priv_data();
6670 else
6671 {
6672 // changes has a non-empty equivalence class so it's going to
6673 // share its private data with its canonical instance. Next
6674 // time class_diff::get_priv() is invoked, it's going to return
6675 // the shared private data of the canonical instance.
6676 return changes;
6677 }
6678
6679 // Compare base specs
6680 compute_diff(f->get_base_specifiers().begin(),
6681 f->get_base_specifiers().end(),
6682 s->get_base_specifiers().begin(),
6683 s->get_base_specifiers().end(),
6684 changes->base_changes());
6685
6686 // Do *not* compare member types because it generates lots of noise
6687 // and I doubt it's really useful.
6688#if 0
6689 compute_diff(f->get_member_types().begin(),
6690 f->get_member_types().end(),
6691 s->get_member_types().begin(),
6692 s->get_member_types().end(),
6693 changes->member_types_changes());
6694#endif
6695
6696 // Compare data member
6697 compute_diff(f->get_non_static_data_members().begin(),
6698 f->get_non_static_data_members().end(),
6699 s->get_non_static_data_members().begin(),
6700 s->get_non_static_data_members().end(),
6701 changes->data_members_changes());
6702
6703 // Compare virtual member functions
6704 compute_diff(f->get_virtual_mem_fns().begin(),
6705 f->get_virtual_mem_fns().end(),
6706 s->get_virtual_mem_fns().begin(),
6707 s->get_virtual_mem_fns().end(),
6708 changes->member_fns_changes());
6709
6710 // Compare member function templates
6711 compute_diff(f->get_member_function_templates().begin(),
6712 f->get_member_function_templates().end(),
6713 s->get_member_function_templates().begin(),
6714 s->get_member_function_templates().end(),
6715 changes->member_fn_tmpls_changes());
6716
6717 // Likewise, do not compare member class templates
6718#if 0
6719 compute_diff(f->get_member_class_templates().begin(),
6720 f->get_member_class_templates().end(),
6721 s->get_member_class_templates().begin(),
6722 s->get_member_class_templates().end(),
6723 changes->member_class_tmpls_changes());
6724#endif
6725
6726 changes->ensure_lookup_tables_populated();
6727
6728 return changes;
6729}
6730
6731//</class_diff stuff>
6732
6733// <base_diff stuff>
6734
6735/// Populate the vector of children node of the @ref diff base type
6736/// sub-object of this instance of @ref base_diff.
6737///
6738/// The children node can then later be retrieved using
6739/// diff::children_node().
6740void
6743
6744/// @param first the first base spec to consider.
6745///
6746/// @param second the second base spec to consider.
6747///
6748/// @param ctxt the context of the diff. Note that this context
6749/// object must stay alive at least during the life time of the
6750/// current instance of @ref base_diff. Otherwise memory corruption
6751/// issues occur.
6754 class_diff_sptr underlying,
6755 diff_context_sptr ctxt)
6756 : diff(first, second, ctxt),
6757 priv_(new priv(underlying))
6758{}
6759
6760/// Getter for the first base spec of the diff object.
6761///
6762/// @return the first base specifier for the diff object.
6765{return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6766
6767/// Getter for the second base spec of the diff object.
6768///
6769/// @return the second base specifier for the diff object.
6772{return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6773
6774/// Getter for the diff object for the diff of the underlying base
6775/// classes.
6776///
6777/// @return the diff object for the diff of the underlying base
6778/// classes.
6779const class_diff_sptr
6781{return priv_->underlying_class_diff_;}
6782
6783/// Setter for the diff object for the diff of the underlyng base
6784/// classes.
6785///
6786/// @param d the new diff object for the diff of the underlying base
6787/// classes.
6788void
6790{priv_->underlying_class_diff_ = d;}
6791
6792/// @return the pretty representation for the current instance of @ref
6793/// base_diff.
6794const string&
6796{
6797 if (diff::priv_->pretty_representation_.empty())
6798 {
6799 std::ostringstream o;
6800 o << "base_diff["
6801 << first_subject()->get_pretty_representation()
6802 << ", "
6803 << second_subject()->get_pretty_representation()
6804 << "]";
6805 diff::priv_->pretty_representation_ = o.str();
6806 }
6807 return diff::priv_->pretty_representation_;
6808}
6809
6810/// Return true iff the current diff node carries a change.
6811///
6812/// Return true iff the current diff node carries a change.
6813bool
6815{return first_base() != second_base();}
6816
6817/// @return the kind of local change carried by the current diff node.
6818/// The value returned is zero if the current node carries no local
6819/// change.
6820enum change_kind
6822{
6823 ir::change_kind k = ir::NO_CHANGE_KIND;
6824 if (!equals(*first_base(), *second_base(), &k))
6825 return k & ir::ALL_LOCAL_CHANGES_MASK;
6826 return ir::NO_CHANGE_KIND;
6827}
6828
6829/// Generates a report for the current instance of base_diff.
6830///
6831/// @param out the output stream to send the report to.
6832///
6833/// @param indent the string to use for indentation.
6834void
6835base_diff::report(ostream& out, const string& indent) const
6836{
6837 context()->get_reporter()->report(*this, out, indent);
6838}
6839
6840/// Constructs the diff object representing a diff between two base
6841/// class specifications.
6842///
6843/// Note that the two artifacts must have been created in the same
6844/// @ref environment, otherwise, this function aborts.
6845///
6846/// @param first the first base class specification.
6847///
6848/// @param second the second base class specification.
6849///
6850/// @param ctxt the content of the diff.
6851///
6852/// @return the resulting diff object.
6855 const class_decl::base_spec_sptr second,
6856 diff_context_sptr ctxt)
6857{
6858 class_diff_sptr cl = compute_diff(first->get_base_class(),
6859 second->get_base_class(),
6860 ctxt);
6861 base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6862
6863 ctxt->initialize_canonical_diff(changes);
6864
6865 return changes;
6866}
6867
6868// </base_diff stuff>
6869
6870
6871// <union_diff stuff>
6872
6873/// Clear the lookup tables useful for reporting.
6874///
6875/// This function must be updated each time a lookup table is added or
6876/// removed from the union_diff::priv.
6877void
6878union_diff::clear_lookup_tables(void)
6880
6881/// Tests if the lookup tables are empty.
6882///
6883/// @return true if the lookup tables are empty, false otherwise.
6884bool
6885union_diff::lookup_tables_empty(void) const
6887
6888/// If the lookup tables are not yet built, walk the differences and
6889/// fill them.
6890void
6891union_diff::ensure_lookup_tables_populated(void) const
6893
6894/// Allocate the memory for the priv_ pimpl data member of the @ref
6895/// union_diff class.
6896void
6897union_diff::allocate_priv_data()
6898{
6900}
6901
6902/// Constructor for the @ref union_diff type.
6903///
6904/// @param first_union the first object of the comparison.
6905///
6906/// @param second_union the second object of the comparison.
6907///
6908/// @param ctxt the context of the comparison.
6909union_diff::union_diff(union_decl_sptr first_union,
6910 union_decl_sptr second_union,
6911 diff_context_sptr ctxt)
6912 : class_or_union_diff(first_union, second_union, ctxt)
6913{}
6914
6915/// Destructor of the union_diff node.
6917{}
6918
6919/// @return the first object of the comparison.
6920union_decl_sptr
6922{return is_union_type(first_subject());}
6923
6924/// @return the second object of the comparison.
6925union_decl_sptr
6927{return is_union_type(second_subject());}
6928
6929/// @return the pretty representation of the current diff node.
6930const string&
6932{
6933 if (diff::priv_->pretty_representation_.empty())
6934 {
6935 std::ostringstream o;
6936 o << "union_diff["
6937 << first_subject()->get_pretty_representation()
6938 << ", "
6939 << second_subject()->get_pretty_representation()
6940 << "]";
6941 diff::priv_->pretty_representation_ = o.str();
6942 }
6943 return diff::priv_->pretty_representation_;
6944}
6945
6946/// Report the changes carried by the current @ref union_diff node in
6947/// a textual format.
6948///
6949/// @param out the output stream to write the textual report to.
6950///
6951/// @param indent the number of white space to use as indentation.
6952void
6953union_diff::report(ostream& out, const string& indent) const
6954{
6955 context()->get_reporter()->report(*this, out, indent);
6956}
6957
6958/// Compute the difference between two @ref union_decl types.
6959///
6960/// Note that the two types must hav been created in the same
6961/// environment, otherwise, this function aborts.
6962///
6963/// @param first the first @ref union_decl to consider.
6964///
6965/// @param second the second @ref union_decl to consider.
6966///
6967/// @param ctxt the context of the diff to use.
6968union_diff_sptr
6969compute_diff(const union_decl_sptr first,
6970 const union_decl_sptr second,
6971 diff_context_sptr ctxt)
6972{
6973 union_diff_sptr changes(new union_diff(first, second, ctxt));
6974
6975 ctxt->initialize_canonical_diff(changes);
6976 ABG_ASSERT(changes->get_canonical_diff());
6977
6978 // Ok, so this is an optimization. Do not freak out if it looks
6979 // weird, because, well, it does look weird. This speeds up
6980 // greatly, for instance, the test case given at PR
6981 // libabigail/17948.
6982 //
6983 // We are setting the private data of the new instance of class_diff
6984 // (which is 'changes') to the private data of its canonical
6985 // instance. That is, we are sharing the private data of 'changes'
6986 // with the private data of its canonical instance to consume less
6987 // memory in cases where the equivalence class of 'changes' is huge.
6988 //
6989 // But if changes is its own canonical instance, then we initialize
6990 // its private data properly.
6991 if (is_union_diff(changes->get_canonical_diff()) == changes.get())
6992 // changes is its own canonical instance, so it gets a brand new
6993 // private data.
6994 changes->allocate_priv_data();
6995 else
6996 {
6997 // changes has a non-empty equivalence class so it's going to
6998 // share its private data with its canonical instance. Next
6999 // time class_diff::get_priv() is invoked, it's going to return
7000 // the shared private data of the canonical instance.
7001 return changes;
7002 }
7003
7004 // Compare data member
7005 compute_diff(first->get_non_static_data_members().begin(),
7006 first->get_non_static_data_members().end(),
7007 second->get_non_static_data_members().begin(),
7008 second->get_non_static_data_members().end(),
7009 changes->data_members_changes());
7010
7011#if 0
7012 // Compare member functions
7013 compute_diff(first->get_mem_fns().begin(),
7014 first->get_mem_fns().end(),
7015 second->get_mem_fns().begin(),
7016 second->get_mem_fns().end(),
7017 changes->member_fns_changes());
7018
7019 // Compare member function templates
7020 compute_diff(first->get_member_function_templates().begin(),
7021 first->get_member_function_templates().end(),
7022 second->get_member_function_templates().begin(),
7023 second->get_member_function_templates().end(),
7024 changes->member_fn_tmpls_changes());
7025#endif
7026
7027 changes->ensure_lookup_tables_populated();
7028
7029 return changes;
7030}
7031
7032// </union_diff stuff>
7033
7034//<scope_diff stuff>
7035
7036/// Clear the lookup tables that are useful for reporting.
7037///
7038/// This function must be updated each time a lookup table is added or
7039/// removed.
7040void
7041scope_diff::clear_lookup_tables()
7042{
7043 priv_->deleted_types_.clear();
7044 priv_->deleted_decls_.clear();
7045 priv_->inserted_types_.clear();
7046 priv_->inserted_decls_.clear();
7047 priv_->changed_types_.clear();
7048 priv_->changed_decls_.clear();
7049 priv_->removed_types_.clear();
7050 priv_->removed_decls_.clear();
7051 priv_->added_types_.clear();
7052 priv_->added_decls_.clear();
7053}
7054
7055/// Tests if the lookup tables are empty.
7056///
7057/// This function must be updated each time a lookup table is added or
7058/// removed.
7059///
7060/// @return true iff all the lookup tables are empty.
7061bool
7062scope_diff::lookup_tables_empty() const
7063{
7064 return (priv_->deleted_types_.empty()
7065 && priv_->deleted_decls_.empty()
7066 && priv_->inserted_types_.empty()
7067 && priv_->inserted_decls_.empty()
7068 && priv_->changed_types_.empty()
7069 && priv_->changed_decls_.empty()
7070 && priv_->removed_types_.empty()
7071 && priv_->removed_decls_.empty()
7072 && priv_->added_types_.empty()
7073 && priv_->added_decls_.empty());
7074}
7075
7076/// If the lookup tables are not yet built, walk the member_changes_
7077/// member and fill the lookup tables.
7078void
7079scope_diff::ensure_lookup_tables_populated()
7080{
7081 if (!lookup_tables_empty())
7082 return;
7083
7084 edit_script& e = priv_->member_changes_;
7085
7086 // Populate deleted types & decls lookup tables.
7087 for (const auto& deletion : e.deletions())
7088 {
7089 unsigned i = deletion.index();
7090 decl_base_sptr decl = deleted_member_at(i);
7091 string qname = decl->get_qualified_name();
7092 if (is_type(decl))
7093 {
7094 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
7095 if (klass_decl && klass_decl->get_is_declaration_only())
7096 continue;
7097
7098 // Unique types are artifically put in a scope because they
7099 // have to belong somewhere, but they should not be
7100 // considered added/removed from any scope because they are
7101 // artificial and always present in the system.
7102 if (is_unique_type(is_type(decl)))
7103 continue;
7104
7105 ABG_ASSERT(priv_->deleted_types_.find(qname)
7106 == priv_->deleted_types_.end());
7107 priv_->deleted_types_[qname] = decl;
7108 }
7109 else
7110 {
7111 ABG_ASSERT(priv_->deleted_decls_.find(qname)
7112 == priv_->deleted_decls_.end());
7113 priv_->deleted_decls_[qname] = decl;
7114 }
7115 }
7116
7117 // Populate inserted types & decls as well as chagned types & decls
7118 // lookup tables.
7119 for (vector<insertion>::const_iterator it = e.insertions().begin();
7120 it != e.insertions().end();
7121 ++it)
7122 {
7123 for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
7124 i != it->inserted_indexes().end();
7125 ++i)
7126 {
7127 decl_base_sptr decl = inserted_member_at(i);
7128 string qname = decl->get_qualified_name();
7129 if (is_type(decl))
7130 {
7131 class_decl_sptr klass_decl =
7132 dynamic_pointer_cast<class_decl>(decl);
7133 if (klass_decl && klass_decl->get_is_declaration_only())
7134 continue;
7135
7136 // Unique types are artifically put in a scope because they
7137 // have to belong somewhere, but they should not be
7138 // considered added/removed from any scope because they are
7139 // artificial and always present in the system.
7140 if (is_unique_type(is_type(decl)))
7141 continue;
7142
7143 ABG_ASSERT(priv_->inserted_types_.find(qname)
7144 == priv_->inserted_types_.end());
7145 string_decl_base_sptr_map::const_iterator j =
7146 priv_->deleted_types_.find(qname);
7147 if (j != priv_->deleted_types_.end())
7148 {
7149 if (*j->second != *decl)
7150 priv_->changed_types_[qname] =
7151 compute_diff(j->second, decl, context());
7152 priv_->deleted_types_.erase(j);
7153 }
7154 else
7155 priv_->inserted_types_[qname] = decl;
7156 }
7157 else
7158 {
7159 ABG_ASSERT(priv_->inserted_decls_.find(qname)
7160 == priv_->inserted_decls_.end());
7161 string_decl_base_sptr_map::const_iterator j =
7162 priv_->deleted_decls_.find(qname);
7163 if (j != priv_->deleted_decls_.end())
7164 {
7165 if (*j->second != *decl)
7166 priv_->changed_decls_[qname] =
7167 compute_diff(j->second, decl, context());
7168 priv_->deleted_decls_.erase(j);
7169 }
7170 else
7171 priv_->inserted_decls_[qname] = decl;
7172 }
7173 }
7174 }
7175
7176 sort_string_diff_sptr_map(priv_->changed_decls_,
7177 priv_->sorted_changed_decls_);
7178 sort_string_diff_sptr_map(priv_->changed_types_,
7179 priv_->sorted_changed_types_);
7180
7181 // Populate removed types/decls lookup tables
7182 for (string_decl_base_sptr_map::const_iterator i =
7183 priv_->deleted_types_.begin();
7184 i != priv_->deleted_types_.end();
7185 ++i)
7186 {
7187 string_decl_base_sptr_map::const_iterator r =
7188 priv_->inserted_types_.find(i->first);
7189 if (r == priv_->inserted_types_.end())
7190 priv_->removed_types_[i->first] = i->second;
7191 }
7192 for (string_decl_base_sptr_map::const_iterator i =
7193 priv_->deleted_decls_.begin();
7194 i != priv_->deleted_decls_.end();
7195 ++i)
7196 {
7197 string_decl_base_sptr_map::const_iterator r =
7198 priv_->inserted_decls_.find(i->first);
7199 if (r == priv_->inserted_decls_.end())
7200 priv_->removed_decls_[i->first] = i->second;
7201 }
7202
7203 // Populate added types/decls.
7204 for (string_decl_base_sptr_map::const_iterator i =
7205 priv_->inserted_types_.begin();
7206 i != priv_->inserted_types_.end();
7207 ++i)
7208 {
7209 string_decl_base_sptr_map::const_iterator r =
7210 priv_->deleted_types_.find(i->first);
7211 if (r == priv_->deleted_types_.end())
7212 priv_->added_types_[i->first] = i->second;
7213 }
7214 for (string_decl_base_sptr_map::const_iterator i =
7215 priv_->inserted_decls_.begin();
7216 i != priv_->inserted_decls_.end();
7217 ++i)
7218 {
7219 string_decl_base_sptr_map::const_iterator r =
7220 priv_->deleted_decls_.find(i->first);
7221 if (r == priv_->deleted_decls_.end())
7222 priv_->added_decls_[i->first] = i->second;
7223 }
7224}
7225
7226/// Populate the vector of children node of the @ref diff base type
7227/// sub-object of this instance of @ref scope_diff.
7228///
7229/// The children node can then later be retrieved using
7230/// diff::children_node().
7231void
7233{
7234 for (diff_sptrs_type::const_iterator i = changed_types().begin();
7235 i != changed_types().end();
7236 ++i)
7237 if (*i)
7239
7240 for (diff_sptrs_type::const_iterator i = changed_decls().begin();
7241 i != changed_decls().end();
7242 ++i)
7243 if (*i)
7245}
7246
7247/// Constructor for scope_diff
7248///
7249/// @param first_scope the first scope to consider for the diff.
7250///
7251/// @param second_scope the second scope to consider for the diff.
7252///
7253/// @param ctxt the diff context to use. Note that this context
7254/// object must stay alive at least during the life time of the
7255/// current instance of @ref scope_diff. Otherwise memory corruption
7256/// issues occur.
7258 scope_decl_sptr second_scope,
7259 diff_context_sptr ctxt)
7260 : diff(first_scope, second_scope, ctxt),
7261 priv_(new priv)
7262{}
7263
7264/// Getter for the first scope of the diff.
7265///
7266/// @return the first scope of the diff.
7267const scope_decl_sptr
7269{return dynamic_pointer_cast<scope_decl>(first_subject());}
7270
7271/// Getter for the second scope of the diff.
7272///
7273/// @return the second scope of the diff.
7274const scope_decl_sptr
7276{return dynamic_pointer_cast<scope_decl>(second_subject());}
7277
7278/// Accessor of the edit script of the members of a scope.
7279///
7280/// This edit script is computed using the equality operator that
7281/// applies to shared_ptr<decl_base>.
7282///
7283/// That has interesting consequences. For instance, consider two
7284/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7285/// S0'. C0 and C0' have the same qualified name, but have different
7286/// members. The edit script will consider that C0 has been deleted
7287/// from S0 and that S0' has been inserted. This is a low level
7288/// canonical representation of the changes; a higher level
7289/// representation would give us a simpler way to say "the class C0
7290/// has been modified into C0'". But worry not. We do have such
7291/// higher representation as well; that is what changed_types() and
7292/// changed_decls() is for.
7293///
7294/// @return the edit script of the changes encapsulatd in this
7295/// instance of scope_diff.
7296const edit_script&
7298{return priv_->member_changes_;}
7299
7300/// Accessor of the edit script of the members of a scope.
7301///
7302/// This edit script is computed using the equality operator that
7303/// applies to shared_ptr<decl_base>.
7304///
7305/// That has interesting consequences. For instance, consider two
7306/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7307/// S0'. C0 and C0' have the same qualified name, but have different
7308/// members. The edit script will consider that C0 has been deleted
7309/// from S0 and that S0' has been inserted. This is a low level
7310/// canonical representation of the changes; a higher level
7311/// representation would give us a simpler way to say "the class C0
7312/// has been modified into C0'". But worry not. We do have such
7313/// higher representation as well; that is what changed_types() and
7314/// changed_decls() is for.
7315///
7316/// @return the edit script of the changes encapsulatd in this
7317/// instance of scope_diff.
7320{return priv_->member_changes_;}
7321
7322/// Accessor that eases the manipulation of the edit script associated
7323/// to this instance. It returns the scope member that is reported
7324/// (in the edit script) as deleted at a given index.
7325///
7326/// @param i the index (in the edit script) of an element of the first
7327/// scope that has been reported as being delete.
7328///
7329/// @return the scope member that has been reported by the edit script
7330/// as being deleted at index i.
7331const decl_base_sptr
7333{
7334 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
7335 return scope->get_member_decls()[i];
7336}
7337
7338/// Accessor that eases the manipulation of the edit script associated
7339/// to this instance. It returns the scope member (of the first scope
7340/// of this diff instance) that is reported (in the edit script) as
7341/// deleted at a given iterator.
7342///
7343/// @param i the iterator of an element of the first scope that has
7344/// been reported as being delete.
7345///
7346/// @return the scope member of the first scope of this diff that has
7347/// been reported by the edit script as being deleted at iterator i.
7348const decl_base_sptr
7349scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
7350{return deleted_member_at(i->index());}
7351
7352/// Accessor that eases the manipulation of the edit script associated
7353/// to this instance. It returns the scope member (of the second
7354/// scope of this diff instance) that is reported as being inserted
7355/// from a given index.
7356///
7357/// @param i the index of an element of the second scope this diff
7358/// that has been reported by the edit script as being inserted.
7359///
7360/// @return the scope member of the second scope of this diff that has
7361/// been reported as being inserted from index i.
7362const decl_base_sptr
7364{
7365 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
7366 return scope->get_member_decls()[i];
7367}
7368
7369/// Accessor that eases the manipulation of the edit script associated
7370/// to this instance. It returns the scope member (of the second
7371/// scope of this diff instance) that is reported as being inserted
7372/// from a given iterator.
7373///
7374/// @param i the iterator of an element of the second scope this diff
7375/// that has been reported by the edit script as being inserted.
7376///
7377/// @return the scope member of the second scope of this diff that has
7378/// been reported as being inserted from iterator i.
7379const decl_base_sptr
7380scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
7381{return inserted_member_at(*i);}
7382
7383/// @return a sorted vector of the types which content has changed
7384/// from the first scope to the other.
7385const diff_sptrs_type&
7387{return priv_->sorted_changed_types_;}
7388
7389/// @return a sorted vector of the decls which content has changed
7390/// from the first scope to the other.
7391const diff_sptrs_type&
7393{return priv_->sorted_changed_decls_;}
7394
7396scope_diff::removed_types() const
7397{return priv_->removed_types_;}
7398
7400scope_diff::removed_decls() const
7401{return priv_->removed_decls_;}
7402
7404scope_diff::added_types() const
7405{return priv_->added_types_;}
7406
7408scope_diff::added_decls() const
7409{return priv_->added_decls_;}
7410
7411/// @return the pretty representation for the current instance of @ref
7412/// scope_diff.
7413const string&
7415{
7416 if (diff::priv_->pretty_representation_.empty())
7417 {
7418 std::ostringstream o;
7419 o << "scope_diff["
7420 << first_subject()->get_pretty_representation()
7421 << ", "
7422 << second_subject()->get_pretty_representation()
7423 << "]";
7424 diff::priv_->pretty_representation_ = o.str();
7425 }
7426 return diff::priv_->pretty_representation_;
7427}
7428
7429/// Return true iff the current diff node carries a change.
7430///
7431/// Return true iff the current diff node carries a change.
7432bool
7434{
7435 // TODO: add the number of really removed/added stuff.
7436 return changed_types().size() + changed_decls().size();
7437}
7438
7439/// @return the kind of local change carried by the current diff node.
7440/// The value returned is zero if the current node carries no local
7441/// change.
7442enum change_kind
7444{
7445 ir::change_kind k = ir::NO_CHANGE_KIND;
7446 if (!equals(*first_scope(), *second_scope(), &k))
7447 return k & ir::ALL_LOCAL_CHANGES_MASK;
7448 return ir::NO_CHANGE_KIND;
7449}
7450
7451/// Report the changes of one scope against another.
7452///
7453/// @param out the out stream to report the changes to.
7454///
7455/// @param indent the string to use for indentation.
7456void
7457scope_diff::report(ostream& out, const string& indent) const
7458{
7459 context()->get_reporter()->report(*this, out, indent);
7460}
7461
7462/// Compute the diff between two scopes.
7463///
7464/// Note that the two decls must have been created in the same @ref
7465/// environment, otherwise, this function aborts.
7466///
7467/// @param first the first scope to consider in computing the diff.
7468///
7469/// @param second the second scope to consider in the diff
7470/// computation. The second scope is diffed against the first scope.
7471///
7472/// @param d a pointer to the diff object to populate with the
7473/// computed diff.
7474///
7475/// @return return the populated \a d parameter passed to this
7476/// function.
7477///
7478/// @param ctxt the diff context to use.
7481 const scope_decl_sptr second,
7483 diff_context_sptr ctxt)
7484{
7485 ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
7486
7487 compute_diff(first->get_member_decls().begin(),
7488 first->get_member_decls().end(),
7489 second->get_member_decls().begin(),
7490 second->get_member_decls().end(),
7491 d->member_changes());
7492
7493 d->ensure_lookup_tables_populated();
7494 d->context(ctxt);
7495
7496 return d;
7497}
7498
7499/// Compute the diff between two scopes.
7500///
7501/// Note that the two decls must have been created in the same @ref
7502/// environment, otherwise, this function aborts.
7503///
7504/// @param first_scope the first scope to consider in computing the diff.
7505///
7506/// @param second_scope the second scope to consider in the diff
7507/// computation. The second scope is diffed against the first scope.
7508///
7509/// @param ctxt the diff context to use.
7510///
7511/// @return return the resulting diff
7514 const scope_decl_sptr second_scope,
7515 diff_context_sptr ctxt)
7516{
7517 scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
7518 d = compute_diff(first_scope, second_scope, d, ctxt);
7519 ctxt->initialize_canonical_diff(d);
7520 return d;
7521}
7522
7523//</scope_diff stuff>
7524
7525// <fn_parm_diff stuff>
7526
7527/// Constructor for the fn_parm_diff type.
7528///
7529/// @param first the first subject of the diff.
7530///
7531/// @param second the second subject of the diff.
7532///
7533/// @param ctxt the context of the diff. Note that this context
7534/// object must stay alive at least during the life time of the
7535/// current instance of @ref fn_parm_diff. Otherwise memory
7536/// corruption issues occur.
7537fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
7538 const function_decl::parameter_sptr second,
7539 diff_context_sptr ctxt)
7540 : decl_diff_base(first, second, ctxt),
7541 priv_(new priv)
7542{
7543 ABG_ASSERT(first->get_index() == second->get_index());
7544 priv_->type_diff = compute_diff(first->get_type(),
7545 second->get_type(),
7546 ctxt);
7547 ABG_ASSERT(priv_->type_diff);
7548}
7549
7550/// Getter for the first subject of this diff node.
7551///
7552/// @return the first function_decl::parameter_sptr subject of this
7553/// diff node.
7556{return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
7557
7558/// Getter for the second subject of this diff node.
7559///
7560/// @return the second function_decl::parameter_sptr subject of this
7561/// diff node.
7564{return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7565
7566/// Getter for the diff representing the changes on the type of the
7567/// function parameter involved in the current instance of @ref
7568/// fn_parm_diff.
7569///
7570/// @return a diff_sptr representing the changes on the type of the
7571/// function parameter we are interested in.
7574{return priv_->type_diff;}
7575
7576/// Build and return a textual representation of the current instance
7577/// of @ref fn_parm_diff.
7578///
7579/// @return the string representing the current instance of
7580/// fn_parm_diff.
7581const string&
7583{
7584 if (diff::priv_->pretty_representation_.empty())
7585 {
7586 std::ostringstream o;
7587 o << "function_parameter_diff["
7588 << first_subject()->get_pretty_representation()
7589 << ", "
7590 << second_subject()->get_pretty_representation()
7591 << "]";
7592 diff::priv_->pretty_representation_ = o.str();
7593 }
7594 return diff::priv_->pretty_representation_;
7595}
7596
7597/// Return true iff the current diff node carries a change.
7598///
7599/// @return true iff the current diff node carries a change.
7600bool
7602{return *first_parameter() != *second_parameter();}
7603
7604/// Check if the current diff node carries a local change.
7605///
7606/// @return the kind of local change carried by the current diff node.
7607/// The value returned is zero if the current node carries no local
7608/// change.
7609enum change_kind
7611{
7612 ir::change_kind k = ir::NO_CHANGE_KIND;
7613 if (!equals(*first_parameter(), *second_parameter(), &k))
7614 return k & ir::ALL_LOCAL_CHANGES_MASK;
7615 return ir::NO_CHANGE_KIND;
7616}
7617
7618/// Emit a textual report about the current fn_parm_diff instance.
7619///
7620/// @param out the output stream to emit the textual report to.
7621///
7622/// @param indent the indentation string to use in the report.
7623void
7624fn_parm_diff::report(ostream& out, const string& indent) const
7625{
7626 context()->get_reporter()->report(*this, out, indent);
7627}
7628
7629/// Populate the vector of children nodes of the @ref diff base type
7630/// sub-object of this instance of @ref fn_parm_diff.
7631///
7632/// The children nodes can then later be retrieved using
7633/// diff::children_nodes()
7634void
7636{
7637 if (type_diff())
7639}
7640
7641/// Compute the difference between two function_decl::parameter_sptr;
7642/// that is, between two function parameters. Return a resulting
7643/// fn_parm_diff_sptr that represents the changes.
7644///
7645/// Note that the two decls must have been created in the same @ref
7646/// environment, otherwise, this function aborts.
7647///
7648/// @param first the first subject of the diff.
7649///
7650/// @param second the second subject of the diff.
7651///
7652/// @param ctxt the context of the diff.
7653///
7654/// @return fn_parm_diff_sptr the resulting diff node.
7657 const function_decl::parameter_sptr second,
7658 diff_context_sptr ctxt)
7659{
7660 if (!first || !second)
7661 return fn_parm_diff_sptr();
7662
7663 fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7664 ctxt->initialize_canonical_diff(result);
7665
7666 return result;
7667}
7668// </fn_parm_diff stuff>
7669
7670// <function_type_diff stuff>
7671
7672void
7673function_type_diff::ensure_lookup_tables_populated()
7674{
7675 priv_->return_type_diff_ =
7676 compute_diff(first_function_type()->get_return_type(),
7677 second_function_type()->get_return_type(),
7678 context());
7679
7680 string parm_name;
7682 for (vector<deletion>::const_iterator i =
7683 priv_->parm_changes_.deletions().begin();
7684 i != priv_->parm_changes_.deletions().end();
7685 ++i)
7686 {
7687 parm = *(first_function_type()->get_first_parm()
7688 + i->index());
7689 parm_name = parm->get_name_id();
7690 // If for a reason the type name is empty we want to know and
7691 // fix that.
7692 ABG_ASSERT(!parm_name.empty());
7693 priv_->deleted_parms_[parm_name] = parm;
7694 priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7695 }
7696
7697 for (vector<insertion>::const_iterator i =
7698 priv_->parm_changes_.insertions().begin();
7699 i != priv_->parm_changes_.insertions().end();
7700 ++i)
7701 {
7702 for (vector<unsigned>::const_iterator j =
7703 i->inserted_indexes().begin();
7704 j != i->inserted_indexes().end();
7705 ++j)
7706 {
7707 parm = *(second_function_type()->get_first_parm() + *j);
7708 parm_name = parm->get_name_id();
7709 // If for a reason the type name is empty we want to know and
7710 // fix that.
7711 ABG_ASSERT(!parm_name.empty());
7712 {
7713 string_parm_map::const_iterator k =
7714 priv_->deleted_parms_.find(parm_name);
7715 if (k != priv_->deleted_parms_.end())
7716 {
7717 if (*k->second != *parm)
7718 priv_->subtype_changed_parms_[parm_name] =
7719 compute_diff(k->second, parm, context());
7720 priv_->deleted_parms_.erase(parm_name);
7721 }
7722 else
7723 priv_->added_parms_[parm_name] = parm;
7724 }
7725 {
7726 unsigned_parm_map::const_iterator k =
7727 priv_->deleted_parms_by_id_.find(parm->get_index());
7728 if (k != priv_->deleted_parms_by_id_.end())
7729 {
7730 if (*k->second != *parm
7731 && (k->second->get_name_id() != parm_name))
7732 priv_->changed_parms_by_id_[parm->get_index()] =
7733 compute_diff(k->second, parm, context());
7734 priv_->added_parms_.erase(parm_name);
7735 priv_->deleted_parms_.erase(k->second->get_name_id());
7736 priv_->deleted_parms_by_id_.erase(parm->get_index());
7737 }
7738 else
7739 priv_->added_parms_by_id_[parm->get_index()] = parm;
7740 }
7741 }
7742 }
7743
7744 sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7745 priv_->sorted_subtype_changed_parms_);
7746 sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7747 priv_->sorted_changed_parms_by_id_);
7748 sort_string_parm_map(priv_->deleted_parms_,
7749 priv_->sorted_deleted_parms_);
7750
7751 sort_string_parm_map(priv_->added_parms_,
7752 priv_->sorted_added_parms_);
7753}
7754
7755/// In the vector of deleted parameters, get the one that is at a given
7756/// index.
7757///
7758/// @param i the index of the deleted parameter to get.
7759///
7760/// @return the parameter returned.
7762function_type_diff::deleted_parameter_at(int i) const
7763{return first_function_type()->get_parameters()[i];}
7764
7765/// Getter for the sorted vector of deleted parameters.
7766///
7767/// @return the sorted vector of deleted parameters.
7768const vector<function_decl::parameter_sptr>&
7770{return priv_->sorted_deleted_parms_;}
7771
7772/// Getter for the sorted vector of added parameters .
7773///
7774/// @return the sorted vector of added parameters.
7775const vector<function_decl::parameter_sptr>&
7777{return priv_->sorted_added_parms_;}
7778
7779/// In the vector of inserted parameters, get the one that is at a
7780/// given index.
7781///
7782/// @param i the index of the inserted parameter to get.
7783///
7784/// @return the parameter returned.
7786function_type_diff::inserted_parameter_at(int i) const
7787{return second_function_type()->get_parameters()[i];}
7788
7789/// Consutrctor of the @ref function_type type.
7790///
7791/// @param first the first @ref function_type subject of the diff to
7792/// create.
7793///
7794/// @param second the second @ref function_type subject of the diff to
7795/// create.
7796///
7797/// @param ctxt the diff context to be used by the newly created
7798/// instance of function_type_diff. Note that this context object
7799/// must stay alive at least during the life time of the current
7800/// instance of @ref function_type_diff. Otherwise memory corruption
7801/// issues occur.
7803 const function_type_sptr second,
7804 diff_context_sptr ctxt)
7805 : type_diff_base(first, second, ctxt),
7806 priv_(new priv)
7807{}
7808
7809/// Getter for the first subject of the diff.
7810///
7811/// @return the first function type involved in the diff.
7814{return dynamic_pointer_cast<function_type>(first_subject());}
7815
7816/// Getter for the second subject of the diff.
7817///
7818/// @return the second function type involved in the diff.
7821{return dynamic_pointer_cast<function_type>(second_subject());}
7822
7823/// Getter for the diff of the return types of the two function types
7824/// of the current diff.
7825///
7826/// @return the diff of the return types of the two function types of
7827/// the current diff.
7828const diff_sptr
7830{return priv_->return_type_diff_;}
7831
7832/// Getter for the map of function parameter changes of the current diff.
7833///
7834/// @return a map of function parameter changes of the current diff.
7837{return priv_->subtype_changed_parms_;}
7838
7839/// Getter for the map of parameters that got removed.
7840///
7841/// @return the map of parameters that got removed.
7842const string_parm_map&
7844{return priv_->deleted_parms_;}
7845
7846/// Getter for the map of parameters that got added.
7847///
7848/// @return the map of parameters that got added.
7849const string_parm_map&
7851{return priv_->added_parms_;}
7852
7853/// Build and return a copy of a pretty representation of the current
7854/// instance of @ref function_type_diff.
7855///
7856/// @return a copy of the pretty representation of the current
7857/// instance of @ref function_type_diff.
7858const string&
7860{
7861 if (diff::priv_->pretty_representation_.empty())
7862 {
7863 std::ostringstream o;
7864 o << "function_type_diff["
7866 << ", "
7868 << "]";
7869 diff::priv_->pretty_representation_ = o.str();
7870 }
7871 return diff::priv_->pretty_representation_;
7872}
7873
7874/// Test if the current diff node carries changes.
7875///
7876/// @return true iff the current diff node carries changes.
7877bool
7880
7881/// Test if the current diff node carries local changes.
7882///
7883/// A local change is a change that is carried by this diff node, not
7884/// by any of its children nodes.
7885///
7886/// @return the kind of local change carried by the current diff node.
7887/// The value returned is zero if the current node carries no local
7888/// change.
7889enum change_kind
7891{
7892 ir::change_kind k = ir::NO_CHANGE_KIND;
7894 return k & ir::ALL_LOCAL_CHANGES_MASK;
7895 return ir::NO_CHANGE_KIND;
7896}
7897
7898/// Build and emit a textual report about the current @ref
7899/// function_type_diff instance.
7900///
7901/// @param out the output stream.
7902///
7903/// @param indent the indentation string to use.
7904void
7905function_type_diff::report(ostream& out, const string& indent) const
7906{
7907 context()->get_reporter()->report(*this, out, indent);
7908}
7909
7910/// Populate the vector of children node of the @ref diff base type
7911/// sub-object of this instance of @ref function_type_diff.
7912///
7913/// The children node can then later be retrieved using
7914/// diff::children_node().
7915void
7917{
7918 if (diff_sptr d = return_type_diff())
7920
7921 for (vector<fn_parm_diff_sptr>::const_iterator i =
7922 priv_->sorted_subtype_changed_parms_.begin();
7923 i != priv_->sorted_subtype_changed_parms_.end();
7924 ++i)
7925 if (diff_sptr d = *i)
7927
7928 for (vector<fn_parm_diff_sptr>::const_iterator i =
7929 priv_->sorted_changed_parms_by_id_.begin();
7930 i != priv_->sorted_changed_parms_by_id_.end();
7931 ++i)
7932 if (diff_sptr d = *i)
7934}
7935
7936/// Compute the diff between two instances of @ref function_type.
7937///
7938/// Note that the two types must have been created in the same @ref
7939/// environment, otherwise, this function aborts.
7940///
7941/// @param first the first @ref function_type to consider for the diff.
7942///
7943/// @param second the second @ref function_type to consider for the diff.
7944///
7945/// @param ctxt the diff context to use.
7946///
7947/// @return the resulting diff between the two @ref function_type.
7950 const function_type_sptr second,
7951 diff_context_sptr ctxt)
7952{
7953 if (!first || !second)
7954 {
7955 // TODO: implement this for either first or second being NULL.
7956 return function_type_diff_sptr();
7957 }
7958
7959 function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7960
7961 diff_utils::compute_diff(first->get_first_parm(),
7962 first->get_parameters().end(),
7963 second->get_first_parm(),
7964 second->get_parameters().end(),
7965 result->priv_->parm_changes_);
7966
7967 result->ensure_lookup_tables_populated();
7968
7969 ctxt->initialize_canonical_diff(result);
7970
7971 return result;
7972}
7973// </function_type_diff stuff>
7974
7975// <function_decl_diff stuff>
7976
7977/// Build the lookup tables of the diff, if necessary.
7978void
7979function_decl_diff::ensure_lookup_tables_populated()
7980{
7981}
7982
7983/// Populate the vector of children node of the @ref diff base type
7984/// sub-object of this instance of @ref function_decl_diff.
7985///
7986/// The children node can then later be retrieved using
7987/// diff::children_node().
7988void
7990{
7991 if (diff_sptr d = type_diff())
7993}
7994
7995/// Constructor for function_decl_diff
7996///
7997/// @param first the first function considered by the diff.
7998///
7999/// @param second the second function considered by the diff.
8000///
8001/// @param ctxt the context of the diff. Note that this context
8002/// object must stay alive at least during the life time of the
8003/// current instance of @ref function_decl_diff. Otherwise memory
8004/// corruption issues occur.
8006 const function_decl_sptr second,
8007 diff_context_sptr ctxt)
8008 : decl_diff_base(first, second, ctxt),
8009 priv_(new priv)
8010{
8011}
8012
8013/// @return the first function considered by the diff.
8016{return dynamic_pointer_cast<function_decl>(first_subject());}
8017
8018/// @return the second function considered by the diff.
8021{return dynamic_pointer_cast<function_decl>(second_subject());}
8022
8024function_decl_diff::type_diff() const
8025{return priv_->type_diff_;}
8026
8027/// @return the pretty representation for the current instance of @ref
8028/// function_decl_diff.
8029const string&
8031{
8032 if (diff::priv_->pretty_representation_.empty())
8033 {
8034 std::ostringstream o;
8035 o << "function_diff["
8036 << first_subject()->get_pretty_representation()
8037 << ", "
8038 << second_subject()->get_pretty_representation()
8039 << "]";
8040 diff::priv_->pretty_representation_ = o.str();
8041 }
8042 return diff::priv_->pretty_representation_;
8043}
8044
8045/// Return true iff the current diff node carries a change.
8046///
8047/// @return true iff the current diff node carries a change.
8048bool
8051
8052/// @return the kind of local change carried by the current diff node.
8053/// The value returned is zero if the current node carries no local
8054/// change.
8055enum change_kind
8057{
8058 ir::change_kind k = ir::NO_CHANGE_KIND;
8060 return k & ir::ALL_LOCAL_CHANGES_MASK;
8061 return ir::NO_CHANGE_KIND;
8062}
8063
8064/// Serialize a report of the changes encapsulated in the current
8065/// instance of @ref function_decl_diff over to an output stream.
8066///
8067/// @param out the output stream to serialize the report to.
8068///
8069/// @param indent the string to use an an indentation prefix.
8070void
8071function_decl_diff::report(ostream& out, const string& indent) const
8072{
8073 context()->get_reporter()->report(*this, out, indent);
8074}
8075
8076/// Compute the diff between two function_decl.
8077///
8078/// Note that the two decls must have been created in the same @ref
8079/// environment, otherwise, this function aborts.
8080///
8081/// @param first the first function_decl to consider for the diff
8082///
8083/// @param second the second function_decl to consider for the diff
8084///
8085/// @param ctxt the diff context to use.
8086///
8087/// @return the computed diff
8090 const function_decl_sptr second,
8091 diff_context_sptr ctxt)
8092{
8093 if (!first || !second)
8094 {
8095 // TODO: implement this for either first or second being NULL.
8096 return function_decl_diff_sptr();
8097 }
8098
8099 function_type_diff_sptr type_diff = compute_diff(first->get_type(),
8100 second->get_type(),
8101 ctxt);
8102
8103 function_decl_diff_sptr result(new function_decl_diff(first, second,
8104 ctxt));
8105 result->priv_->type_diff_ = type_diff;
8106
8107 result->ensure_lookup_tables_populated();
8108
8109 ctxt->initialize_canonical_diff(result);
8110
8111 return result;
8112}
8113
8114// </function_decl_diff stuff>
8115
8116// <type_decl_diff stuff>
8117
8118/// Constructor for type_decl_diff.
8119///
8120/// @param first the first subject of the diff.
8121///
8122/// @param second the second subject of the diff.
8123///
8124/// @param ctxt the context of the diff. Note that this context
8125/// object must stay alive at least during the life time of the
8126/// current instance of @ref type_decl_diff. Otherwise memory
8127/// corruption issues occur.
8128type_decl_diff::type_decl_diff(const type_decl_sptr first,
8129 const type_decl_sptr second,
8130 diff_context_sptr ctxt)
8131 : type_diff_base(first, second, ctxt)
8132{}
8133
8134/// Getter for the first subject of the type_decl_diff.
8135///
8136/// @return the first type_decl involved in the diff.
8137const type_decl_sptr
8139{return dynamic_pointer_cast<type_decl>(first_subject());}
8140
8141/// Getter for the second subject of the type_decl_diff.
8142///
8143/// @return the second type_decl involved in the diff.
8144const type_decl_sptr
8146{return dynamic_pointer_cast<type_decl>(second_subject());}
8147
8148/// @return the pretty representation for the current instance of @ref
8149/// type_decl_diff.
8150const string&
8152{
8153 if (diff::priv_->pretty_representation_.empty())
8154 {
8155 std::ostringstream o;
8156 o << "type_decl_diff["
8157 << first_subject()->get_pretty_representation()
8158 << ", "
8159 << second_subject()->get_pretty_representation()
8160 << "]";
8161 diff::priv_->pretty_representation_ = o.str();
8162 }
8163 return diff::priv_->pretty_representation_;
8164}
8165/// Return true iff the current diff node carries a change.
8166///
8167/// @return true iff the current diff node carries a change.
8168bool
8170{return first_type_decl() != second_type_decl();}
8171
8172/// @return the kind of local change carried by the current diff node.
8173/// The value returned is zero if the current node carries no local
8174/// change.
8175enum change_kind
8177{
8178 ir::change_kind k = ir::NO_CHANGE_KIND;
8179 if (!equals(*first_type_decl(), *second_type_decl(), &k))
8180 return k & ir::ALL_LOCAL_CHANGES_MASK;
8181 return ir::NO_CHANGE_KIND;
8182}
8183/// Ouputs a report of the differences between of the two type_decl
8184/// involved in the type_decl_diff.
8185///
8186/// @param out the output stream to emit the report to.
8187///
8188/// @param indent the string to use for indentatino indent.
8189void
8190type_decl_diff::report(ostream& out, const string& indent) const
8191{
8192 context()->get_reporter()->report(*this, out, indent);
8193}
8194
8195/// Compute a diff between two type_decl.
8196///
8197/// Note that the two types must have been created in the same @ref
8198/// environment, otherwise, this function aborts.
8199///
8200/// This function doesn't actually compute a diff. As a type_decl is
8201/// very simple (unlike compound constructs like function_decl or
8202/// class_decl) it's easy to just compare the components of the
8203/// type_decl to know what has changed. Thus this function just
8204/// builds and return a type_decl_diff object. The
8205/// type_decl_diff::report function will just compare the components
8206/// of the the two type_decl and display where and how they differ.
8207///
8208/// @param first a pointer to the first type_decl to
8209/// consider.
8210///
8211/// @param second a pointer to the second type_decl to consider.
8212///
8213/// @param ctxt the diff context to use.
8214///
8215/// @return a pointer to the resulting type_decl_diff.
8218 const type_decl_sptr second,
8219 diff_context_sptr ctxt)
8220{
8221 type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
8222
8223 // We don't need to actually compute a diff here as a type_decl
8224 // doesn't have complicated sub-components. type_decl_diff::report
8225 // just walks the members of the type_decls and display information
8226 // about the ones that have changed. On a similar note,
8227 // type_decl_diff::length returns 0 if the two type_decls are equal,
8228 // and 1 otherwise.
8229
8230 ctxt->initialize_canonical_diff(result);
8231
8232 return result;
8233}
8234
8235// </type_decl_diff stuff>
8236
8237// <typedef_diff stuff>
8238
8239/// Populate the vector of children node of the @ref diff base type
8240/// sub-object of this instance of @ref typedef_diff.
8241///
8242/// The children node can then later be retrieved using
8243/// diff::children_node().
8244void
8247
8248/// Constructor for typedef_diff.
8249///
8250/// @param first the first subject of the diff.
8251///
8252/// @param second the second subject of the diff.
8253///
8254/// @param underlying the underlying diff of the @ref typedef_diff.
8255/// That is the diff between the underlying types of @p first and @p
8256/// second.
8257///
8258/// @param ctxt the context of the diff. Note that this context
8259/// object must stay alive at least during the life time of the
8260/// current instance of @ref typedef_diff. Otherwise memory
8261/// corruption issues occur.
8262typedef_diff::typedef_diff(const typedef_decl_sptr first,
8263 const typedef_decl_sptr second,
8264 const diff_sptr underlying,
8265 diff_context_sptr ctxt)
8266 : type_diff_base(first, second, ctxt),
8267 priv_(new priv(underlying))
8268{}
8269
8270/// Getter for the firt typedef_decl involved in the diff.
8271///
8272/// @return the first subject of the diff.
8275{return dynamic_pointer_cast<typedef_decl>(first_subject());}
8276
8277/// Getter for the second typedef_decl involved in the diff.
8278///
8279/// @return the second subject of the diff.
8282{return dynamic_pointer_cast<typedef_decl>(second_subject());}
8283
8284/// Getter for the diff between the two underlying types of the
8285/// typedefs.
8286///
8287/// @return the diff object reprensenting the difference between the
8288/// two underlying types of the typedefs.
8289const diff_sptr
8291{return priv_->underlying_type_diff_;}
8292
8293/// Setter for the diff between the two underlying types of the
8294/// typedefs.
8295///
8296/// @param d the new diff object reprensenting the difference between
8297/// the two underlying types of the typedefs.
8298void
8300{priv_->underlying_type_diff_ = d;}
8301
8302/// @return the pretty representation for the current instance of @ref
8303/// typedef_diff.
8304const string&
8306{
8307 if (diff::priv_->pretty_representation_.empty())
8308 {
8309 std::ostringstream o;
8310 o << "typedef_diff["
8311 << first_subject()->get_pretty_representation()
8312 << ", "
8313 << second_subject()->get_pretty_representation()
8314 << "]";
8315 diff::priv_->pretty_representation_ = o.str();
8316 }
8317 return diff::priv_->pretty_representation_;
8318}
8319
8320/// Return true iff the current diff node carries a change.
8321///
8322/// @return true iff the current diff node carries a change.
8323bool
8325{
8326 decl_base_sptr second = second_typedef_decl();
8327 return !(*first_typedef_decl() == *second);
8328}
8329
8330/// @return the kind of local change carried by the current diff node.
8331/// The value returned is zero if the current node carries no local
8332/// change.
8333enum change_kind
8335{
8336 ir::change_kind k = ir::NO_CHANGE_KIND;
8338 return k & ir::ALL_LOCAL_CHANGES_MASK;
8339 return ir::NO_CHANGE_KIND;
8340}
8341
8342/// Reports the difference between the two subjects of the diff in a
8343/// serialized form.
8344///
8345/// @param out the output stream to emit the report to.
8346///
8347/// @param indent the indentation string to use.
8348void
8349typedef_diff::report(ostream& out, const string& indent) const
8350{
8351 context()->get_reporter()->report(*this, out, indent);
8352}
8353
8354/// Compute a diff between two typedef_decl.
8355///
8356/// Note that the two types must have been created in the same @ref
8357/// environment, otherwise, this function aborts.
8358///
8359/// @param first a pointer to the first typedef_decl to consider.
8360///
8361/// @param second a pointer to the second typedef_decl to consider.
8362///
8363/// @param ctxt the diff context to use.
8364///
8365/// @return a pointer to the the resulting typedef_diff.
8368 const typedef_decl_sptr second,
8369 diff_context_sptr ctxt)
8370{
8371 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
8372 second->get_underlying_type(),
8373 ctxt);
8374 typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
8375
8376 ctxt->initialize_canonical_diff(result);
8377
8378 return result;
8379}
8380
8381/// Return the leaf underlying diff node of a @ref typedef_diff node.
8382///
8383/// If the underlying diff node of a @ref typedef_diff node is itself
8384/// a @ref typedef_diff node, then recursively look at the underlying
8385/// diff nodes to get the first one that is not a a @ref typedef_diff
8386/// node. This is what a leaf underlying diff node means.
8387///
8388/// Otherwise, if the underlying diff node of @ref typedef_diff is
8389/// *NOT* a @ref typedef_diff node, then just return the underlying
8390/// diff node.
8391///
8392/// And if the diff node considered is not a @ref typedef_diff node,
8393/// then just return it.
8394///
8395/// @return the leaf underlying diff node of a @p diff.
8396const diff*
8398{
8399 const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
8400 if (!d)
8401 return diff;
8402
8403 if (const typedef_diff* deef =
8404 dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
8406
8407 return d->underlying_type_diff().get();
8408}
8409
8410// </typedef_diff stuff>
8411
8412// <translation_unit_diff stuff>
8413
8414/// Constructor for translation_unit_diff.
8415///
8416/// @param first the first translation unit to consider for this diff.
8417///
8418/// @param second the second translation unit to consider for this diff.
8419///
8420/// @param ctxt the context of the diff. Note that this context
8421/// object must stay alive at least during the life time of the
8422/// current instance of @ref translation_unit_diff. Otherwise memory
8423/// corruption issues occur.
8425 translation_unit_sptr second,
8426 diff_context_sptr ctxt)
8427 : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
8428 priv_(new priv(first, second))
8429{
8430}
8431
8432/// Getter for the first translation unit of this diff.
8433///
8434/// @return the first translation unit of this diff.
8437{return priv_->first_;}
8438
8439/// Getter for the second translation unit of this diff.
8440///
8441/// @return the second translation unit of this diff.
8444{return priv_->second_;}
8445
8446/// Return true iff the current diff node carries a change.
8447///
8448/// @return true iff the current diff node carries a change.
8449bool
8451{return scope_diff::has_changes();}
8452
8453/// @return the kind of local change carried by the current diff node.
8454/// The value returned is zero if the current node carries no local
8455/// change.
8456enum change_kind
8458{return ir::NO_CHANGE_KIND;}
8459
8460/// Report the diff in a serialized form.
8461///
8462/// @param out the output stream to serialize the report to.
8463///
8464/// @param indent the prefix to use as indentation for the report.
8465void
8466translation_unit_diff::report(ostream& out, const string& indent) const
8467{scope_diff::report(out, indent);}
8468
8469/// Compute the diff between two translation_units.
8470///
8471/// Note that the two translation units must have been created in the
8472/// same @ref environment, otherwise, this function aborts.
8473///
8474/// @param first the first translation_unit to consider.
8475///
8476/// @param second the second translation_unit to consider.
8477///
8478/// @param ctxt the diff context to use. If null, this function will
8479/// create a new context and set to the diff object returned.
8480///
8481/// @return the newly created diff object.
8484 const translation_unit_sptr second,
8485 diff_context_sptr ctxt)
8486{
8487 ABG_ASSERT(first && second);
8488
8489 if (!ctxt)
8490 ctxt.reset(new diff_context);
8491
8492 // TODO: handle first or second having empty contents.
8493 translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
8494 ctxt));
8495 scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
8496
8497 compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
8498 static_pointer_cast<scope_decl>(second->get_global_scope()),
8499 sc_diff,
8500 ctxt);
8501
8502 ctxt->initialize_canonical_diff(tu_diff);
8503
8504 return tu_diff;
8505}
8506
8507// </translation_unit_diff stuff>
8508
8509// <diff_maps stuff>
8510
8511/// The private data of the @ref diff_maps type.
8512struct diff_maps::priv
8513{
8514 string_diff_ptr_map type_decl_diff_map_;
8515 string_diff_ptr_map enum_diff_map_;
8516 string_diff_ptr_map class_diff_map_;
8517 string_diff_ptr_map union_diff_map_;
8518 string_diff_ptr_map typedef_diff_map_;
8519 string_diff_ptr_map subrange_diff_map_;
8520 string_diff_ptr_map array_diff_map_;
8521 string_diff_ptr_map reference_diff_map_;
8522 string_diff_ptr_map function_type_diff_map_;
8523 string_diff_ptr_map function_decl_diff_map_;
8524 string_diff_ptr_map var_decl_diff_map_;
8525 string_diff_ptr_map distinct_diff_map_;
8526 string_diff_ptr_map fn_parm_diff_map_;
8527 diff_artifact_set_map_type impacted_artifacts_map_;
8528}; // end struct diff_maps::priv
8529
8530/// Default constructor of the @ref diff_maps type.
8532 : priv_(new diff_maps::priv())
8533{}
8534
8535diff_maps::~diff_maps() = default;
8536
8537/// Getter of the map that contains basic type diffs.
8538///
8539/// @return the map that contains basic type diffs.
8542{return priv_->type_decl_diff_map_;}
8543
8544/// Getter of the map that contains basic type diffs.
8545///
8546/// @return the map that contains basic type diffs.
8549{return priv_->type_decl_diff_map_;}
8550
8551/// Getter of the map that contains enum type diffs.
8552///
8553/// @return the map that contains enum type diffs.
8556{return priv_->enum_diff_map_;}
8557
8558/// Getter of the map that contains enum type diffs.
8559///
8560/// @return the map that contains enum type diffs.
8563{return priv_->enum_diff_map_;}
8564
8565/// Getter of the map that contains class type diffs.
8566///
8567/// @return the map that contains class type diffs.
8570{return priv_->class_diff_map_;}
8571
8572/// Getter of the map that contains class type diffs.
8573///
8574/// @return the map that contains class type diffs.
8577{return priv_->class_diff_map_;}
8578
8579/// Getter of the map that contains union type diffs.
8580///
8581/// @return the map that contains union type diffs.
8584{return priv_->union_diff_map_;}
8585
8586/// Getter of the map that contains union type diffs.
8587///
8588/// @return the map that contains union type diffs.
8591{return priv_->union_diff_map_;}
8592
8593/// Getter of the map that contains typedef type diffs.
8594///
8595/// @return the map that contains typedef type diffs.
8598{return priv_->typedef_diff_map_;}
8599
8600/// Getter of the map that contains typedef type diffs.
8601///
8602/// @return the map that contains typedef type diffs.
8605{return priv_->typedef_diff_map_;}
8606
8607/// Getter of the map that contains subrange type diffs.
8608///
8609/// @return the map that contains subrange type diffs.
8612{return priv_->subrange_diff_map_;}
8613
8614/// Getter of the map that contains subrange type diffs.
8615///
8616/// @return the map that contains subrange type diffs.
8619{return priv_->subrange_diff_map_;}
8620
8621/// Getter of the map that contains array type diffs.
8622///
8623/// @return the map that contains array type diffs.
8626{return priv_->array_diff_map_;}
8627
8628/// Getter of the map that contains array type diffs.
8629///
8630/// @return the map that contains array type diffs.
8633{return priv_->array_diff_map_;}
8634
8635/// Getter of the map that contains reference type diffs.
8636///
8637/// @return the map that contains reference type diffs.
8640{return priv_->reference_diff_map_;}
8641
8642/// Getter of the map that contains reference type diffs.
8643///
8644/// @return the map that contains reference type diffs.
8647{{return priv_->reference_diff_map_;}}
8648
8649/// Getter of the map that contains function parameter diffs.
8650///
8651/// @return the map that contains function parameter diffs.
8654{return priv_->fn_parm_diff_map_;}
8655
8656/// Getter of the map that contains function parameter diffs.
8657///
8658/// @return the map that contains function parameter diffs.
8661{return priv_->fn_parm_diff_map_;}
8662
8663/// Getter of the map that contains function type diffs.
8664///
8665/// @return the map that contains function type diffs.
8668{return priv_->function_type_diff_map_;}
8669
8670/// Getter of the map that contains function type diffs.
8671///
8672/// @return the map that contains function type diffs.
8675{return priv_->function_type_diff_map_;}
8676
8677/// Getter of the map that contains function decl diffs.
8678///
8679/// @return the map that contains function decl diffs.
8682{return priv_->function_decl_diff_map_;}
8683
8684/// Getter of the map that contains function decl diffs.
8685///
8686/// @return the map that contains function decl diffs.
8689{return priv_->function_decl_diff_map_;}
8690
8691/// Getter of the map that contains var decl diffs.
8692///
8693/// @return the map that contains var decl diffs.
8696{return priv_->var_decl_diff_map_;}
8697
8698/// Getter of the map that contains var decl diffs.
8699///
8700/// @return the map that contains var decl diffs.
8703{return priv_->var_decl_diff_map_;}
8704
8705/// Getter of the map that contains distinct diffs.
8706///
8707/// @return the map that contains distinct diffs.
8710{return priv_->distinct_diff_map_;}
8711
8712/// Getter of the map that contains distinct diffs.
8713///
8714/// @return the map that contains distinct diffs.
8717{return priv_->distinct_diff_map_;}
8718
8719/// Insert a new diff node into the current instance of @ref diff_maps.
8720///
8721/// @param dif the new diff node to insert into the @ref diff_maps.
8722///
8723/// @param impacted_iface the interface (global function or variable)
8724/// currently being analysed that led to analysing the diff node @p
8725/// dif. In other words, this is the interface impacted by the diff
8726/// node @p dif. Note that this can be nil in cases where we are
8727/// directly analysing changes to a type that is not reachable from
8728/// any global function or variable.
8729///
8730/// @return true iff the diff node could be added to the current
8731/// instance of @ref diff_maps.
8732bool
8734 const type_or_decl_base_sptr& impacted_iface)
8735{
8736 string n = get_pretty_representation(dif->first_subject(),
8737 /*internal=*/true);
8738 if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8739 get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8740 else if (const enum_diff *d = is_enum_diff(dif))
8741 get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8742 else if (const class_diff *d = is_class_diff(dif))
8743 get_class_diff_map()[n] = const_cast<class_diff*>(d);
8744 else if (const union_diff *d = is_union_diff(dif))
8745 get_union_diff_map()[n] = const_cast<union_diff*>(d);
8746 else if (const typedef_diff *d = is_typedef_diff(dif))
8747 get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8748 else if (const subrange_diff *d = is_subrange_diff(dif))
8749 get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8750 else if (const array_diff *d = is_array_diff(dif))
8751 get_array_diff_map()[n] = const_cast<array_diff*>(d);
8752 else if (const reference_diff *d = is_reference_diff(dif))
8753 get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8754 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8755 get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8756 else if (const function_type_diff *d = is_function_type_diff(dif))
8757 get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8758 else if (const var_diff *d = is_var_diff(dif))
8759 get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8760 else if (const function_decl_diff *d = is_function_decl_diff(dif))
8761 get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8762 else if (const distinct_diff *d = is_distinct_diff(dif))
8763 get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8764 else if (is_base_diff(dif))
8765 // we silently drop this case.
8766 return true;
8767 else
8769
8770 // Update the map that associates this diff node to the set of
8771 // interfaces it impacts.
8772
8773 if (impacted_iface)
8774 {
8775 diff_artifact_set_map_type::iterator i =
8776 priv_->impacted_artifacts_map_.find(dif);
8777
8778 if (i == priv_->impacted_artifacts_map_.end())
8779 {
8781 set.insert(impacted_iface);
8782 priv_->impacted_artifacts_map_[dif] = set;
8783 }
8784 else
8785 i->second.insert(impacted_iface);
8786 }
8787
8788 return true;
8789}
8790
8791/// Lookup the interfaces that are impacted by a given leaf diff node.
8792///
8793/// @param d the diff node to consider.
8794///
8795/// @return the set of artifacts impacted by @p d.
8798{
8799 diff_artifact_set_map_type::iterator i =
8800 priv_->impacted_artifacts_map_.find(d);
8801
8802 if (i == priv_->impacted_artifacts_map_.end())
8803 return 0;
8804
8805 return &i->second;
8806}
8807
8808//
8809// </diff_maps stuff>
8810
8811/// Constructor for the @ref diff_stat type.
8812///
8813/// @param ctxt the context of the corpus diff. Note that this
8814/// context object must stay alive at least during the life time of
8815/// the current instance of @ref corpus_diff::diff_stats. Otherwise
8816/// memory corruption issues occur.
8817corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8818 : priv_(new priv(ctxt))
8819{}
8820
8821/// Getter for the number of functions removed.
8822///
8823/// @return the number of functions removed.
8824size_t
8826{return priv_->num_func_removed;}
8827
8828/// Setter for the number of functions removed.
8829///
8830/// @param n the new number of functions removed.
8831void
8833{priv_->num_func_removed = n;}
8834
8835/// Getter for the number of removed functions that have been filtered
8836/// out.
8837///
8838/// @return the number of removed functions that have been filtered
8839/// out.
8840size_t
8842{
8843 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8844 return num_func_removed();
8845 return priv_->num_removed_func_filtered_out;
8846}
8847
8848/// Setter for the number of removed functions that have been filtered
8849/// out.
8850///
8851/// @param t the new value.
8852void
8854{priv_->num_removed_func_filtered_out = t;}
8855
8856/// Getter for the net number of function removed.
8857///
8858/// This is the difference between the number of functions removed and
8859/// the number of functons removed that have been filtered out.
8860///
8861/// @return the net number of function removed.
8862size_t
8864{
8865 ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8866 return num_func_removed() - num_removed_func_filtered_out();
8867}
8868
8869/// Getter for the number of functions added.
8870///
8871/// @return the number of functions added.
8872size_t
8874{return priv_->num_func_added;}
8875
8876/// Setter for the number of functions added.
8877///
8878/// @param n the new number of functions added.
8879void
8881{priv_->num_func_added = n;}
8882
8883/// Getter for the number of added function that have been filtered out.
8884///
8885/// @return the number of added function that have been filtered out.
8886size_t
8888{
8889 if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8890 return num_func_added();
8891 return priv_->num_added_func_filtered_out;
8892}
8893
8894/// Setter for the number of added function that have been filtered
8895/// out.
8896///
8897/// @param n the new value.
8898void
8900{priv_->num_added_func_filtered_out = n;}
8901
8902/// Getter for the net number of added functions.
8903///
8904/// The net number of added functions is the difference between the
8905/// number of added functions and the number of added functions that
8906/// have been filtered out.
8907///
8908/// @return the net number of added functions.
8909size_t
8911{
8912 ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8913 return num_func_added() - num_added_func_filtered_out();
8914}
8915
8916/// Getter for the number of functions that have a change in one of
8917/// their sub-types.
8918///
8919/// @return the number of functions that have a change in one of their
8920/// sub-types.
8921size_t
8923{return priv_->num_func_changed;}
8924
8925/// Setter for the number of functions that have a change in one of
8926/// their sub-types.
8927///
8928/// @@param n the new number of functions that have a change in one of
8929/// their sub-types.
8930void
8932{priv_->num_func_changed = n;}
8933
8934/// Getter for the number of functions that have a change in one of
8935/// their sub-types, and that have been filtered out.
8936///
8937/// @return the number of functions that have a change in one of their
8938/// sub-types, and that have been filtered out.
8939size_t
8941{return priv_->num_changed_func_filtered_out;}
8942
8943/// Setter for the number of functions that have a change in one of
8944/// their sub-types, and that have been filtered out.
8945///
8946/// @param n the new number of functions that have a change in one of their
8947/// sub-types, and that have been filtered out.
8948void
8950{priv_->num_changed_func_filtered_out = n;}
8951
8952/// Getter for the number of functions that carry virtual member
8953/// offset changes.
8954///
8955/// @return the number of functions that carry virtual member changes.
8956size_t
8958{return priv_->num_func_with_virt_offset_changes;}
8959
8960/// Setter for the number of functions that carry virtual member
8961/// offset changes.
8962///
8963/// @param n the new number of functions that carry virtual member
8964/// offset. changes.
8965void
8967{priv_->num_func_with_virt_offset_changes = n;}
8968
8969/// Getter for the number of functions with local harmful changes.
8970///
8971/// A local harmful change is a harmful change that is local to the
8972/// function itself or is local to a return or parameter type.
8973///
8974/// @return the number of functions with local harmful changes.
8975size_t
8977{return priv_->num_func_with_local_harmful_changes;}
8978
8979/// Setter for the number of functions with local harmful changes.
8980///
8981/// A local harmful change is a harmful change that is local to the
8982/// function itself or is local to a return or parameter type.
8983///
8984/// @param n the number of functions with local harmful changes.
8985void
8987{priv_->num_func_with_local_harmful_changes = n;}
8988
8989/// Getter for the number of variables with local harmful changes.
8990///
8991/// A local harmful change is a harmful change that is local to the
8992/// variable itself or is local to its type.
8993///
8994/// @return the number of variables with local harmful changes.
8995size_t
8997{return priv_->num_var_with_local_harmful_changes;}
8998
8999/// Setter for the number of variables with local harmful changes.
9000///
9001/// A local harmful change is a harmful change that is local to the
9002/// variable itself or is local to its type.
9003///
9004/// @param n the number of variables with local harmful changes.
9005void
9007{priv_->num_var_with_local_harmful_changes = n;}
9008
9009/// Getter for the number of functions with incompatible changes.
9010///
9011/// @return the number of functions with incompatible changes.
9012size_t
9014{return priv_->num_func_with_incompatible_changes;}
9015
9016/// Setter for the number of functions with incompatible changes.
9017///
9018/// @param n the number of functions with incompatible changes.
9019void
9021{priv_->num_func_with_incompatible_changes = n;}
9022
9023/// Getter for the number of variables with incompatible changes.
9024///
9025/// @return the number of variables with incompatible changes.
9026size_t
9028{return priv_->num_var_with_incompatible_changes;}
9029
9030/// Setter for the number of variables with incompatible changes.
9031///
9032/// @param n the number of variables with incompatible changes.
9033void
9035{priv_->num_var_with_incompatible_changes = n;}
9036
9037/// Getter for the number of functions that have a change in their
9038/// sub-types, minus the number of these functions that got filtered
9039/// out from the diff.
9040///
9041/// @return for the the number of functions that have a change in
9042/// their sub-types, minus the number of these functions that got
9043/// filtered out from the diff.
9044size_t
9046{return num_func_changed() - num_changed_func_filtered_out();}
9047
9048/// Getter of the net number of functions with changes that are not
9049/// incompatible.
9050///
9051/// @return net number of functions with changes that are not
9052/// incompatible.
9053size_t
9055{return net_num_func_changed() - num_func_with_incompatible_changes();}
9056
9057/// Getter for the number of variables removed.
9058///
9059/// @return the number of variables removed.
9060size_t
9062{return priv_->num_vars_removed;}
9063
9064/// Setter for the number of variables removed.
9065///
9066/// @param n the new number of variables removed.
9067void
9069{priv_->num_vars_removed = n;}
9070
9071/// Getter for the number removed variables that have been filtered
9072/// out.
9073///
9074/// @return the number removed variables that have been filtered out.
9075size_t
9077{
9078 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
9079 return num_vars_removed();
9080 return priv_->num_removed_vars_filtered_out;
9081}
9082
9083/// Setter for the number of removed variables that have been filtered
9084/// out.
9085///
9086/// @param n the new value.
9087void
9089{priv_->num_removed_vars_filtered_out = n;}
9090
9091/// Getter for the net number of removed variables.
9092///
9093/// The net number of removed variables is the difference between the
9094/// number of removed variables and the number of removed variables
9095/// that have been filtered out.
9096///
9097/// @return the net number of removed variables.
9098size_t
9100{
9101 ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
9102 return num_vars_removed() - num_removed_vars_filtered_out();
9103}
9104
9105/// Getter for the number of variables added.
9106///
9107/// @return the number of variables added.
9108size_t
9110{return priv_->num_vars_added;}
9111
9112/// Setter for the number of variables added.
9113///
9114/// @param n the new number of variables added.
9115void
9117{priv_->num_vars_added = n;}
9118
9119/// Getter for the number of added variables that have been filtered
9120/// out.
9121///
9122/// @return the number of added variables that have been filtered out.
9123size_t
9125{
9126 if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
9127 return num_vars_added();
9128 return priv_->num_added_vars_filtered_out;
9129}
9130
9131/// Setter for the number of added variables that have been filtered
9132/// out.
9133///
9134/// @param n the new value.
9135void
9137{priv_->num_added_vars_filtered_out = n;}
9138
9139/// Getter for the net number of added variables.
9140///
9141/// The net number of added variables is the difference between the
9142/// number of added variables and the number of added variables that
9143/// have been filetered out.
9144///
9145/// @return the net number of added variables.
9146size_t
9148{
9149 ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
9150 return num_vars_added() - num_added_vars_filtered_out();
9151}
9152
9153/// Getter for the number of variables that have a change in one of
9154/// their sub-types.
9155///
9156/// @return the number of variables that have a change in one of their
9157/// sub-types.
9158size_t
9160{return priv_->num_vars_changed;}
9161
9162/// Setter for the number of variables that have a change in one of
9163/// their sub-types.
9164///
9165/// @param n the new number of variables that have a change in one of
9166/// their sub-types.
9167void
9169{priv_->num_vars_changed = n;}
9170
9171/// Getter for the number of variables that have a change in one of
9172/// their sub-types, and that have been filtered out.
9173///
9174/// @return the number of functions that have a change in one of their
9175/// sub-types, and that have been filtered out.
9176size_t
9178{return priv_->num_changed_vars_filtered_out;}
9179
9180/// Setter for the number of variables that have a change in one of
9181/// their sub-types, and that have been filtered out.
9182///
9183/// @param n the new number of variables that have a change in one of their
9184/// sub-types, and that have been filtered out.
9185void
9187{priv_->num_changed_vars_filtered_out = n;}
9188
9189/// Getter for the number of variables that have a change in their
9190/// sub-types, minus the number of these variables that got filtered
9191/// out from the diff.
9192///
9193/// @return for the the number of variables that have a change in
9194/// their sub-types, minus the number of these variables that got
9195/// filtered out from the diff.
9196size_t
9198{return num_vars_changed() - num_changed_vars_filtered_out();}
9199
9200/// Getter of the net number of variables with changes that are not
9201/// incompatible.
9202///
9203/// @return net number of variables with changes that are not
9204/// incompatible.
9205size_t
9207{return net_num_vars_changed() - num_var_with_incompatible_changes();}
9208
9209/// Getter for the number of function symbols (not referenced by any
9210/// debug info) that got removed.
9211///
9212/// @return the number of function symbols (not referenced by any
9213/// debug info) that got removed.
9214size_t
9216{return priv_->num_func_syms_removed;}
9217
9218/// Setter for the number of function symbols (not referenced by any
9219/// debug info) that got removed.
9220///
9221/// @param n the number of function symbols (not referenced by any
9222/// debug info) that got removed.
9223void
9225{priv_->num_func_syms_removed = n;}
9226
9227/// Getter for the number of removed function symbols, not referenced
9228/// by debug info, that have been filtered out.
9229///
9230/// @return the number of removed function symbols, not referenced by
9231/// debug info, that have been filtered out.
9232size_t
9234{
9235 if (priv_->ctxt()
9236 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
9237 return num_func_syms_removed();
9238 return priv_->num_removed_func_syms_filtered_out;
9239}
9240
9241/// Setter for the number of removed function symbols, not referenced
9242/// by debug info, that have been filtered out.
9243///
9244/// @param n the new the number of removed function symbols, not
9245/// referenced by debug info, that have been filtered out.
9246void
9248{priv_->num_removed_func_syms_filtered_out = n;}
9249
9250/// Getter of the net number of removed function symbols that are not
9251/// referenced by any debug info.
9252///
9253/// This is the difference between the total number of removed
9254/// function symbols and the number of removed function symbols that
9255/// have been filteted out. Both numbers are for symbols not
9256/// referenced by debug info.
9257///
9258/// return the net number of removed function symbols that are not
9259/// referenced by any debug info.
9260size_t
9262{
9263 ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
9264 return num_func_syms_removed() - num_removed_func_syms_filtered_out();
9265}
9266
9267/// Getter for the number of function symbols (not referenced by any
9268/// debug info) that got added.
9269///
9270/// @return the number of function symbols (not referenced by any
9271/// debug info) that got added.
9272size_t
9274{return priv_->num_func_syms_added;}
9275
9276/// Setter for the number of function symbols (not referenced by any
9277/// debug info) that got added.
9278///
9279/// @param n the new number of function symbols (not referenced by any
9280/// debug info) that got added.
9281void
9283{priv_->num_func_syms_added = n;}
9284
9285/// Getter for the number of added function symbols, not referenced by
9286/// any debug info, that have been filtered out.
9287///
9288/// @return the number of added function symbols, not referenced by
9289/// any debug info, that have been filtered out.
9290size_t
9292{
9293 if (priv_->ctxt()
9294 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9295 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9296 return num_func_syms_added();
9297 return priv_->num_added_func_syms_filtered_out;
9298}
9299
9300/// Setter for the number of added function symbols, not referenced by
9301/// any debug info, that have been filtered out.
9302///
9303/// @param n the new number of added function symbols, not referenced
9304/// by any debug info, that have been filtered out.
9305void
9307{priv_->num_added_func_syms_filtered_out = n;}
9308
9309/// Getter of the net number of added function symbols that are not
9310/// referenced by any debug info.
9311///
9312/// This is the difference between the total number of added
9313/// function symbols and the number of added function symbols that
9314/// have been filteted out. Both numbers are for symbols not
9315/// referenced by debug info.
9316///
9317/// return the net number of added function symbols that are not
9318/// referenced by any debug info.
9319size_t
9321{
9322 ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
9323 return num_func_syms_added()- num_added_func_syms_filtered_out();
9324}
9325
9326/// Getter for the number of variable symbols (not referenced by any
9327/// debug info) that got removed.
9328///
9329/// @return the number of variable symbols (not referenced by any
9330/// debug info) that got removed.
9331size_t
9333{return priv_->num_var_syms_removed;}
9334
9335/// Setter for the number of variable symbols (not referenced by any
9336/// debug info) that got removed.
9337///
9338/// @param n the number of variable symbols (not referenced by any
9339/// debug info) that got removed.
9340void
9342{priv_->num_var_syms_removed = n;}
9343
9344/// Getter for the number of removed variable symbols, not referenced
9345/// by any debug info, that have been filtered out.
9346///
9347/// @return the number of removed variable symbols, not referenced
9348/// by any debug info, that have been filtered out.
9349size_t
9351{
9352 if (priv_->ctxt()
9353 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
9354 return num_var_syms_removed();
9355 return priv_->num_removed_var_syms_filtered_out;
9356}
9357
9358/// Setter for the number of removed variable symbols, not referenced
9359/// by any debug info, that have been filtered out.
9360///
9361/// @param n the number of removed variable symbols, not referenced by
9362/// any debug info, that have been filtered out.
9363void
9365{priv_->num_removed_var_syms_filtered_out = n;}
9366
9367/// Getter of the net number of removed variable symbols that are not
9368/// referenced by any debug info.
9369///
9370/// This is the difference between the total number of removed
9371/// variable symbols and the number of removed variable symbols that
9372/// have been filteted out. Both numbers are for symbols not
9373/// referenced by debug info.
9374///
9375/// return the net number of removed variable symbols that are not
9376/// referenced by any debug info.
9377size_t
9379{
9380 ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
9381 return num_var_syms_removed() - num_removed_var_syms_filtered_out();
9382}
9383
9384/// Getter for the number of variable symbols (not referenced by any
9385/// debug info) that got added.
9386///
9387/// @return the number of variable symbols (not referenced by any
9388/// debug info) that got added.
9389size_t
9391{return priv_->num_var_syms_added;}
9392
9393/// Setter for the number of variable symbols (not referenced by any
9394/// debug info) that got added.
9395///
9396/// @param n the new number of variable symbols (not referenced by any
9397/// debug info) that got added.
9398void
9400{priv_->num_var_syms_added = n;}
9401
9402/// Getter for the number of added variable symbols, not referenced by
9403/// any debug info, that have been filtered out.
9404///
9405/// @return the number of added variable symbols, not referenced by
9406/// any debug info, that have been filtered out.
9407size_t
9409{
9410 if (priv_->ctxt()
9411 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9412 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9413 return num_var_syms_added();
9414 return priv_->num_added_var_syms_filtered_out;
9415}
9416
9417/// Setter for the number of added variable symbols, not referenced by
9418/// any debug info, that have been filtered out.
9419///
9420/// @param n the new number of added variable symbols, not referenced
9421/// by any debug info, that have been filtered out.
9422void
9424{priv_->num_added_var_syms_filtered_out = n;}
9425
9426/// Getter of the net number of added variable symbols that are not
9427/// referenced by any debug info.
9428///
9429/// This is the difference between the total number of added
9430/// variable symbols and the number of added variable symbols that
9431/// have been filteted out. Both numbers are for symbols not
9432/// referenced by debug info.
9433///
9434/// return the net number of added variable symbols that are not
9435/// referenced by any debug info.
9436size_t
9438{
9439 ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
9440 return num_var_syms_added() - num_added_var_syms_filtered_out();
9441}
9442
9443/// Getter of the number of leaf type change diff nodes.
9444///
9445/// @return the number of leaf type change diff nodes.
9446size_t
9448{return priv_->num_leaf_changes;}
9449
9450/// Setter of the number of leaf type change diff nodes.
9451///
9452/// @param n the new number of leaf type change diff nodes.
9453void
9455{priv_->num_leaf_changes = n;}
9456
9457/// Getter of the number of leaf type change diff nodes that have been
9458/// filtered out.
9459///
9460/// @return the number of leaf type change diff nodes that have been
9461size_t
9463{return priv_->num_leaf_changes_filtered_out;}
9464
9465/// Setter of the number of leaf type change diff nodes that have been
9466/// filtered out.
9467///
9468/// @param n the new number of leaf type change diff nodes that have
9469/// been filtered out.
9470void
9472{priv_->num_leaf_changes_filtered_out = n;}
9473
9474/// Getter of the net number of leaf change diff nodes.
9475///
9476/// This is the difference between the total number of leaf change
9477/// diff nodes, and the number of the leaf change diff nodes that have
9478/// been filtered out.
9479///
9480/// A leaf change is either a type change, a function change or a
9481/// variable change.
9482size_t
9484{
9485 ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
9486 return num_leaf_changes() - num_leaf_changes_filtered_out();
9487}
9488
9489/// Getter for the number of leaf type change diff nodes.
9490///
9491/// @return the number of leaf type changes diff nodes.
9492size_t
9494{return priv_->num_leaf_type_changes;}
9495
9496/// Setter for the number of leaf type change diff nodes.
9497///
9498/// @param n the new number of leaf type change diff nodes.
9499void
9501{priv_->num_leaf_type_changes = n;}
9502
9503/// Getter for the number of filtered out leaf type change diff nodes.
9504///
9505/// @return the number of filtered out leaf type change diff nodes.
9506size_t
9508{return priv_->num_leaf_type_changes_filtered_out;}
9509
9510/// Setter for the number of filtered out leaf type change diff nodes.
9511/// @param n the new number of filtered out leaf type change diff nodes.
9512void
9514{priv_->num_leaf_type_changes_filtered_out = n;}
9515
9516/// Getter for the net number of leaf type change diff nodes.
9517///
9518/// This is the difference between the number of leaf type changes and
9519/// the number of filtered out leaf type changes.
9520///
9521/// @return the net number of leaf type change diff nodes.
9522size_t
9524{return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
9525
9526/// Getter for the number of leaf function change diff nodes.
9527///
9528/// @return the number of leaf function change diff nodes.
9529size_t
9531{return priv_->num_leaf_func_changes;}
9532
9533/// Setter for the number of leaf function change diff nodes.
9534///
9535/// @param n the new number of leaf function change diff nodes.
9536void
9538{priv_->num_leaf_func_changes = n;}
9539
9540/// Getter for the number of leaf function diff nodes that carry
9541/// incompatible changes.
9542///
9543/// @return the number of leaf function diff nodes that carry
9544/// incompatible changes.
9545size_t
9547{return priv_->num_leaf_func_with_incompatible_changes;}
9548
9549/// Setter for the number of leaf function diff nodes that carry
9550/// incompatible changes.
9551///
9552/// @param n the new number of leaf function diff nodes that carry
9553/// incompatible changes.
9554void
9556{priv_->num_leaf_func_with_incompatible_changes = n;}
9557
9558/// Getter for the number of leaf function change diff nodes that were
9559/// filtered out.
9560///
9561/// @return the number of leaf function change diff nodes that were
9562/// filtered out.
9563size_t
9565{return priv_->num_leaf_func_changes_filtered_out;}
9566
9567/// Setter for the number of leaf function change diff nodes that were
9568/// filtered out.
9569///
9570/// @param n the new number of leaf function change diff nodes that
9571/// were filtered out.
9572void
9574{priv_->num_leaf_func_changes_filtered_out = n;}
9575
9576/// Getter for the net number of leaf function change diff nodes.
9577///
9578/// This is the difference between the number of leaf function change
9579/// diff nodes and the number of filtered out leaf function change
9580/// diff nodes.
9581///
9582/// @return the net number of leaf function change diff nodes.
9583size_t
9585{return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
9586
9587/// Getter for the net number of leaf function diff nodes that carry
9588/// changes that are NOT incompatible.
9589///
9590/// @return net number of leaf function diff nodes that carry changes
9591/// that are NOT incompatible.
9592size_t
9594{
9595 return (net_num_leaf_func_changes()
9596 - num_leaf_func_with_incompatible_changes());
9597}
9598
9599/// Getter for the number of leaf variable change diff nodes.
9600///
9601/// @return the number of leaf variable change diff nodes.
9602size_t
9604{return priv_->num_leaf_var_changes;}
9605
9606/// Setter for the number of leaf variable change diff nodes.
9607///
9608/// @param n the number of leaf variable change diff nodes.
9609void
9611{priv_->num_leaf_var_changes = n;}
9612
9613/// Getter for the number of leaf variable diff nodes that carry
9614/// incompatible changes.
9615///
9616/// @return the number of leaf variable diff nodes that carry
9617/// incompatible changes.
9618size_t
9620{return priv_->num_leaf_var_with_incompatible_changes;}
9621
9622/// Setter for the number of leaf variable diff nodes that carry
9623/// incompatible changes.
9624///
9625/// @param n the new number of leaf variable diff nodes that carry
9626/// incompatible changes.
9627void
9629{priv_->num_leaf_var_with_incompatible_changes = n;}
9630
9631/// Getter of the number of added types that are unreachable from the
9632/// public interface of the ABI corpus.
9633///
9634/// Public interface means the set of defined and publicly exported
9635/// functions and variables of the ABI corpus.
9636///
9637/// @return the number of added types that are unreachable from the
9638/// public interface of the ABI corpus.
9639size_t
9641{return priv_->num_added_unreachable_types;}
9642
9643/// Setter of the number of added types that are unreachable from the
9644/// public interface (global functions or variables) of the ABI
9645/// corpus.
9646///
9647/// Public interface means the set of defined and publicly exported
9648/// functions and variables of the ABI corpus.
9649///
9650/// @param n the new number of added types that are unreachable from
9651/// the public interface of the ABI corpus.
9652void
9654{priv_->num_added_unreachable_types = n;}
9655
9656/// Getter of the number of added types that are unreachable from
9657/// public interfaces and that are filtered out by suppression
9658/// specifications.
9659///
9660/// @return the number of added types that are unreachable from public
9661/// interfaces and that are filtered out by suppression
9662/// specifications.
9663size_t
9665{return priv_->num_added_unreachable_types_filtered_out;}
9666
9667/// Setter of the number of added types that are unreachable from
9668/// public interfaces and that are filtered out by suppression
9669/// specifications.
9670///
9671/// @param n the new number of added types that are unreachable from
9672/// public interfaces and that are filtered out by suppression
9673/// specifications.
9674void
9676{priv_->num_added_unreachable_types_filtered_out = n;}
9677
9678/// Getter of the number of added types that are unreachable from
9679/// public interfaces and that are *NOT* filtered out by suppression
9680/// specifications.
9681///
9682/// @return the number of added types that are unreachable from public
9683/// interfaces and that are *NOT* filtered out by suppression
9684/// specifications.
9685size_t
9687{
9688 ABG_ASSERT(num_added_unreachable_types()
9689 >=
9690 num_added_unreachable_types_filtered_out());
9691
9692 return (num_added_unreachable_types()
9693 -
9694 num_added_unreachable_types_filtered_out());
9695}
9696
9697/// Getter of the number of removed types that are unreachable from
9698/// the public interface of the ABI corpus.
9699///
9700/// Public interface means the set of defined and publicly exported
9701/// functions and variables of the ABI corpus.
9702///
9703/// @return the number of removed types that are unreachable from
9704/// the public interface of the ABI corpus.
9705size_t
9707{return priv_->num_removed_unreachable_types;}
9708
9709/// Setter of the number of removed types that are unreachable from
9710/// the public interface of the ABI corpus.
9711///
9712/// Public interface means the set of defined and publicly exported
9713/// functions and variables of the ABI corpus.
9714///
9715///@param n the new number of removed types that are unreachable from
9716/// the public interface of the ABI corpus.
9717void
9719{priv_->num_removed_unreachable_types = n;}
9720
9721/// Getter of the number of removed types that are not reachable from
9722/// public interfaces and that have been filtered out by suppression
9723/// specifications.
9724///
9725/// @return the number of removed types that are not reachable from
9726/// public interfaces and that have been filtered out by suppression
9727/// specifications.
9728size_t
9730{return priv_->num_removed_unreachable_types_filtered_out;}
9731
9732/// Setter of the number of removed types that are not reachable from
9733/// public interfaces and that have been filtered out by suppression
9734/// specifications.
9735///
9736/// @param n the new number of removed types that are not reachable
9737/// from public interfaces and that have been filtered out by
9738/// suppression specifications.
9739void
9741{priv_->num_removed_unreachable_types_filtered_out = n;}
9742
9743/// Getter of the number of removed types that are not reachable from
9744/// public interfaces and that have *NOT* been filtered out by
9745/// suppression specifications.
9746///
9747/// @return the number of removed types that are not reachable from
9748/// public interfaces and that have *NOT* been filtered out by
9749/// suppression specifications.
9750size_t
9752{
9753 ABG_ASSERT(num_removed_unreachable_types()
9754 >=
9755 num_removed_unreachable_types_filtered_out());
9756
9757 return (num_removed_unreachable_types()
9758 -
9759 num_removed_unreachable_types_filtered_out());
9760}
9761
9762/// Getter of the number of changed types that are unreachable from
9763/// the public interface of the ABI corpus.
9764///
9765/// Public interface means the set of defined and publicly exported
9766/// functions and variables of the ABI corpus.
9767///
9768/// @return the number of changed types that are unreachable from the
9769/// public interface of the ABI corpus.
9770size_t
9772{return priv_->num_changed_unreachable_types;}
9773
9774/// Setter of the number of changed types that are unreachable from
9775/// the public interface of the ABI corpus.
9776///
9777/// Public interface means the set of defined and publicly exported
9778/// functions and variables of the ABI corpus.
9779///
9780///@param n the new number of changed types that are unreachable from
9781/// the public interface of the ABI corpus.
9782void
9784{priv_->num_changed_unreachable_types = n;}
9785
9786/// Getter of the number of changed types that are unreachable from
9787/// public interfaces and that have been filtered out by suppression
9788/// specifications.
9789///
9790/// @return the number of changed types that are unreachable from
9791/// public interfaces and that have been filtered out by suppression
9792/// specifications.
9793size_t
9795{return priv_->num_changed_unreachable_types_filtered_out;}
9796
9797/// Setter of the number of changed types that are unreachable from
9798/// public interfaces and that have been filtered out by suppression
9799/// specifications.
9800///
9801/// @param n the new number of changed types that are unreachable from
9802/// public interfaces and that have been filtered out by suppression
9803/// specifications.
9804void
9806{priv_->num_changed_unreachable_types_filtered_out = n;}
9807
9808/// Getter of the number of changed types that are unreachable from
9809/// public interfaces and that have *NOT* been filtered out by
9810/// suppression specifications.
9811///
9812/// @return the number of changed types that are unreachable from
9813/// public interfaces and that have *NOT* been filtered out by
9814/// suppression specifications.
9815size_t
9817{
9818 ABG_ASSERT(num_changed_unreachable_types()
9819 >=
9820 num_changed_unreachable_types_filtered_out());
9821
9822 return (num_changed_unreachable_types()
9823 -
9824 num_changed_unreachable_types_filtered_out());
9825}
9826
9827/// Getter for the number of leaf variable changes diff nodes that
9828/// have been filtered out.
9829///
9830/// @return the number of leaf variable changes diff nodes that have
9831/// been filtered out.
9832size_t
9834{return priv_->num_leaf_var_changes_filtered_out;}
9835
9836/// Setter for the number of leaf variable changes diff nodes that
9837/// have been filtered out.
9838///
9839/// @param n the number of leaf variable changes diff nodes that have
9840/// been filtered out.
9841void
9843{priv_->num_leaf_var_changes_filtered_out = n;}
9844
9845/// Getter for the net number of leaf variable change diff nodes.
9846///
9847/// This the difference between the number of leaf variable change
9848/// diff nodes and the number of filtered out leaf variable change
9849/// diff nodes.
9850///
9851/// @return the net number of leaf variable change diff nodes.
9852size_t
9854{return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9855
9856/// Getter for the net number of leaf variable diff nodes that carry
9857/// changes that are NOT incompatible.
9858///
9859/// @return the net number of leaf variable diff nodes that carry
9860/// changes that are NOT incompatible.
9861size_t
9863{return net_num_leaf_var_changes() - num_leaf_var_with_incompatible_changes();}
9864// <corpus_diff stuff>
9865
9866/// Getter of the context associated with this corpus.
9867///
9868/// @return a smart pointer to the context associate with the corpus.
9871{return ctxt_.lock();}
9872
9873/// Tests if the lookup tables are empty.
9874///
9875/// @return true if the lookup tables are empty, false otherwise.
9876bool
9878{
9879 return (deleted_fns_.empty()
9880 && added_fns_.empty()
9881 && changed_fns_map_.empty()
9882 && deleted_vars_.empty()
9883 && added_vars_.empty()
9884 && changed_vars_map_.empty());
9885}
9886
9887/// Clear the lookup tables useful for reporting an enum_diff.
9888void
9890{
9891 deleted_fns_.clear();
9892 added_fns_.clear();
9893 changed_fns_map_.clear();
9894 deleted_vars_.clear();
9895 added_vars_.clear();
9896 changed_vars_map_.clear();
9897}
9898
9899/// If the lookup tables are not yet built, walk the differences and
9900/// fill the lookup tables.
9901void
9903{
9904 if (!lookup_tables_empty())
9905 return;
9906
9907 diff_context_sptr ctxt = get_context();
9908
9909 {
9910 edit_script& e = fns_edit_script_;
9911
9912 for (vector<deletion>::const_iterator it = e.deletions().begin();
9913 it != e.deletions().end();
9914 ++it)
9915 {
9916 unsigned i = it->index();
9917 ABG_ASSERT(i < first_->get_functions().size());
9918
9919 const function_decl* deleted_fn = first_->get_functions()[i];
9920 string n = get_function_id_or_pretty_representation(deleted_fn);
9921 ABG_ASSERT(!n.empty());
9922 // The below is commented out because there can be several
9923 // functions with the same ID in the corpus. So several
9924 // functions with the same ID can be deleted.
9925 // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9926 deleted_fns_[n] = deleted_fn;
9927 }
9928
9929 for (vector<insertion>::const_iterator it = e.insertions().begin();
9930 it != e.insertions().end();
9931 ++it)
9932 {
9933 for (vector<unsigned>::const_iterator iit =
9934 it->inserted_indexes().begin();
9935 iit != it->inserted_indexes().end();
9936 ++iit)
9937 {
9938 unsigned i = *iit;
9939 const function_decl* added_fn = second_->get_functions()[i];
9940 string n = get_function_id_or_pretty_representation(added_fn);
9941 ABG_ASSERT(!n.empty());
9942 // The below is commented out because there can be several
9943 // functions with the same ID in the corpus. So several
9944 // functions with the same ID can be added.
9945 // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9946 string_function_ptr_map::const_iterator j =
9947 deleted_fns_.find(n);
9948 if (j != deleted_fns_.end())
9949 {
9950 function_decl_sptr f(const_cast<function_decl*>(j->second),
9951 noop_deleter());
9952 function_decl_sptr s(const_cast<function_decl*>(added_fn),
9953 noop_deleter());
9954 function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9955 if (*j->second != *added_fn)
9956 changed_fns_map_[j->first] = d;
9957 deleted_fns_.erase(j);
9958 }
9959 else
9960 added_fns_[n] = added_fn;
9961 }
9962 }
9963 sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9964
9965 // Now walk the allegedly deleted functions; check if their
9966 // underlying symbols are deleted as well; otherwise, consider
9967 // that the function in question hasn't been deleted.
9968
9969 vector<string> to_delete;
9970 for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9971 i != deleted_fns_.end();
9972 ++i)
9973 if (second_->lookup_function_symbol(*i->second->get_symbol()))
9974 to_delete.push_back(i->first);
9975
9976 for (vector<string>::const_iterator i = to_delete.begin();
9977 i != to_delete.end();
9978 ++i)
9979 deleted_fns_.erase(*i);
9980
9981 // Do something similar for added functions.
9982
9983 to_delete.clear();
9984 for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9985 i != added_fns_.end();
9986 ++i)
9987 {
9988 if (first_->lookup_function_symbol(*i->second->get_symbol()))
9989 to_delete.push_back(i->first);
9990 else if (! i->second->get_symbol()->get_version().is_empty()
9991 && i->second->get_symbol()->get_version().is_default())
9992 // We are looking for a symbol that has a default version,
9993 // and which seems to be newly added. Let's see if the same
9994 // symbol with *no* version was already present in the
9995 // former corpus. If yes, then the symbol shouldn't be
9996 // considered as 'added'.
9997 {
9998 elf_symbol::version empty_version;
9999 if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
10000 empty_version))
10001 to_delete.push_back(i->first);
10002 }
10003 }
10004
10005 for (vector<string>::const_iterator i = to_delete.begin();
10006 i != to_delete.end();
10007 ++i)
10008 added_fns_.erase(*i);
10009 }
10010
10011 {
10012 edit_script& e = vars_edit_script_;
10013
10014 for (vector<deletion>::const_iterator it = e.deletions().begin();
10015 it != e.deletions().end();
10016 ++it)
10017 {
10018 unsigned i = it->index();
10019 ABG_ASSERT(i < first_->get_variables().size());
10020
10021 const var_decl_sptr deleted_var = first_->get_variables()[i];
10022 string n = deleted_var->get_id();
10023 ABG_ASSERT(!n.empty());
10024 // The below is commented out because there can be several
10025 // global variables with the same ID in the corpus. So
10026 // several global variables with the same ID can be deleted.
10027 //
10028 // In general these are static member variables. There can be
10029 // multiple instances of these (one per translation unit) that
10030 // appear to be different, but they are put into a COMDAT
10031 // section (with CLOOS ELF binding in modern toolchains) in
10032 // the end.
10033 //
10034 // In that case, let's keep track of the first global variable
10035 // removed and let's ignore the subsequent ones as they should
10036 // all be "merged" into one by the linker.
10037 //
10038 // ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
10039 string_var_ptr_map::const_iterator j = deleted_vars_.find(n);
10040 if (j != deleted_vars_.end())
10041 {
10042 ABG_ASSERT(is_member_decl(j->second)
10043 && get_member_is_static(j->second));
10044 continue;
10045 }
10046 else
10047 deleted_vars_[n] = deleted_var;
10048 }
10049
10050 for (vector<insertion>::const_iterator it = e.insertions().begin();
10051 it != e.insertions().end();
10052 ++it)
10053 {
10054 for (vector<unsigned>::const_iterator iit =
10055 it->inserted_indexes().begin();
10056 iit != it->inserted_indexes().end();
10057 ++iit)
10058 {
10059 unsigned i = *iit;
10060 const var_decl_sptr added_var = second_->get_variables()[i];
10061 string n = added_var->get_id();
10062 ABG_ASSERT(!n.empty());
10063 {
10064 string_var_ptr_map::const_iterator k = added_vars_.find(n);
10065 if ( k != added_vars_.end())
10066 {
10067 ABG_ASSERT(is_member_decl(k->second)
10068 && get_member_is_static(k->second));
10069 continue;
10070 }
10071 }
10072 string_var_ptr_map::const_iterator j =
10073 deleted_vars_.find(n);
10074 if (j != deleted_vars_.end())
10075 {
10076 if (*j->second != *added_var)
10077 {
10078 var_decl_sptr f = j->second;
10079 var_decl_sptr s = added_var;
10080 changed_vars_map_[n] = compute_diff(f, s, ctxt);
10081 }
10082 deleted_vars_.erase(j);
10083 }
10084 else
10085 added_vars_[n] = added_var;
10086 }
10087 }
10088 sort_string_var_diff_sptr_map(changed_vars_map_,
10089 sorted_changed_vars_);
10090
10091 // Now walk the allegedly deleted variables; check if their
10092 // underlying symbols are deleted as well; otherwise consider
10093 // that the variable in question hasn't been deleted.
10094
10095 vector<string> to_delete;
10096 for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
10097 i != deleted_vars_.end();
10098 ++i)
10099 if (second_->lookup_variable_symbol(*i->second->get_symbol()))
10100 to_delete.push_back(i->first);
10101
10102 for (vector<string>::const_iterator i = to_delete.begin();
10103 i != to_delete.end();
10104 ++i)
10105 deleted_vars_.erase(*i);
10106
10107 // Do something similar for added variables.
10108
10109 to_delete.clear();
10110 for (string_var_ptr_map::const_iterator i = added_vars_.begin();
10111 i != added_vars_.end();
10112 ++i)
10113 if (first_->lookup_variable_symbol(*i->second->get_symbol()))
10114 to_delete.push_back(i->first);
10115 else if (! i->second->get_symbol()->get_version().is_empty()
10116 && i->second->get_symbol()->get_version().is_default())
10117 // We are looking for a symbol that has a default version,
10118 // and which seems to be newly added. Let's see if the same
10119 // symbol with *no* version was already present in the
10120 // former corpus. If yes, then the symbol shouldn't be
10121 // considered as 'added'.
10122 {
10123 elf_symbol::version empty_version;
10124 if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
10125 empty_version))
10126 to_delete.push_back(i->first);
10127 }
10128
10129 for (vector<string>::const_iterator i = to_delete.begin();
10130 i != to_delete.end();
10131 ++i)
10132 added_vars_.erase(*i);
10133 }
10134
10135 // Massage the edit script for added/removed function symbols that
10136 // were not referenced by any debug info and turn them into maps of
10137 // {symbol_name, symbol}.
10138 {
10139 edit_script& e = unrefed_fn_syms_edit_script_;
10140 for (vector<deletion>::const_iterator it = e.deletions().begin();
10141 it != e.deletions().end();
10142 ++it)
10143 {
10144 unsigned i = it->index();
10145 ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
10146 elf_symbol_sptr deleted_sym =
10147 first_->get_unreferenced_function_symbols()[i];
10148 if (!second_->lookup_function_symbol(*deleted_sym))
10149 deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
10150 }
10151
10152 for (vector<insertion>::const_iterator it = e.insertions().begin();
10153 it != e.insertions().end();
10154 ++it)
10155 {
10156 for (vector<unsigned>::const_iterator iit =
10157 it->inserted_indexes().begin();
10158 iit != it->inserted_indexes().end();
10159 ++iit)
10160 {
10161 unsigned i = *iit;
10162 ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
10163 elf_symbol_sptr added_sym =
10164 second_->get_unreferenced_function_symbols()[i];
10165 if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
10166 == deleted_unrefed_fn_syms_.end()))
10167 {
10168 if (!first_->lookup_function_symbol(*added_sym))
10169 {
10170 bool do_add = true;
10171 if (! added_sym->get_version().is_empty()
10172 && added_sym->get_version().is_default())
10173 {
10174 // So added_seem has a default version. If
10175 // the former corpus had a symbol with the
10176 // same name as added_sym but with *no*
10177 // version, then added_sym shouldn't be
10178 // considered as a newly added symbol.
10179 elf_symbol::version empty_version;
10180 if (first_->lookup_function_symbol(added_sym->get_name(),
10181 empty_version))
10182 do_add = false;
10183 }
10184
10185 if (do_add)
10186 added_unrefed_fn_syms_[added_sym->get_id_string()] =
10187 added_sym;
10188 }
10189 }
10190 else
10191 deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
10192 }
10193 }
10194 }
10195
10196 // Massage the edit script for added/removed variable symbols that
10197 // were not referenced by any debug info and turn them into maps of
10198 // {symbol_name, symbol}.
10199 {
10200 edit_script& e = unrefed_var_syms_edit_script_;
10201 for (vector<deletion>::const_iterator it = e.deletions().begin();
10202 it != e.deletions().end();
10203 ++it)
10204 {
10205 unsigned i = it->index();
10206 ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
10207 elf_symbol_sptr deleted_sym =
10208 first_->get_unreferenced_variable_symbols()[i];
10209 if (!second_->lookup_variable_symbol(*deleted_sym))
10210 deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
10211 }
10212
10213 for (vector<insertion>::const_iterator it = e.insertions().begin();
10214 it != e.insertions().end();
10215 ++it)
10216 {
10217 for (vector<unsigned>::const_iterator iit =
10218 it->inserted_indexes().begin();
10219 iit != it->inserted_indexes().end();
10220 ++iit)
10221 {
10222 unsigned i = *iit;
10223 ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
10224 elf_symbol_sptr added_sym =
10225 second_->get_unreferenced_variable_symbols()[i];
10226 if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
10227 == deleted_unrefed_var_syms_.end())
10228 {
10229 if (!first_->lookup_variable_symbol(*added_sym))
10230 {
10231 bool do_add = true;
10232 if (! added_sym->get_version().is_empty()
10233 && added_sym->get_version().is_default())
10234 {
10235 // So added_seem has a default version. If
10236 // the former corpus had a symbol with the
10237 // same name as added_sym but with *no*
10238 // version, then added_sym shouldn't be
10239 // considered as a newly added symbol.
10240 elf_symbol::version empty_version;
10241 if (first_->lookup_variable_symbol(added_sym->get_name(),
10242 empty_version))
10243 do_add = false;
10244 }
10245
10246 if (do_add)
10247 added_unrefed_var_syms_[added_sym->get_id_string()] =
10248 added_sym;
10249 }
10250 }
10251 else
10252 deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
10253 }
10254 }
10255 }
10256
10257 // Handle the unreachable_types_edit_script_
10258 {
10259 edit_script& e = unreachable_types_edit_script_;
10260
10261 // Populate the map of deleted unreachable types from the
10262 // deletions of the edit script.
10263 for (vector<deletion>::const_iterator it = e.deletions().begin();
10264 it != e.deletions().end();
10265 ++it)
10266 {
10267 unsigned i = it->index();
10268 type_base_sptr t
10269 (first_->get_types_not_reachable_from_public_interfaces()[i]);
10270
10271 if (!is_user_defined_type(t))
10272 continue;
10273
10274 string repr =
10275 abigail::ir::get_pretty_representation(t, /*internal=*/false);
10276 deleted_unreachable_types_[repr] = t;
10277 }
10278
10279 // Populate the map of added and change unreachable types from the
10280 // insertions of the edit script.
10281 for (vector<insertion>::const_iterator it = e.insertions().begin();
10282 it != e.insertions().end();
10283 ++it)
10284 {
10285 for (vector<unsigned>::const_iterator iit =
10286 it->inserted_indexes().begin();
10287 iit != it->inserted_indexes().end();
10288 ++iit)
10289 {
10290 unsigned i = *iit;
10291 type_base_sptr t
10292 (second_->get_types_not_reachable_from_public_interfaces()[i]);
10293
10294 if (!is_user_defined_type(t))
10295 continue;
10296
10297 string repr =
10298 abigail::ir::get_pretty_representation(t, /*internal=*/false);
10299
10300 // Let's see if the inserted type we are looking at was
10301 // reported as deleted as well.
10302 //
10303 // If it's been deleted and a different version of it has
10304 // now been added, it means it's been *changed*. In that
10305 // case we'll compute the diff of that change and store it
10306 // in the map of changed unreachable types.
10307 //
10308 // Otherwise, it means the type's been added so we'll add
10309 // it to the set of added unreachable types.
10310
10311 string_type_base_sptr_map::const_iterator j =
10312 deleted_unreachable_types_.find(repr);
10313 if (j != deleted_unreachable_types_.end())
10314 {
10315 // So there was another type of the same pretty
10316 // representation which was reported as deleted.
10317 // Let's see if they are different or not ...
10318 decl_base_sptr old_type = is_decl(j->second);
10319 decl_base_sptr new_type = is_decl(t);
10320 if (old_type != new_type)
10321 {
10322 // The previously added type is different from this
10323 // one that is added. That means the initial type
10324 // was changed. Let's compute its diff and store it
10325 // as a changed type.
10326 diff_sptr d = compute_diff(old_type, new_type, ctxt);
10327 ABG_ASSERT(d->has_changes());
10328 changed_unreachable_types_[repr]= d;
10329 }
10330
10331 // In any case, the type was both deleted and added,
10332 // so we cannot have it marked as being deleted. So
10333 // let's remove it from the deleted types.
10334 deleted_unreachable_types_.erase(j);
10335 }
10336 else
10337 // The type wasn't previously reported as deleted, so
10338 // it's really added.
10339 added_unreachable_types_[repr] = t;
10340 }
10341 }
10342
10343 // Handle anonymous enums that got changed. An anonymous enum is
10344 // designated by its flat textual representation. So a change to
10345 // any of its enumerators results in a different enum. That is
10346 // represented by a deletion of the previous anonymous enum, and
10347 // the addition of a new one. For the user however, it's the same
10348 // enum that changed. Let's massage this "added/removed" pattern
10349 // to show what the user expects, namely, a changed anonymous
10350 // enum.
10351 {
10352 std::set<type_base_sptr> deleted_anon_types;
10353 std::set<type_base_sptr> added_anon_types;
10354
10355 for (auto entry : deleted_unreachable_types_)
10356 {
10357 if ((is_enum_type(entry.second)
10358 && is_enum_type(entry.second)->get_is_anonymous())
10359 || (is_class_or_union_type(entry.second)
10360 && is_class_or_union_type(entry.second)->get_is_anonymous()))
10361 deleted_anon_types.insert(entry.second);
10362 }
10363
10364
10365 for (auto entry : added_unreachable_types_)
10366 if ((is_enum_type(entry.second)
10367 && is_enum_type(entry.second)->get_is_anonymous())
10368 || (is_class_or_union_type(entry.second)
10369 && is_class_or_union_type(entry.second)->get_is_anonymous()))
10370 added_anon_types.insert(entry.second);
10371
10372 string_type_base_sptr_map added_anon_types_to_erase;
10373 string_type_base_sptr_map removed_anon_types_to_erase;
10374 enum_type_decl_sptr deleted_enum;
10375 class_or_union_sptr deleted_class;
10376
10377 // Look for deleted anonymous types (enums, unions, structs &
10378 // classes) which have enumerators or data members present in an
10379 // added anonymous type ...
10380 for (auto deleted: deleted_anon_types)
10381 {
10382 deleted_enum = is_enum_type(deleted);
10383 deleted_class = is_class_or_union_type(deleted);
10384
10385 // For enums, look for any enumerator of 'deleted_enum' that
10386 // is also present in an added anonymous enum.
10387 if (deleted_enum)
10388 {
10389 for (auto enr : deleted_enum->get_enumerators())
10390 {
10391 bool this_enum_got_changed = false;
10392 for (auto t : added_anon_types)
10393 {
10394 if (enum_type_decl_sptr added_enum = is_enum_type(t))
10395 if (is_enumerator_present_in_enum(enr, *added_enum))
10396 {
10397 // So the enumerator 'enr' from the
10398 // 'deleted_enum' enum is also present in the
10399 // 'added_enum' enum so we assume that
10400 // 'deleted_enum' and 'added_enum' are the same
10401 // enum that got changed. Let's represent it
10402 // using a diff node.
10403 diff_sptr d = compute_diff(deleted_enum,
10404 added_enum, ctxt);
10405 ABG_ASSERT(d->has_changes());
10406 string repr =
10408 /*internal=*/false);
10409 changed_unreachable_types_[repr]= d;
10410 this_enum_got_changed = true;
10411 string r1 =
10413 /*internal=*/false);
10414 string r2 =
10416 /*internal=*/false);
10417 removed_anon_types_to_erase[r1] = deleted_enum;
10418 added_anon_types_to_erase[r2] = added_enum;
10419 break;
10420 }
10421 }
10422 if (this_enum_got_changed)
10423 break;
10424 }
10425 }
10426 else if (deleted_class)
10427 {
10428 // For unions, structs & classes, look for any data
10429 // member of 'deleted_class' that is also present in an
10430 // added anonymous class.
10431 for (auto dm : deleted_class->get_data_members())
10432 {
10433 bool this_class_got_changed = false;
10434 for (auto klass : added_anon_types)
10435 {
10436 if (class_or_union_sptr added_class =
10438 if (class_or_union_types_of_same_kind(deleted_class,
10439 added_class)
10440 && lookup_data_member(added_class, dm))
10441 {
10442 // So the data member 'dm' from the
10443 // 'deleted_class' class is also present in
10444 // the 'added_class' class so we assume that
10445 // 'deleted_class' and 'added_class' are the
10446 // same anonymous class that got changed.
10447 // Let's represent it using a diff node.
10448 diff_sptr d = compute_diff(is_type(deleted_class),
10449 is_type(added_class),
10450 ctxt);
10451 ABG_ASSERT(d->has_changes());
10452 string repr =
10454 /*internal=*/false);
10455 changed_unreachable_types_[repr]= d;
10456 this_class_got_changed = true;
10457 string r1 =
10459 /*internal=*/false);
10460 string r2 =
10462 /*internal=*/false);
10463 removed_anon_types_to_erase[r1] = deleted_class;
10464 added_anon_types_to_erase[r2] = added_class;
10465 break;
10466 }
10467 }
10468 if (this_class_got_changed)
10469 break;
10470 }
10471 }
10472 }
10473
10474 // Now remove the added/removed anonymous types from their maps,
10475 // as they are now represented as a changed type, not an added
10476 // and removed anonymous type.
10477 for (auto entry : added_anon_types_to_erase)
10478 added_unreachable_types_.erase(entry.first);
10479
10480 for (auto entry : removed_anon_types_to_erase)
10481 deleted_unreachable_types_.erase(entry.first);
10482 }
10483 }
10484}
10485
10486/// Test if a change reports about a given @ref function_decl that is
10487/// changed in a certain way is suppressed by a given suppression
10488/// specifiation
10489///
10490/// @param fn the @ref function_decl to consider.
10491///
10492/// @param suppr the suppression specification to consider.
10493///
10494/// @param k the kind of change that happened to @p fn.
10495///
10496/// @param ctxt the context of the current diff.
10497///
10498/// @return true iff the suppression specification @p suppr suppresses
10499/// change reports about function @p fn, if that function changes in
10500/// the way expressed by @p k.
10501static bool
10502function_is_suppressed(const function_decl* fn,
10503 const suppression_sptr suppr,
10505 const diff_context_sptr ctxt)
10506{
10508 if (!fn_suppr)
10509 return false;
10510 return fn_suppr->suppresses_function(fn, k, ctxt);
10511}
10512
10513/// Test if a change reports about a given @ref var_decl that is
10514/// changed in a certain way is suppressed by a given suppression
10515/// specifiation
10516///
10517/// @param fn the @ref var_decl to consider.
10518///
10519/// @param suppr the suppression specification to consider.
10520///
10521/// @param k the kind of change that happened to @p fn.
10522///
10523/// @param ctxt the context of the current diff.
10524///
10525/// @return true iff the suppression specification @p suppr suppresses
10526/// change reports about variable @p fn, if that variable changes in
10527/// the way expressed by @p k.
10528static bool
10529variable_is_suppressed(const var_decl_sptr& var,
10530 const suppression_sptr suppr,
10532 const diff_context_sptr ctxt)
10533{
10535 if (!var_suppr)
10536 return false;
10537 return var_suppr->suppresses_variable(var, k, ctxt);
10538}
10539
10540/// Apply suppression specifications for this corpus diff to the set
10541/// of added/removed functions/variables, as well as to types not
10542/// reachable from global functions/variables.
10543void
10545{
10546 diff_context_sptr ctxt = get_context();
10547
10548 const suppressions_type& suppressions = ctxt->suppressions();
10549 for (suppressions_type::const_iterator i = suppressions.begin();
10550 i != suppressions.end();
10551 ++i)
10552 {
10553 // Added/Deleted functions.
10555 {
10556 // Added functions
10557 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10558 e != added_fns_.end();
10559 ++e)
10560 if (function_is_suppressed(e->second, fn_suppr,
10562 ctxt))
10563 suppressed_added_fns_[e->first] = e->second;
10564
10565 // Deleted functions.
10566 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10567 e != deleted_fns_.end();
10568 ++e)
10569 if (function_is_suppressed(e->second, fn_suppr,
10571 ctxt))
10572 suppressed_deleted_fns_[e->first] = e->second;
10573
10574 // Added function symbols not referenced by any debug info
10575 for (string_elf_symbol_map::const_iterator e =
10576 added_unrefed_fn_syms_.begin();
10577 e != added_unrefed_fn_syms_.end();
10578 ++e)
10579 if (fn_suppr->suppresses_function_symbol(e->second,
10581 ctxt))
10582 suppressed_added_unrefed_fn_syms_[e->first] = e->second;
10583
10584 // Removed function symbols not referenced by any debug info
10585 for (string_elf_symbol_map::const_iterator e =
10586 deleted_unrefed_fn_syms_.begin();
10587 e != deleted_unrefed_fn_syms_.end();
10588 ++e)
10589 if (fn_suppr->suppresses_function_symbol(e->second,
10591 ctxt))
10592 suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
10593 }
10594 // Added/Delete virtual member functions changes that might be
10595 // suppressed by a type_suppression that matches the enclosing
10596 // class of the virtual member function.
10597 else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
10598 {
10599 // Added virtual functions
10600 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10601 e != added_fns_.end();
10602 ++e)
10603 if (is_member_function(e->second)
10604 && get_member_function_is_virtual(e->second))
10605 {
10606 const function_decl *f = e->second;
10607 class_decl_sptr c =
10608 is_class_type(is_method_type(f->get_type())->get_class_type());
10609 ABG_ASSERT(c);
10610 if (type_suppr->suppresses_type(c, ctxt))
10611 suppressed_added_fns_[e->first] = e->second;
10612 }
10613 // Deleted virtual functions
10614 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10615 e != deleted_fns_.end();
10616 ++e)
10617 if (is_member_function(e->second)
10618 && get_member_function_is_virtual(e->second))
10619 {
10620 const function_decl *f = e->second;
10621 class_decl_sptr c =
10622 is_class_type(is_method_type(f->get_type())->get_class_type());
10623 ABG_ASSERT(c);
10624 if (type_suppr->suppresses_type(c, ctxt))
10625 suppressed_deleted_fns_[e->first] = e->second;
10626 }
10627
10628 // Apply this type suppression to deleted types
10629 // non-reachable from a public interface.
10630 for (string_type_base_sptr_map::const_iterator e =
10631 deleted_unreachable_types_.begin();
10632 e != deleted_unreachable_types_.end();
10633 ++e)
10634 if (type_suppr->suppresses_type(e->second, ctxt))
10635 suppressed_deleted_unreachable_types_[e->first] = e->second;
10636
10637 // Apply this type suppression to added types
10638 // non-reachable from a public interface.
10639 for (string_type_base_sptr_map::const_iterator e =
10640 added_unreachable_types_.begin();
10641 e != added_unreachable_types_.end();
10642 ++e)
10643 if (type_suppr->suppresses_type(e->second, ctxt))
10644 suppressed_added_unreachable_types_[e->first] = e->second;
10645 }
10646 // Added/Deleted variables
10647 else if (variable_suppression_sptr var_suppr =
10649 {
10650 // Added variables
10651 for (string_var_ptr_map::const_iterator e = added_vars_.begin();
10652 e != added_vars_.end();
10653 ++e)
10654 if (variable_is_suppressed(e->second, var_suppr,
10656 ctxt))
10657 suppressed_added_vars_[e->first] = e->second;
10658
10659 //Deleted variables
10660 for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
10661 e != deleted_vars_.end();
10662 ++e)
10663 if (variable_is_suppressed(e->second, var_suppr,
10665 ctxt))
10666 suppressed_deleted_vars_[e->first] = e->second;
10667
10668 // Added variable symbols not referenced by any debug info
10669 for (string_elf_symbol_map::const_iterator e =
10670 added_unrefed_var_syms_.begin();
10671 e != added_unrefed_var_syms_.end();
10672 ++e)
10673 if (var_suppr->suppresses_variable_symbol(e->second,
10675 ctxt))
10676 suppressed_added_unrefed_var_syms_[e->first] = e->second;
10677
10678 // Removed variable symbols not referenced by any debug info
10679 for (string_elf_symbol_map::const_iterator e =
10680 deleted_unrefed_var_syms_.begin();
10681 e != deleted_unrefed_var_syms_.end();
10682 ++e)
10683 if (var_suppr->suppresses_variable_symbol(e->second,
10685 ctxt))
10686 suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
10687 }
10688 }
10689}
10690
10691/// Test if the change reports for a given deleted function have
10692/// been deleted.
10693///
10694/// @param fn the function to consider.
10695///
10696/// @return true iff the change reports for a give given deleted
10697/// function have been deleted.
10698bool
10700{
10701 if (!fn)
10702 return false;
10703
10704 string_function_ptr_map::const_iterator i =
10705 suppressed_deleted_fns_.find(fn->get_id());
10706
10707 return (i != suppressed_deleted_fns_.end());
10708}
10709
10710/// Test if an added type that is unreachable from public interface
10711/// has been suppressed by a suppression specification.
10712///
10713/// @param t the added unreachable type to be considered.
10714///
10715/// @return true iff @p t has been suppressed by a suppression
10716/// specification.
10717bool
10719{
10720 if (!t)
10721 return false;
10722
10723 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10724 string_type_base_sptr_map::const_iterator i =
10725 suppressed_added_unreachable_types_.find(repr);
10726 if (i == suppressed_added_unreachable_types_.end())
10727 return false;
10728
10729 return true;
10730}
10731
10732/// Test if a deleted type that is unreachable from public interface
10733/// has been suppressed by a suppression specification.
10734///
10735/// @param t the deleted unreachable type to be considered.
10736///
10737/// @return true iff @p t has been suppressed by a suppression
10738/// specification.
10739bool
10741{
10742 if (!t)
10743 return false;
10744
10745 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10746 string_type_base_sptr_map::const_iterator i =
10747 suppressed_deleted_unreachable_types_.find(repr);
10748 if (i == suppressed_deleted_unreachable_types_.end())
10749 return false;
10750
10751 return true;
10752}
10753
10754/// Test if the change reports for a give given added function has
10755/// been deleted.
10756///
10757/// @param fn the function to consider.
10758///
10759/// @return true iff the change reports for a give given added
10760/// function has been deleted.
10761bool
10763{
10764 if (!fn)
10765 return false;
10766
10767 string_function_ptr_map::const_iterator i =
10768 suppressed_added_fns_.find(fn->get_id());
10769
10770 return (i != suppressed_added_fns_.end());
10771}
10772
10773/// Test if the change reports for a give given deleted variable has
10774/// been deleted.
10775///
10776/// @param var the variable to consider.
10777///
10778/// @return true iff the change reports for a give given deleted
10779/// variable has been deleted.
10780bool
10782{
10783 if (!var)
10784 return false;
10785
10786 string_var_ptr_map::const_iterator i =
10787 suppressed_deleted_vars_.find(var->get_id());
10788
10789 return (i != suppressed_deleted_vars_.end());
10790}
10791
10792/// Test if the change reports for a given added variable have been
10793/// suppressed.
10794///
10795/// @param var the variable to consider.
10796///
10797/// @return true iff the change reports for a given deleted
10798/// variable has been deleted.
10799bool
10801{
10802 if (!var)
10803 return false;
10804
10805 string_var_ptr_map::const_iterator i =
10806 suppressed_added_vars_.find(var->get_id());
10807
10808 return (i != suppressed_added_vars_.end());
10809}
10810
10811/// Test if the change reports for a given deleted function symbol
10812/// (that is not referenced by any debug info) has been suppressed.
10813///
10814/// @param var the function to consider.
10815///
10816/// @return true iff the change reports for a given deleted function
10817/// symbol has been suppressed.
10818bool
10820{
10821 if (!s)
10822 return false;
10823
10824 string_elf_symbol_map::const_iterator i =
10825 suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10826
10827 return (i != suppressed_deleted_unrefed_fn_syms_.end());
10828}
10829
10830/// Test if the change reports for a given added function symbol
10831/// (that is not referenced by any debug info) has been suppressed.
10832///
10833/// @param var the function to consider.
10834///
10835/// @return true iff the change reports for a given added function
10836/// symbol has been suppressed.
10837bool
10839{
10840 if (!s)
10841 return false;
10842
10843 string_elf_symbol_map::const_iterator i =
10844 suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10845
10846 return (i != suppressed_added_unrefed_fn_syms_.end());
10847}
10848
10849/// Test if the change reports for a given deleted variable symbol
10850/// (that is not referenced by any debug info) has been suppressed.
10851///
10852/// @param var the variable to consider.
10853///
10854/// @return true iff the change reports for a given deleted variable
10855/// symbol has been suppressed.
10856bool
10858{
10859 if (!s)
10860 return false;
10861
10862 string_elf_symbol_map::const_iterator i =
10863 suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10864
10865 return (i != suppressed_deleted_unrefed_var_syms_.end());
10866}
10867
10868/// Test if the change reports for a given added variable symbol
10869/// (that is not referenced by any debug info) has been suppressed.
10870///
10871/// @param var the variable to consider.
10872///
10873/// @return true iff the change reports for a given added variable
10874/// symbol has been suppressed.
10875bool
10877{
10878 if (!s)
10879 return false;
10880
10881 string_elf_symbol_map::const_iterator i =
10882 suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10883
10884 return (i != suppressed_added_unrefed_var_syms_.end());
10885}
10886
10887#ifdef do_count_diff_map_changes
10888#undef do_count_diff_map_changes
10889#endif
10890#define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10891 { \
10892 string_diff_ptr_map::const_iterator i; \
10893 for (i = diff_map.begin(); \
10894 i != diff_map.end(); \
10895 ++i) \
10896 { \
10897 if (const var_diff* d = is_var_diff(i->second)) \
10898 if (is_data_member(d->first_var())) \
10899 continue; \
10900 \
10901 if (i->second->has_local_changes()) \
10902 ++n_changes; \
10903 if (!i->second->get_canonical_diff()->to_be_reported()) \
10904 ++n_filtered; \
10905 } \
10906 }
10907
10908/// Count the number of leaf changes as well as the number of the
10909/// changes that have been filtered out.
10910///
10911/// @param num_changes out parameter. This is set to the total number
10912/// of leaf changes.
10913///
10914/// @param num_filtered out parameter. This is set to the number of
10915/// leaf changes that have been filtered out.
10916void
10917corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10918{
10919 count_leaf_type_changes(num_changes, num_filtered);
10920
10921 // Now count the non-type changes.
10922 do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10923 num_changes, num_filtered);
10924 do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10925 num_changes, num_filtered);
10926}
10927
10928/// Count the number of leaf *type* changes as well as the number of
10929/// the leaf type changes that have been filtered out.
10930///
10931/// @param num_changes out parameter. This is set to the total number
10932/// of leaf type changes.
10933///
10934/// @param num_filtered out parameter. This is set to the number of
10935/// leaf type changes that have been filtered out.
10936void
10938 size_t &num_filtered)
10939{
10940 do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10941 num_changes, num_filtered);
10942 do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10943 num_changes, num_filtered);
10944 do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10945 num_changes, num_filtered);
10946 do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10947 num_changes, num_filtered);
10948 do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10949 num_changes, num_filtered);
10950 do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10951 num_changes, num_filtered);
10952 do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10953 num_changes, num_filtered);
10954 do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10955 num_changes, num_filtered);
10956 do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10957 num_changes, num_filtered);
10958}
10959
10960/// Count the number of types not reachable from the interface (i.e,
10961/// not reachable from global functions or variables).
10962///
10963/// @param num_added this is set to the number of added types not
10964/// reachable from the interface.
10965///
10966/// @param num_deleted this is set to the number of deleted types not
10967/// reachable from the interface.
10968///
10969/// @param num_changed this is set to the number of changed types not
10970/// reachable from the interface.
10971///
10972/// @param num_filtered_added this is set to the number of added types
10973/// not reachable from the interface and that have been filtered out
10974/// by suppression specifications.
10975///
10976/// @param num_filtered_deleted this is set to the number of deleted
10977/// types not reachable from the interface and that have been filtered
10978/// out by suppression specifications.
10979///
10980/// @param num_filtered_changed this is set to the number of changed
10981/// types not reachable from the interface and that have been filtered
10982/// out by suppression specifications.
10983void
10985 size_t &num_deleted,
10986 size_t &num_changed,
10987 size_t &num_filtered_added,
10988 size_t &num_filtered_deleted,
10989 size_t &num_filtered_changed)
10990{
10991 num_added = added_unreachable_types_.size();
10992 num_deleted = deleted_unreachable_types_.size();
10993 num_changed = changed_unreachable_types_.size();
10994 num_filtered_added = suppressed_added_unreachable_types_.size();
10995 num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10996
10997 for (vector<diff_sptr>::const_iterator i =
11000 ++i)
11001 if (!(*i)->to_be_reported())
11002 ++num_filtered_changed;
11003}
11004
11005/// Get the map of diff nodes representing changed unreachable types.
11006///
11007/// @return the map of diff nodes representing changed unreachable
11008/// types.
11011{return changed_unreachable_types_;}
11012
11013/// Get the sorted vector of diff nodes representing changed
11014/// unreachable types.
11015///
11016/// Upon the first invocation of this method, if the vector is empty,
11017/// this function gets the diff nodes representing changed
11018/// unreachable, sort them, and return the sorted vector.
11019///
11020/// @return the sorted vector of diff nodes representing changed
11021/// unreachable types.
11022const vector<diff_sptr>&
11024{
11025if (changed_unreachable_types_sorted_.empty())
11026 if (!changed_unreachable_types_.empty())
11027 sort_string_diff_sptr_map(changed_unreachable_types_,
11028 changed_unreachable_types_sorted_);
11029
11030 return changed_unreachable_types_sorted_;
11031}
11032
11033/// Compute the diff stats.
11034///
11035/// To know the number of functions that got filtered out, this
11036/// function applies the categorizing filters to the diff sub-trees of
11037/// each function changes diff, prior to calculating the stats.
11038///
11039/// @param num_removed the number of removed functions.
11040///
11041/// @param num_added the number of added functions.
11042///
11043/// @param num_changed the number of changed functions.
11044///
11045/// @param num_filtered_out the number of changed functions that are
11046/// got filtered out from the report
11047void
11049{
11050 stat.num_func_removed(deleted_fns_.size());
11051 stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
11052 stat.num_func_added(added_fns_.size());
11053 stat.num_added_func_filtered_out(suppressed_added_fns_.size());
11054 stat.num_func_changed(changed_fns_map_.size());
11055
11056 stat.num_vars_removed(deleted_vars_.size());
11057 stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
11058 stat.num_vars_added(added_vars_.size());
11059 stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
11060 stat.num_vars_changed(changed_vars_map_.size());
11061
11062 diff_context_sptr ctxt = get_context();
11063
11065 if (ctxt->perform_change_categorization())
11066 {
11067 if (get_context()->do_log())
11068 {
11069 std::cerr << "in apply_filters_and_compute_diff_stats:"
11070 << "applying filters to "
11071 << changed_fns_.size()
11072 << " changed fns ...\n";
11073 t.start();
11074 }
11075 // Walk the changed function diff nodes to apply the categorization
11076 // filters.
11078 for (function_decl_diff_sptrs_type::const_iterator i =
11079 changed_fns_.begin();
11080 i != changed_fns_.end();
11081 ++i)
11082 {
11083 diff_sptr diff = *i;
11084 ctxt->maybe_apply_filters(diff);
11085 }
11086
11087 if (get_context()->do_log())
11088 {
11089 t.stop();
11090 std::cerr << "in apply_filters_and_compute_diff_stats:"
11091 << "filters to changed fn applied!:" << t << "\n";
11092
11093 std::cerr << "in apply_filters_and_compute_diff_stats:"
11094 << "applying filters to "
11095 << sorted_changed_vars_.size()
11096 << " changed vars ...\n";
11097 t.start();
11098 }
11099
11100 // Walk the changed variable diff nodes to apply the categorization
11101 // filters.
11102 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11103 i != sorted_changed_vars_.end();
11104 ++i)
11105 {
11106 diff_sptr diff = *i;
11107 ctxt->maybe_apply_filters(diff);
11108 }
11109
11110 if (get_context()->do_log())
11111 {
11112 t.stop();
11113 std::cerr << "in apply_filters_and_compute_diff_stats:"
11114 << "filters to changed vars applied!:" << t << "\n";
11115
11116 std::cerr << "in apply_filters_and_compute_diff_stats:"
11117 << "applying filters to unreachable types ...\n";
11118 t.start();
11119 }
11120
11121 // walk the changed unreachable types to apply categorization
11122 // filters
11124 ctxt->maybe_apply_filters(diff);
11125
11126 for (auto& entry : changed_unreachable_types())
11127 ctxt->maybe_apply_filters(entry.second);
11128
11129 if (get_context()->do_log())
11130 {
11131 t.stop();
11132 std::cerr << "in apply_filters_and_compute_diff_stats:"
11133 << "filters to unreachable types applied!:" << t << "\n";
11134
11135 std::cerr << "in apply_filters_and_compute_diff_stats:"
11136 << "categorizing redundant changed sub nodes ...\n";
11137 t.start();
11138 }
11139
11140 categorize_redundant_changed_sub_nodes();
11141
11142 if (get_context()->do_log())
11143 {
11144 t.stop();
11145 std::cerr << "in apply_filters_and_compute_diff_stats:"
11146 << "redundant changed sub nodes categorized!:" << t << "\n";
11147
11148 std::cerr << "in apply_filters_and_compute_diff_stats:"
11149 << "count changed fns ...\n";
11150 t.start();
11151 }
11152 }
11153
11154 // Walk the changed function diff nodes to count the number of
11155 // filtered-out functions and the number of functions with virtual
11156 // offset changes.
11157 for (function_decl_diff_sptrs_type::const_iterator i =
11158 changed_fns_.begin();
11159 i != changed_fns_.end();
11160 ++i)
11161 {
11162 bool incompatible_change = false;
11163 if ((*i)->is_filtered_out())
11164 {
11166 (stat.num_changed_func_filtered_out() + 1);
11167
11168 if ((*i)->has_local_changes())
11171 }
11172
11173 // Now let's detect functions with incompatible changes.
11174 if (!(*i)->is_categorized_as_suppressed())
11175 {
11176 // Note that a filtered-out function diff (because of
11177 // redundancy) can still carry an incompatible change. In
11178 // that case, the diff will later be removed from the
11179 // account of filtered diff nodes.
11180 //
11181 // Also note that such a filtered-out function was *NOT*
11182 // suppressed by a user-provided suppression specification.
11183
11185 {
11188 incompatible_change = true;
11189 }
11190
11191 // Are any of the local changes of the function_diff harmful?
11192 // If yes, then set stat.num_func_with_local_harmful_changes()
11193 // and stat.num_var_with_local_harmful_changes().
11195 {
11198 incompatible_change = true;
11199 }
11200 }
11201
11202 if ((*i)->has_local_changes())
11204 (stat.num_leaf_func_changes() + 1);
11205
11206 if (incompatible_change)
11207 {
11208 incompatible_changed_fns_.push_back(*i);
11211
11212 if ((*i)->has_local_changes())
11213 // The function is a leaf node.
11216
11217 if ((*i)->is_filtered_out())
11218 {
11219 // If the incompatible change was filtered-out (possibly
11220 // b/c of redundancy) consider it as not being filtered
11221 // out anymore.
11223 (stat.num_changed_func_filtered_out() - 1);
11224
11225 if ((*i)->has_local_changes())
11228 }
11229 }
11230 }
11231
11232 if (get_context()->do_log())
11233 {
11234 t.stop();
11235 std::cerr << "in apply_filters_and_compute_diff_stats:"
11236 << "changed fn counted!:" << t << "\n";
11237
11238 std::cerr << "in apply_filters_and_compute_diff_stats:"
11239 << "count changed vars ...\n";
11240 t.start();
11241 }
11242
11243 // Similarly to function diff nodes above, walk the changed
11244 // variables diff nodes to count the number of filtered-out,
11245 // suppressed and incompatible variable diff nodes.
11246 for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
11247 i != sorted_changed_vars_.end();
11248 ++i)
11249 {
11250 bool incompatible_change = false;
11251 if ((*i)->is_filtered_out())
11252 {
11254 (stat.num_changed_vars_filtered_out() + 1);
11255
11256 if ((*i)->has_local_changes())
11259 }
11260
11261 if (!(*i)->is_categorized_as_suppressed())
11262 {
11264 {
11265 incompatible_change = true;
11266 incompatible_changed_vars_.push_back(*i);
11271
11272 if ((*i)->is_filtered_out())
11273 {
11275 (stat.num_changed_vars_filtered_out() - 1);
11276
11277 if ((*i)->has_local_changes())
11280 }
11281 }
11282 }
11283
11284 if ((*i)->has_local_changes())
11285 {
11287 (stat.num_leaf_var_changes() + 1);
11288
11289 if (incompatible_change)
11292 }
11293 }
11294
11295 if (get_context()->do_log())
11296 {
11297 t.stop();
11298 std::cerr << "in apply_filters_and_compute_diff_stats:"
11299 << "changed vars counted!:" << t << "\n";
11300
11301 std::cerr << "in apply_filters_and_compute_diff_stats:"
11302 << "count leaf changed types ...\n";
11303 t.start();
11304 }
11305
11306 stat.num_func_syms_added(added_unrefed_fn_syms_.size());
11307 stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
11308 stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
11309 stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
11310 stat.num_var_syms_added(added_unrefed_var_syms_.size());
11311 stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
11312 stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
11313 stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
11314
11315 // Walk the general leaf type diff nodes to count them
11316 {
11317 size_t num_type_changes = 0, num_type_filtered = 0;
11318 count_leaf_type_changes(num_type_changes, num_type_filtered);
11319
11320 stat.num_leaf_type_changes(num_type_changes);
11321 stat.num_leaf_type_changes_filtered_out(num_type_filtered);
11322 }
11323
11324 if (get_context()->do_log())
11325 {
11326 t.stop();
11327 std::cerr << "in apply_filters_and_compute_diff_stats:"
11328 << "changed leaf types counted!:" << t << "\n";
11329
11330 std::cerr << "in apply_filters_and_compute_diff_stats:"
11331 << "count leaf changed artefacts ...\n";
11332 t.start();
11333 }
11334
11335 // Walk the general leaf artefacts diff nodes to count them
11336 {
11337 size_t num_changes = 0, num_filtered = 0;
11338 count_leaf_changes(num_changes, num_filtered);
11339
11340 stat.num_leaf_changes(num_changes);
11341 stat.num_leaf_changes_filtered_out(num_filtered);
11342 }
11343
11344 if (get_context()->do_log())
11345 {
11346 t.stop();
11347 std::cerr << "in apply_filters_and_compute_diff_stats:"
11348 << "changed leaf artefacts counted!:" << t << "\n";
11349
11350 std::cerr << "in apply_filters_and_compute_diff_stats:"
11351 << "count unreachable types ...\n";
11352 t.start();
11353 }
11354
11355 // Walk the unreachable types to count them
11356 {
11357 size_t num_added_unreachable_types = 0,
11358 num_changed_unreachable_types = 0,
11359 num_deleted_unreachable_types = 0,
11360 num_added_unreachable_types_filtered = 0,
11361 num_changed_unreachable_types_filtered = 0,
11362 num_deleted_unreachable_types_filtered = 0;
11363
11364 count_unreachable_types(num_added_unreachable_types,
11365 num_deleted_unreachable_types,
11366 num_changed_unreachable_types,
11367 num_added_unreachable_types_filtered,
11368 num_deleted_unreachable_types_filtered,
11369 num_changed_unreachable_types_filtered);
11370
11371 if (get_context()->do_log())
11372 {
11373 t.stop();
11374 std::cerr << "in apply_filters_and_compute_diff_stats:"
11375 << "unreachable types counted!:" << t << "\n";
11376 }
11377
11378 stat.num_added_unreachable_types(num_added_unreachable_types);
11379 stat.num_removed_unreachable_types(num_deleted_unreachable_types);
11380 stat.num_changed_unreachable_types(num_changed_unreachable_types);
11382 (num_added_unreachable_types_filtered);
11384 (num_deleted_unreachable_types_filtered);
11386 (num_changed_unreachable_types_filtered);
11387 }
11388}
11389
11390/// Emit the summary of the functions & variables that got
11391/// removed/changed/added.
11392///
11393/// TODO: This should be handled by the reporters, just like what is
11394/// done for reporter_base::diff_to_be_reported.
11395///
11396/// @param out the output stream to emit the stats to.
11397///
11398/// @param indent the indentation string to use in the summary.
11399void
11401 ostream& out,
11402 const string& indent)
11403{
11404 /// Report added/removed/changed functions.
11405 size_t net_num_leaf_changes =
11407 s.net_num_func_added() +
11410 s.net_num_vars_added() +
11417
11418 if (!sonames_equal_)
11419 out << indent << "ELF SONAME changed\n";
11420
11421 if (!architectures_equal_)
11422 out << indent << "ELF architecture changed\n";
11423
11424 diff_context_sptr ctxt = get_context();
11425
11426 if (ctxt->show_leaf_changes_only())
11427 {
11428 out << "Leaf changes summary: ";
11429 out << net_num_leaf_changes << " artifact";
11430 if (net_num_leaf_changes > 1)
11431 out << "s";
11432 out << " changed";
11433
11434 if (size_t num_filtered = s.num_leaf_changes_filtered_out())
11435 out << " (" << num_filtered << " filtered out)";
11436 out << "\n";
11437
11438 out << indent << "Changed leaf types summary: "
11441 out << " (" << s.num_leaf_type_changes_filtered_out()
11442 << " filtered out)";
11443 out << " leaf type";
11444 if (s.num_leaf_type_changes() > 1)
11445 out << "s";
11446 out << " changed\n";
11447
11448 // function changes summary
11449 out << indent << "Removed/Changed/Added functions summary: ";
11450 out << s.net_num_func_removed() << " Removed";
11452 out << " ("
11454 << " filtered out)";
11455 out << ", ";
11456
11457 out << s.net_num_leaf_func_changes() << " Changed";
11459 out << " ("
11461 << " filtered out)";
11462 out << ", ";
11463
11464 out << s.net_num_func_added()<< " Added ";
11465 if (s.net_num_func_added() <= 1)
11466 out << "function";
11467 else
11468 out << "functions";
11470 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11471 out << "\n";
11472
11473 // variables changes summary
11474 out << indent << "Removed/Changed/Added variables summary: ";
11475 out << s.net_num_vars_removed() << " Removed";
11477 out << " (" << s.num_removed_vars_filtered_out()
11478 << " filtered out)";
11479 out << ", ";
11480
11481 out << s.net_num_leaf_var_changes() << " Changed";
11483 out << " ("
11485 << " filtered out)";
11486 out << ", ";
11487
11488 out << s.net_num_vars_added() << " Added ";
11489 if (s.net_num_vars_added() <= 1)
11490 out << "variable";
11491 else
11492 out << "variables";
11494 out << " (" << s.num_added_vars_filtered_out()
11495 << " filtered out)";
11496 out << "\n";
11497 }
11498 else // if (ctxt->show_leaf_changes_only())
11499 {
11500 size_t total_nb_function_changes = s.num_func_removed()
11501 + s.num_func_changed() + s.num_func_added();
11502
11503 // function changes summary
11504 out << indent << "Functions changes summary: ";
11505 out << s.net_num_func_removed() << " Removed";
11507 out << " ("
11509 << " filtered out)";
11510 out << ", ";
11511
11512 out << s.net_num_func_changed() << " Changed";
11514 out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
11515 out << ", ";
11516
11517 out << s.net_num_func_added() << " Added";
11519 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11520 if (total_nb_function_changes <= 1)
11521 out << " function";
11522 else
11523 out << " functions";
11524 out << "\n";
11525
11526 // variables changes summary
11527 size_t total_nb_variable_changes = s.num_vars_removed()
11528 + s.num_vars_changed() + s.num_vars_added();
11529
11530 out << indent << "Variables changes summary: ";
11531 out << s.net_num_vars_removed() << " Removed";
11533 out << " (" << s.num_removed_vars_filtered_out()
11534 << " filtered out)";
11535 out << ", ";
11536
11537 out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
11539 out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
11540 out << ", ";
11541
11542 out << s.net_num_vars_added() << " Added";
11544 out << " (" << s.num_added_vars_filtered_out()
11545 << " filtered out)";
11546 if (total_nb_variable_changes <= 1)
11547 out << " variable";
11548 else
11549 out << " variables";
11550 out << "\n";
11551 }
11552
11553 // Show statistics about types not reachable from global
11554 // functions/variables.
11555 if (ctxt->show_unreachable_types())
11556 {
11557 size_t total_nb_unreachable_type_changes =
11561
11562 // Show summary of unreachable types
11563 out << indent << "Unreachable types summary: "
11565 << " removed";
11568 << " filtered out)";
11569 out << ", ";
11570
11572 << " changed";
11575 << " filtered out)";
11576 out << ", ";
11577
11579 << " added";
11582 << " filtered out)";
11583 if (total_nb_unreachable_type_changes <= 1)
11584 out << " type";
11585 else
11586 out << " types";
11587 out << "\n";
11588 }
11589
11590 if (ctxt->show_symbols_unreferenced_by_debug_info()
11591 && (s.num_func_syms_removed()
11592 || s.num_func_syms_added()
11594 || s.num_var_syms_added()))
11595 {
11596 // function symbols changes summary.
11597
11598 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11599 && s.num_func_syms_removed() == 0
11600 && s.num_func_syms_added() != 0)
11601 // If the only unreferenced function symbol change is function
11602 // syms that got added, but we were forbidden to show function
11603 // syms being added, do nothing.
11604 ;
11605 else
11606 {
11607 out << indent
11608 << "Function symbols changes summary: "
11609 << s.net_num_removed_func_syms() << " Removed";
11611 out << " (" << s.num_removed_func_syms_filtered_out()
11612 << " filtered out)";
11613 out << ", ";
11614 out << s.net_num_added_func_syms() << " Added";
11616 out << " (" << s.num_added_func_syms_filtered_out()
11617 << " filtered out)";
11618 out << " function symbol";
11620 out << "s";
11621 out << " not referenced by debug info\n";
11622 }
11623
11624 // variable symbol changes summary.
11625
11626 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11627 && s.num_var_syms_removed() == 0
11628 && s.num_var_syms_added() != 0)
11629 // If the only unreferenced variable symbol change is variable
11630 // syms that got added, but we were forbidden to show variable
11631 // syms being added, do nothing.
11632 ;
11633 else
11634 {
11635 out << indent
11636 << "Variable symbols changes summary: "
11637 << s.net_num_removed_var_syms() << " Removed";
11639 out << " (" << s.num_removed_var_syms_filtered_out()
11640 << " filtered out)";
11641 out << ", ";
11642 out << s.net_num_added_var_syms() << " Added";
11644 out << " (" << s.num_added_var_syms_filtered_out()
11645 << " filtered out)";
11646 out << " variable symbol";
11647 if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
11648 out << "s";
11649 out << " not referenced by debug info\n";
11650 }
11651 }
11652}
11653
11654/// Walk the changed functions and variables diff nodes to categorize
11655/// redundant nodes.
11656void
11658{
11660
11661 diff_context_sptr ctxt = get_context();
11662
11663 ctxt->forget_visited_diffs();
11664 for (function_decl_diff_sptrs_type::const_iterator i =
11665 changed_fns_.begin();
11666 i!= changed_fns_.end();
11667 ++i)
11668 {
11669 diff = *i;
11671 }
11672
11673 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11674 i!= sorted_changed_vars_.end();
11675 ++i)
11676 {
11677 diff_sptr diff = *i;
11679 }
11680
11681 for (diff_sptrs_type::const_iterator i =
11684 ++i)
11685 {
11686 diff_sptr diff = *i;
11688 }
11689}
11690
11691/// Walk the changed functions and variables diff nodes and clear the
11692/// redundancy categorization they might carry.
11693void
11695{
11697 for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
11698 i!= changed_fns_.end();
11699 ++i)
11700 {
11701 diff = *i;
11703 }
11704
11705 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11706 i!= sorted_changed_vars_.end();
11707 ++i)
11708 {
11709 diff = *i;
11711 }
11712}
11713
11714/// If the user asked to dump the diff tree node (for changed
11715/// variables and functions) on the error output stream, then just do
11716/// that.
11717///
11718/// This function is used for debugging purposes.
11719void
11721{
11722 diff_context_sptr ctxt = get_context();
11723
11724 if (!ctxt->dump_diff_tree()
11725 || ctxt->error_output_stream() == 0)
11726 return;
11727
11728 if (!changed_fns_.empty())
11729 {
11730 *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
11731 for (function_decl_diff_sptrs_type::const_iterator i =
11732 changed_fns_.begin();
11733 i != changed_fns_.end();
11734 ++i)
11735 {
11736 diff_sptr d = *i;
11737 print_diff_tree(d, *ctxt->error_output_stream());
11738 }
11739 }
11740
11741 if (!sorted_changed_vars_.empty())
11742 {
11743 *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
11744 for (var_diff_sptrs_type::const_iterator i =
11745 sorted_changed_vars_.begin();
11746 i != sorted_changed_vars_.end();
11747 ++i)
11748 {
11749 diff_sptr d = *i;
11750 print_diff_tree(d, *ctxt->error_output_stream());
11751 }
11752 }
11753
11754 if (!changed_unreachable_types_sorted().empty())
11755 {
11756 *ctxt->error_output_stream() << "\nchanged unreachable "
11757 "types diff tree: \n\n";
11758 for (vector<diff_sptr>::const_iterator i =
11761 ++i)
11762 {
11763 diff_sptr d = *i;
11764 print_diff_tree(d, *ctxt->error_output_stream());
11765 }
11766 }
11767}
11768
11769/// Populate the vector of children node of the @ref corpus_diff type.
11770///
11771/// The children node can then later be retrieved using
11772/// corpus_diff::children_node().
11773void
11775{
11776 for (function_decl_diff_sptrs_type::const_iterator i =
11777 changed_functions_sorted().begin();
11778 i != changed_functions_sorted().end();
11779 ++i)
11780 if (diff_sptr d = *i)
11782}
11783
11784/// Constructor for @ref corpus_diff.
11785///
11786/// @param first the first corpus of the diff.
11787///
11788/// @param second the second corpus of the diff.
11789///
11790/// @param ctxt the diff context to use. Note that this context
11791/// object must stay alive at least during the life time of the
11792/// current instance of @ref corpus_diff. Otherwise memory corruption
11793/// issues occur.
11795 corpus_sptr second,
11796 diff_context_sptr ctxt)
11797 : priv_(new priv(first, second, ctxt))
11798{}
11799
11800corpus_diff::~corpus_diff() = default;
11801
11802/// Finish building the current instance of @ref corpus_diff.
11803void
11805{
11806 if (priv_->finished_)
11807 return;
11809 priv_->finished_ = true;
11810}
11811
11812/// Test if logging was requested.
11813///
11814/// @return true iff logging was requested.
11815bool
11817{return context()->do_log();}
11818
11819/// Request logging, or not.
11820///
11821/// @param f true iff logging is requested.
11822void
11824{context()->do_log(f);}
11825
11826/// @return the first corpus of the diff.
11827corpus_sptr
11829{return priv_->first_;}
11830
11831/// @return the second corpus of the diff.
11832corpus_sptr
11834{return priv_->second_;}
11835
11836/// @return the children nodes of the current instance of corpus_diff.
11837const vector<diff*>&
11839{return priv_->children_;}
11840
11841/// Append a new child node to the vector of children nodes for the
11842/// current instance of @ref corpus_diff node.
11843///
11844/// Note that the vector of children nodes for the current instance of
11845/// @ref corpus_diff node must remain sorted, using
11846/// diff_less_than_functor.
11847///
11848/// @param d the new child node. Note that the life time of the
11849/// object held by @p d will thus equal the life time of the current
11850/// instance of @ref corpus_diff.
11851void
11853{
11854 ABG_ASSERT(d);
11855
11857 bool inserted = false;
11858 for (vector<diff*>::iterator i = priv_->children_.begin();
11859 i != priv_->children_.end();
11860 ++i)
11861 // Look for the point where to insert the diff child node.
11862 if (!is_less_than(d.get(), *i))
11863 {
11864 context()->keep_diff_alive(d);
11865 priv_->children_.insert(i, d.get());
11866 // As we have just inserted 'd' into the vector, the iterator
11867 // 'i' is invalidated. We must *NOT* use it anymore.
11868 inserted = true;
11869 break;
11870 }
11871
11872 if (!inserted)
11873 {
11874 context()->keep_diff_alive(d);
11875 // We didn't insert anything to the vector, presumably b/c it was
11876 // empty or had one element that was "less than" 'd'. We can thus
11877 // just append 'd' to the end of the vector.
11878 priv_->children_.push_back(d.get());
11879 }
11880}
11881
11882/// @return the bare edit script of the functions changed as recorded
11883/// by the diff.
11886{return priv_->fns_edit_script_;}
11887
11888/// @return the bare edit script of the variables changed as recorded
11889/// by the diff.
11892{return priv_->vars_edit_script_;}
11893
11894/// Test if the soname of the underlying corpus has changed.
11895///
11896/// @return true iff the soname has changed.
11897bool
11899{return !priv_->sonames_equal_;}
11900
11901/// Test if the architecture of the underlying corpus has changed.
11902///
11903/// @return true iff the architecture has changed.
11904bool
11906{return !priv_->architectures_equal_;}
11907
11908/// Getter for the deleted functions of the diff.
11909///
11910/// @return the the deleted functions of the diff.
11913{return priv_->deleted_fns_;}
11914
11915/// Getter for the added functions of the diff.
11916///
11917/// @return the added functions of the diff.
11920{return priv_->added_fns_;}
11921
11922/// Getter for the functions which signature didn't change, but which
11923/// do have some indirect changes in their parms.
11924///
11925/// @return a non-sorted map of functions which signature didn't
11926/// change, but which do have some indirect changes in their parms.
11927/// The key of the map is a unique identifier for the function; it's
11928/// usually made of the name and version of the underlying ELF symbol
11929/// of the function for corpora that were built from ELF files.
11932{return priv_->changed_fns_map_;}
11933
11934/// Getter for a sorted vector of functions which signature didn't
11935/// change, but which do have some indirect changes in their parms.
11936///
11937/// @return a sorted vector of functions which signature didn't
11938/// change, but which do have some indirect changes in their parms.
11941{return priv_->changed_fns_;}
11942
11943/// Getter of the set of diff nodes representing incompatibly changed
11944/// functions
11945///
11946/// @return the set of diff nodes representing incompatibly changed
11947/// functions
11950{return priv_->incompatible_changed_fns_;}
11951
11952/// Getter of the set of diff nodes representing incompatibly changed
11953/// functions
11954///
11955/// @return the set of diff nodes representing incompatibly changed
11956/// functions
11959{return priv_->incompatible_changed_fns_;}
11960
11961/// Getter for the variables that got deleted from the first subject
11962/// of the diff.
11963///
11964/// @return the map of deleted variable.
11965const string_var_ptr_map&
11967{return priv_->deleted_vars_;}
11968
11969/// Getter for the added variables of the diff.
11970///
11971/// @return the map of added variable.
11972const string_var_ptr_map&
11974{return priv_->added_vars_;}
11975
11976/// Getter for the non-sorted map of variables which signature didn't
11977/// change but which do have some indirect changes in some sub-types.
11978///
11979/// @return the non-sorted map of changed variables.
11982{return priv_->changed_vars_map_;}
11983
11984/// Getter for the sorted vector of variables which signature didn't
11985/// change but which do have some indirect changes in some sub-types.
11986///
11987/// @return a sorted vector of changed variables.
11990{return priv_->sorted_changed_vars_;}
11991
11992/// Getter of the set of diff nodes representing incompatibly changed
11993/// global variables.
11994///
11995/// @return the set of diff nodes representing incompatibly changed
11996/// global variables.
11999{return priv_->incompatible_changed_vars_;}
12000
12001/// Getter of the set of diff nodes representing incompatibly changed
12002/// global variables.
12003///
12004/// @return the set of diff nodes representing incompatibly changed
12005/// global variables.
12008{return priv_->incompatible_changed_vars_;}
12009
12010/// Getter for function symbols not referenced by any debug info and
12011/// that got deleted.
12012///
12013/// @return a map of elf function symbols not referenced by any debug
12014/// info and that got deleted.
12017{return priv_->deleted_unrefed_fn_syms_;}
12018
12019/// Getter for function symbols not referenced by any debug info and
12020/// that got added.
12021///
12022/// @return a map of elf function symbols not referenced by any debug
12023/// info and that got added.
12026{return priv_->added_unrefed_fn_syms_;}
12027
12028/// Getter for variable symbols not referenced by any debug info and
12029/// that got deleted.
12030///
12031/// @return a map of elf variable symbols not referenced by any debug
12032/// info and that got deleted.
12035{return priv_->deleted_unrefed_var_syms_;}
12036
12037/// Getter for variable symbols not referenced by any debug info and
12038/// that got added.
12039///
12040/// @return a map of elf variable symbols not referenced by any debug
12041/// info and that got added.
12044{return priv_->added_unrefed_var_syms_;}
12045
12046/// Getter for a map of deleted types that are not reachable from
12047/// global functions/variables.
12048///
12049/// @return a map that associates pretty representation of deleted
12050/// unreachable types and said types.
12053{return priv_->deleted_unreachable_types_;}
12054
12055/// Getter of a sorted vector of deleted types that are not reachable
12056/// from global functions/variables.
12057///
12058/// @return a sorted vector of deleted types that are not reachable
12059/// from global functions/variables. The types are lexicographically
12060/// sorted by considering their pretty representation.
12061const vector<type_base_sptr>&
12063{
12064 if (priv_->deleted_unreachable_types_sorted_.empty())
12065 if (!priv_->deleted_unreachable_types_.empty())
12066 sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
12067 priv_->deleted_unreachable_types_sorted_);
12068
12069 return priv_->deleted_unreachable_types_sorted_;
12070}
12071
12072/// Getter for a map of added types that are not reachable from global
12073/// functions/variables.
12074///
12075/// @return a map that associates pretty representation of added
12076/// unreachable types and said types.
12079{return priv_->added_unreachable_types_;}
12080
12081/// Getter of a sorted vector of added types that are not reachable
12082/// from global functions/variables.
12083///
12084/// @return a sorted vector of added types that are not reachable from
12085/// global functions/variables. The types are lexicographically
12086/// sorted by considering their pretty representation.
12087const vector<type_base_sptr>&
12089{
12090 if (priv_->added_unreachable_types_sorted_.empty())
12091 if (!priv_->added_unreachable_types_.empty())
12092 sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
12093 priv_->added_unreachable_types_sorted_);
12094
12095 return priv_->added_unreachable_types_sorted_;
12096}
12097
12098/// Getter for a map of changed types that are not reachable from
12099/// global functions/variables.
12100///
12101/// @return a map that associates pretty representation of changed
12102/// unreachable types and said types.
12105{return priv_->changed_unreachable_types_;}
12106
12107/// Getter of a sorted vector of changed types that are not reachable
12108/// from global functions/variables.
12109///
12110/// @return a sorted vector of changed types that are not reachable
12111/// from global functions/variables. The diffs are lexicographically
12112/// sorted by considering their pretty representation.
12113const vector<diff_sptr>&
12115{return priv_->changed_unreachable_types_sorted();}
12116
12117/// Getter of the diff context of this diff
12118///
12119/// @return the diff context for this diff.
12122{return priv_->get_context();}
12123
12124/// @return the pretty representation for the current instance of @ref
12125/// corpus_diff
12126const string&
12128{
12129 if (priv_->pretty_representation_.empty())
12130 {
12131 std::ostringstream o;
12132 o << "corpus_diff["
12133 << first_corpus()->get_path()
12134 << ", "
12135 << second_corpus()->get_path()
12136 << "]";
12137 priv_->pretty_representation_ = o.str();
12138 }
12139 return priv_->pretty_representation_;
12140}
12141/// Return true iff the current @ref corpus_diff node carries a
12142/// change.
12143///
12144/// @return true iff the current diff node carries a change.
12145bool
12147{
12148 return (soname_changed()
12150 || !(priv_->deleted_fns_.empty()
12151 && priv_->added_fns_.empty()
12152 && priv_->changed_fns_map_.empty()
12153 && priv_->deleted_vars_.empty()
12154 && priv_->added_vars_.empty()
12155 && priv_->changed_vars_map_.empty()
12156 && priv_->added_unrefed_fn_syms_.empty()
12157 && priv_->deleted_unrefed_fn_syms_.empty()
12158 && priv_->added_unrefed_var_syms_.empty()
12159 && priv_->deleted_unrefed_var_syms_.empty()
12160 && priv_->deleted_unreachable_types_.empty()
12161 && priv_->added_unreachable_types_.empty()
12162 && priv_->changed_unreachable_types_.empty()));
12163}
12164
12165/// Test if the current instance of @ref corpus_diff carries changes
12166/// that we are sure are incompatible. By incompatible change we mean
12167/// a change that "breaks" the ABI of the corpus we are looking at.
12168///
12169/// In concrete terms, this function considers the following changes
12170/// as being ABI incompatible for sure:
12171///
12172/// - a soname change
12173/// - if exported functions or variables got removed
12174///
12175/// Note that subtype changes *can* represent changes that break ABI
12176/// too. But they also can be changes that are OK, ABI-wise.
12177///
12178/// It's up to the user to provide suppression specifications to say
12179/// explicitely which subtype change is OK. The remaining sub-type
12180/// changes are then considered to be ABI incompatible. But to test
12181/// if such ABI incompatible subtype changes are present you need to
12182/// use the function @ref corpus_diff::has_net_subtype_changes()
12183///
12184/// @return true iff the current instance of @ref corpus_diff carries
12185/// changes that we are sure are ABI incompatible.
12186bool
12188{
12189 const diff_stats& stats = const_cast<corpus_diff*>(this)->
12191
12195 || stats.net_num_func_removed() != 0
12197 // If all reports about functions changes have been
12198 // suppressed, then even those about incompatible changes
12199 // don't matter anymore because the user willingly requested
12200 // to shut them down.
12201 && stats.net_num_func_changed() != 0)
12202 || stats.net_num_vars_removed() != 0
12204 && stats.net_num_vars_changed() != 0)
12205 || stats.net_num_removed_func_syms() != 0
12206 || stats.net_num_removed_var_syms() != 0
12207 || stats.net_num_removed_unreachable_types() != 0);
12208
12209 // If stats.net_num_changed_unreachable_types() != 0 then walk the
12210 // corpus_diff::priv::changed_unreachable_types_, and see if there
12211 // is one that is harmful by bitwise and-ing their category with
12212 // abigail::comparison::get_default_harmful_categories_bitmap().
12215 {
12216 // The changed unreachable types can carry harmful changes.
12217 // Let's figure if they actually do.
12218
12219 diff_context_sptr ctxt = context();
12220 for (auto &entry : priv_->changed_unreachable_types())
12221 {
12222 diff_sptr dif = entry.second;
12223
12224 // Let's see if any of the categories of this diff node
12225 // belong to the "harmful" ones.
12226 if (dif->get_category() & get_default_harmful_categories_bitmap())
12227 {
12229 break;
12230 }
12231 }
12232 }
12233
12235}
12236
12237/// Test if the current instance of @ref corpus_diff carries subtype
12238/// changes whose reports are not suppressed by any suppression
12239/// specification. In effect, these are deemed incompatible ABI
12240/// changes.
12241///
12242/// @return true iff the the current instance of @ref corpus_diff
12243/// carries subtype changes that are deemed incompatible ABI changes.
12244bool
12246{
12247 const diff_stats& stats = const_cast<corpus_diff*>(this)->
12249
12250 return (stats.net_num_func_changed() != 0
12251 || stats.net_num_vars_changed() != 0
12252 || stats.net_num_removed_unreachable_types() != 0
12253 || stats.net_num_changed_unreachable_types() != 0);
12254}
12255
12256/// Test if the current instance of @ref corpus_diff carries changes
12257/// whose reports are not suppressed by any suppression specification.
12258/// In effect, these are deemed incompatible ABI changes.
12259///
12260/// @return true iff the the current instance of @ref corpus_diff
12261/// carries subtype changes that are deemed incompatible ABI changes.
12262bool
12264{return context()->get_reporter()->diff_has_net_changes(this);}
12265
12266/// Apply the different filters that are registered to be applied to
12267/// the diff tree; that includes the categorization filters. Also,
12268/// apply the suppression interpretation filters.
12269///
12270/// After the filters are applied, this function calculates some
12271/// statistics about the changes carried by the current instance of
12272/// @ref corpus_diff. These statistics are represented by an instance
12273/// of @ref corpus_diff::diff_stats.
12274///
12275/// This member function is called by the reporting function
12276/// corpus_diff::report().
12277///
12278/// Note that for a given instance of corpus_diff, this function
12279/// applies the filters and suppressions only the first time it is
12280/// invoked. Subsequent invocations just return the instance of
12281/// corpus_diff::diff_stats that was cached after the first
12282/// invocation.
12283///
12284/// @return a reference to the statistics about the changes carried by
12285/// the current instance of @ref corpus_diff.
12288{
12289 if (priv_->diff_stats_)
12290 return *priv_->diff_stats_;
12291
12293 if (do_log())
12294 {
12295 std::cerr << "Applying suppressions ...\n";
12296 t.start();
12297 }
12298
12299 apply_suppressions(this);
12300
12301 if (do_log())
12302 {
12303 t.stop();
12304 std::cerr << "suppressions applied!:" << t << "\n";
12305 }
12306
12307 priv_->diff_stats_.reset(new diff_stats(context()));
12308
12309 if (do_log())
12310 {
12311 std::cerr << "Marking leaf nodes ...\n";
12312 t.start();
12313 }
12314
12316
12317 if (do_log())
12318 {
12319 t.stop();
12320 std::cerr << "leaf nodes marked!:" << t << "\n";
12321 std::cerr << "Applying filters and computing diff stats ...\n";
12322 t.start();
12323 }
12324
12325 priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
12326
12327 if (do_log())
12328 {
12329 t.stop();
12330 std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
12331 }
12332
12333 return *priv_->diff_stats_;
12334}
12335
12336/// A visitor that marks leaf diff nodes by storing them in the
12337/// instance of @ref diff_maps returned by
12338/// corpus_diff::get_leaf_diffs() invoked on the current instance of
12339/// corpus_diff.
12340struct leaf_diff_node_marker_visitor : public diff_node_visitor
12341{
12342 /// This is called when the visitor visits a diff node.
12343 ///
12344 /// It basically tests if the diff node being visited is a leaf diff
12345 /// node - that is, it contains local changes. If it does, then the
12346 /// node is added to the set of maps that hold leaf diffs in the
12347 /// current corpus_diff.
12348 ///
12349 /// Note that only leaf nodes that are reachable from public
12350 /// interfaces (global functions or variables) are collected by this
12351 /// visitor.
12352 ///
12353 /// @param d the diff node being visited.
12354 virtual void
12355 visit_begin(diff *d)
12356 {
12357 if (d->has_local_changes()
12358 // A leaf basic (or class/union) type name change makes no
12359 // sense when showing just leaf changes. It only makes sense
12360 // when it can explain the details about a non-leaf change.
12361 // In other words, it doesn't make sense to say that an "int"
12362 // became "unsigned int". But it does make sense to say that
12363 // a typedef changed because its underlying type was 'int' and
12364 // is now an "unsigned int".
12366 // Similarly, a *local* change describing a type that changed
12367 // its nature doesn't make sense.
12368 && !is_distinct_diff(d)
12369 // Similarly, a pointer (or reference or array), a typedef or
12370 // qualified type change in itself doesn't make sense. It
12371 // would rather make sense to show that pointer change as part
12372 // of the variable change whose pointer type changed, for
12373 // instance.
12374 && !is_pointer_diff(d)
12375 && !is_reference_diff(d)
12377 && !is_typedef_diff(d)
12378 && !is_array_diff(d)
12379 // Similarly a parameter change in itself doesn't make sense.
12380 // It should have already been reported as part of the change
12381 // of the function it belongs to.
12382 && !is_fn_parm_diff(d)
12383 // An anonymous class or union diff doesn't make sense on its
12384 // own. It must have been described already by the diff of
12385 // the enclosing struct or union if 'd' is from an anonymous
12386 // data member, or from a typedef change if 'd' is from a
12387 // typedef change which underlying type is an anonymous
12388 // struct/union.
12390 // An anonymous subrange doesn't make sense either.
12392 // Don't show decl-only-ness changes either.
12394 // Sometime, we can encounter artifacts of bogus DWARF that
12395 // yield a diff node for a decl-only class (and empty class
12396 // with the is_declaration flag set) that carries a non-zero
12397 // size! And of course at some point that non-zero size
12398 // changes. We need to be able to detect that.
12400 {
12401 diff_context_sptr ctxt = d->context();
12402 const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
12403 ABG_ASSERT(corpus_diff_node);
12404
12405 if (diff *iface_diff = get_current_topmost_iface_diff())
12406 {
12407 type_or_decl_base_sptr iface = iface_diff->first_subject();
12408 // So, this diff node that is reachable from a global
12409 // function or variable carries a leaf change. Let's add
12410 // it to the set of of leaf diffs of corpus_diff_node.
12411 const_cast<corpus_diff*>(corpus_diff_node)->
12412 get_leaf_diffs().insert_diff_node(d, iface);
12413 }
12414 }
12415 }
12416}; // end struct leaf_diff_node_marker_visitor
12417
12418/// Walks the diff nodes associated to the current corpus diff and
12419/// mark those that carry local changes. They are said to be leaf
12420/// diff nodes.
12421///
12422/// The marked nodes are available from the
12423/// corpus_diff::get_leaf_diffs() function.
12424void
12426{
12427 if (!has_changes())
12428 return;
12429
12430 if (!context()->show_leaf_changes_only())
12431 return;
12432
12433 leaf_diff_node_marker_visitor v;
12434 context()->forget_visited_diffs();
12435 bool s = context()->visiting_a_node_twice_is_forbidden();
12436 context()->forbid_visiting_a_node_twice(true);
12437 if (context()->show_impacted_interfaces())
12438 context()->forbid_visiting_a_node_twice_per_interface(true);
12439 traverse(v);
12440 context()->forbid_visiting_a_node_twice(s);
12441 context()->forbid_visiting_a_node_twice_per_interface(false);
12442}
12443
12444/// Get the set of maps that contain leaf nodes. A leaf node being a
12445/// node with a local change.
12446///
12447/// @return the set of maps that contain leaf nodes. A leaf node
12448/// being a node with a local change.
12449diff_maps&
12451{return priv_->leaf_diffs_;}
12452
12453/// Get the set of maps that contain leaf nodes. A leaf node being a
12454/// node with a local change.
12455///
12456/// @return the set of maps that contain leaf nodes. A leaf node
12457/// being a node with a local change.
12458const diff_maps&
12460{return priv_->leaf_diffs_;}
12461
12462/// Report the diff in a serialized form.
12463///
12464/// @param out the stream to serialize the diff to.
12465///
12466/// @param indent the prefix to use for the indentation of this
12467/// serialization.
12468void
12469corpus_diff::report(ostream& out, const string& indent) const
12470{
12471 context()->get_reporter()->report(*this, out, indent);
12472}
12473
12474/// Traverse the diff sub-tree under the current instance corpus_diff.
12475///
12476/// @param v the visitor to invoke on each diff node of the sub-tree.
12477///
12478/// @return true if the traversing has to keep going on, false otherwise.
12479bool
12481{
12483
12484 v.visit_begin(this);
12485
12486 if (!v.visit(this, true))
12487 {
12488 v.visit_end(this);
12489 return false;
12490 }
12491
12492 for (function_decl_diff_sptrs_type::const_iterator i =
12493 changed_functions_sorted().begin();
12494 i != changed_functions_sorted().end();
12495 ++i)
12496 {
12497 if (diff_sptr d = *i)
12498 {
12499 const diff_context_sptr &ctxt = context();
12500 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12501 ctxt->forget_visited_diffs();
12502
12504
12505 if (!d->traverse(v))
12506 {
12507 v.visit_end(this);
12509 return false;
12510 }
12511 }
12512 }
12513
12514 for (var_diff_sptrs_type::const_iterator i =
12515 changed_variables_sorted().begin();
12516 i != changed_variables_sorted().end();
12517 ++i)
12518 {
12519 if (diff_sptr d = *i)
12520 {
12521 const diff_context_sptr &ctxt = context();
12522 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12523 ctxt->forget_visited_diffs();
12524
12526
12527 if (!d->traverse(v))
12528 {
12529 v.visit_end(this);
12531 return false;
12532 }
12533 }
12534 }
12535
12537
12538 // Traverse the changed unreachable type diffs. These diffs are on
12539 // types that are not reachable from global functions or variables.
12540 for (vector<diff_sptr>::const_iterator i =
12543 ++i)
12544 {
12545 if (diff_sptr d = *i)
12546 {
12547 const diff_context_sptr &ctxt = context();
12548 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12549 ctxt->forget_visited_diffs();
12550
12551 if (!d->traverse(v))
12552 {
12553 v.visit_end(this);
12554 return false;
12555 }
12556 }
12557 }
12558
12559 v.visit_end(this);
12560 return true;
12561}
12562
12563/// Compute the diff between two instances of @ref corpus.
12564///
12565/// Note that the two corpora must have been created in the same @ref
12566/// environment, otherwise, this function aborts.
12567///
12568/// @param f the first @ref corpus to consider for the diff.
12569///
12570/// @param s the second @ref corpus to consider for the diff.
12571///
12572/// @param ctxt the diff context to use.
12573///
12574/// @return the resulting diff between the two @ref corpus.
12576compute_diff(const corpus_sptr f,
12577 const corpus_sptr s,
12578 diff_context_sptr ctxt)
12579{
12580 typedef corpus::functions::const_iterator fns_it_type;
12581 typedef corpus::variables::const_iterator vars_it_type;
12582 typedef elf_symbols::const_iterator symbols_it_type;
12583 typedef diff_utils::deep_ptr_eq_functor eq_type;
12584 typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
12585
12586 ABG_ASSERT(f && s);
12587
12588 if (!ctxt)
12589 ctxt.reset(new diff_context);
12590
12591 corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
12592
12593 ctxt->set_corpus_diff(r);
12594
12595 if(ctxt->show_soname_change())
12596 r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
12597 else
12598 r->priv_->sonames_equal_ = true;
12599
12600 r->priv_->architectures_equal_ =
12601 f->get_architecture_name() == s->get_architecture_name();
12602
12603 // Compute the diff of publicly defined and exported functions
12604 diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
12605 f->get_functions().end(),
12606 s->get_functions().begin(),
12607 s->get_functions().end(),
12608 r->priv_->fns_edit_script_);
12609
12610 // Compute the diff of publicly defined and exported variables.
12611 diff_utils::compute_diff<vars_it_type, eq_type>
12612 (f->get_variables().begin(), f->get_variables().end(),
12613 s->get_variables().begin(), s->get_variables().end(),
12614 r->priv_->vars_edit_script_);
12615
12616 // Compute the diff of function elf symbols not referenced by debug
12617 // info.
12618 diff_utils::compute_diff<symbols_it_type, eq_type>
12619 (f->get_unreferenced_function_symbols().begin(),
12620 f->get_unreferenced_function_symbols().end(),
12621 s->get_unreferenced_function_symbols().begin(),
12622 s->get_unreferenced_function_symbols().end(),
12623 r->priv_->unrefed_fn_syms_edit_script_);
12624
12625 // Compute the diff of variable elf symbols not referenced by debug
12626 // info.
12627 diff_utils::compute_diff<symbols_it_type, eq_type>
12628 (f->get_unreferenced_variable_symbols().begin(),
12629 f->get_unreferenced_variable_symbols().end(),
12630 s->get_unreferenced_variable_symbols().begin(),
12631 s->get_unreferenced_variable_symbols().end(),
12632 r->priv_->unrefed_var_syms_edit_script_);
12633
12634 if (ctxt->show_unreachable_types())
12635 // Compute the diff of types not reachable from public functions
12636 // or global variables that are exported.
12637 diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
12638 (f->get_types_not_reachable_from_public_interfaces().begin(),
12639 f->get_types_not_reachable_from_public_interfaces().end(),
12640 s->get_types_not_reachable_from_public_interfaces().begin(),
12641 s->get_types_not_reachable_from_public_interfaces().end(),
12642 r->priv_->unreachable_types_edit_script_);
12643
12644 r->priv_->ensure_lookup_tables_populated();
12645
12646 return r;
12647}
12648
12649// </corpus stuff>
12650
12651/// Compute the diff between two instances of @ref corpus_group.
12652///
12653/// Note that the two corpus_diff must have been created in the same
12654/// @ref environment, otherwise, this function aborts.
12655///
12656/// @param f the first @ref corpus_group to consider for the diff.
12657///
12658/// @param s the second @ref corpus_group to consider for the diff.
12659///
12660/// @param ctxt the diff context to use.
12661///
12662/// @return the resulting diff between the two @ref corpus_group.
12664compute_diff(const corpus_group_sptr& f,
12665 const corpus_group_sptr& s,
12666 diff_context_sptr ctxt)
12667{
12668
12669 corpus_sptr c1 = f;
12670 corpus_sptr c2 = s;
12671
12672 return compute_diff(c1, c2, ctxt);
12673}
12674
12675// <corpus_group stuff>
12676
12677// </corpus_group stuff>
12678// <diff_node_visitor stuff>
12679
12680/// The private data of the @diff_node_visitor type.
12681struct diff_node_visitor::priv
12682{
12683 diff* topmost_interface_diff;
12684 visiting_kind kind;
12685
12686 priv()
12687 : topmost_interface_diff(),
12688 kind()
12689 {}
12690
12691 priv(visiting_kind k)
12692 : topmost_interface_diff(),
12693 kind(k)
12694 {}
12695}; // end struct diff_node_visitor
12696
12697/// Default constructor of the @ref diff_node_visitor type.
12699 : priv_(new priv)
12700{}
12701
12702diff_node_visitor::~diff_node_visitor() = default;
12703
12704/// Constructor of the @ref diff_node_visitor type.
12705///
12706/// @param k how the visiting has to be performed.
12708 : priv_(new priv(k))
12709{}
12710
12711/// Getter for the visiting policy of the traversing code while
12712/// invoking this visitor.
12713///
12714/// @return the visiting policy used by the traversing code when
12715/// invoking this visitor.
12718{return priv_->kind;}
12719
12720/// Setter for the visiting policy of the traversing code while
12721/// invoking this visitor.
12722///
12723/// @param v a bit map representing the new visiting policy used by
12724/// the traversing code when invoking this visitor.
12725void
12727{priv_->kind = v;}
12728
12729/// Setter for the visiting policy of the traversing code while
12730/// invoking this visitor. This one makes a logical or between the
12731/// current policy and the bitmap given in argument and assigns the
12732/// current policy to the result.
12733///
12734/// @param v a bitmap representing the visiting policy to or with
12735/// the current policy.
12736void
12738{priv_->kind = priv_->kind | v;}
12739
12740/// Setter of the diff current topmost interface which is impacted by
12741/// the current diff node being visited.
12742///
12743/// @param d the current topmost interface diff impacted.
12744void
12746{priv_->topmost_interface_diff = d;}
12747
12748/// Getter of the diff current topmost interface which is impacted by
12749/// the current diff node being visited.
12750///
12751/// @return the current topmost interface diff impacted.
12752diff*
12754{return priv_->topmost_interface_diff;}
12755
12756/// This is called by the traversing code on a @ref diff node just
12757/// before visiting it. That is, before visiting it and its children
12758/// node.
12759///
12760/// @param d the diff node to visit.
12761void
12763{}
12764
12765/// This is called by the traversing code on a @ref diff node just
12766/// after visiting it. That is after visiting it and its children
12767/// nodes.
12768///
12769/// @param d the diff node that got visited.
12770void
12772{}
12773
12774/// This is called by the traversing code on a @ref corpus_diff node
12775/// just before visiting it. That is, before visiting it and its
12776/// children node.
12777///
12778/// @param p the corpus_diff node to visit.
12779///
12780void
12782{}
12783
12784/// This is called by the traversing code on a @ref corpus_diff node
12785/// just after visiting it. That is after visiting it and its children
12786/// nodes.
12787///
12788/// @param d the diff node that got visited.
12789void
12791{}
12792
12793/// Default visitor implementation
12794///
12795/// @return true
12796bool
12798{return true;}
12799
12800/// Default visitor implementation.
12801///
12802/// @return true
12803bool
12805{
12806 diff* d = dif;
12807 visit(d, pre);
12808
12809 return true;
12810}
12811
12812/// Default visitor implementation.
12813///
12814/// @return true
12815bool
12817{
12818 diff* d = dif;
12819 visit(d, pre);
12820
12821 return true;
12822}
12823
12824/// Default visitor implementation.
12825///
12826/// @return true
12827bool
12829{
12830 diff* d = dif;
12831 visit(d, pre);
12832
12833 return true;
12834}
12835
12836/// Default visitor implementation.
12837///
12838/// @return true
12839bool
12841{
12842 diff* d = dif;
12843 visit(d, pre);
12844
12845 return true;
12846}
12847
12848/// Default visitor implementation.
12849///
12850/// @return true
12851bool
12853{
12854 diff* d = dif;
12855 visit(d, pre);
12856
12857 return true;
12858}
12859
12860/// Default visitor implementation.
12861///
12862/// @return true
12863bool
12865{
12866 diff* d = dif;
12867 visit(d, pre);
12868
12869 return true;
12870}
12871
12872/// Default visitor implementation.
12873///
12874/// @return true
12875bool
12877{
12878 diff* d = dif;
12879 visit(d, pre);
12880
12881 return true;
12882}
12883
12884/// Default visitor implementation.
12885///
12886/// @return true
12887bool
12889{
12890 diff* d = dif;
12891 visit(d, pre);
12892
12893 return true;
12894}
12895
12896/// Default visitor implementation.
12897///
12898/// @return true
12899bool
12901{
12902 diff* d = dif;
12903 visit(d, pre);
12904
12905 return true;
12906}
12907
12908/// Default visitor implementation.
12909///
12910/// @return true
12911bool
12913{
12914 diff* d = dif;
12915 visit(d, pre);
12916
12917 return true;
12918}
12919
12920/// Default visitor implementation.
12921///
12922/// @return true
12923bool
12925{
12926 diff* d = dif;
12927 visit(d, pre);
12928
12929 return true;
12930}
12931
12932/// Default visitor implementation.
12933///
12934/// @return true
12935bool
12937{
12938 diff* d = dif;
12939 visit(d, pre);
12940
12941 return true;
12942}
12943
12944/// Default visitor implementation.
12945///
12946/// @return true
12947bool
12949{
12950 diff* d = dif;
12951 visit(d, pre);
12952
12953 return true;
12954}
12955
12956/// Default visitor implementation.
12957///
12958/// @return true
12959bool
12961{return true;}
12962
12963// </diff_node_visitor stuff>
12964
12965// <redundant diff node marking>
12966
12967// </redundant diff node marking>
12968
12969// <diff tree category propagation>
12970
12971/// A visitor to propagate the category of a node up to its parent
12972/// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
12973/// SUPPRESSED_CATEGORY because those are propagated using other
12974/// specific visitors.
12975struct category_propagation_visitor : public diff_node_visitor
12976{
12977 virtual void
12978 visit_end(diff* d)
12979 {
12980 // Has this diff node 'd' been already visited ?
12981 bool already_visited = d->context()->diff_has_been_visited(d);
12982
12983 // The canonical diff node of the class of equivalence of the diff
12984 // node 'd'.
12985 diff* canonical = d->get_canonical_diff();
12986
12987 // If this class of equivalence of diff node is being visited for
12988 // the first time, then update its canonical node's category too.
12989 bool update_canonical = !already_visited && canonical;
12990
12991 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12992 i != d->children_nodes().end();
12993 ++i)
12994 {
12995 // If we are visiting the class of equivalence of 'd' for the
12996 // first time, then let's look at the children of 'd' and
12997 // propagate their categories to 'd'.
12998 //
12999 // If the class of equivalence of 'd' has already been
13000 // visited, then let's look at the canonical diff nodes of the
13001 // children of 'd' and propagate their categories to 'd'.
13002 diff* diff = already_visited
13003 ? (*i)->get_canonical_diff()
13004 : *i;
13005
13007
13009 // Do not propagate redundant and suppressed categories. Those
13010 // are propagated in a specific pass elsewhere.
13011 c &= ~(REDUNDANT_CATEGORY
13017 // Also, if a (class) type has got a harmful name change, do not
13018 // propagate harmless name changes coming from its sub-types
13019 // (i.e, data members) to the class itself.
13022
13023 d->add_to_category(c);
13024 if (!already_visited && canonical)
13025 if (update_canonical)
13026 canonical->add_to_category(c);
13027 }
13028
13031 {
13032 // The current diff node has either:
13033 //
13034 // 1/ a harmless "void pointer to pointer" change
13035 //
13036 // or:
13037 //
13038 // 2/ a harmless "enum to int" change.
13039 //
13040 // The change 1/ was most likely flagged locally as a
13041 // non-compatible distinct change, aka, a non-compatible
13042 // change between two types of different kinds. At a higher
13043 // level however, as we see that it's just a void pointer to
13044 // pointer change, we should unset the
13045 // NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY categorization.
13046 //
13047 // The change 2/ was most likely flagged locally (in the
13048 // children nodes of the current diff node) as a
13049 // non-compatible name change. At a higher level however, as
13050 // we see that it's just a harmless "enum to int" change,
13051 // let's unset the NON_COMPATIBLE_NAME_CHANGE_CATEGORY
13052 // categorization as well.
13053 diff_category c = d->get_category();
13054 c &= (~NON_COMPATIBLE_NAME_CHANGE_CATEGORY
13055 & ~NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY);
13056 d->set_category(c);
13058 {
13059 // For pointers and references, changes to
13060 // pointed-to-types are considered local. So, if some
13061 // pointed-to-types have non-compatible name or distinct
13062 // change, then the local category of the
13063 // pointer/reference will reflect that. Let's thus clear
13064 // those NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY and
13065 // NON_COMPATIBLE_NAME_CHANGE_CATEGORY bits from the local
13066 // category as well.
13067 c = d->get_local_category();
13068 c &= (~NON_COMPATIBLE_NAME_CHANGE_CATEGORY
13069 & ~NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY);
13070 d->set_local_category(c);
13071 }
13072 }
13073
13075 {
13076 diff_category c = d->get_category();
13077 c &= ~NON_COMPATIBLE_NAME_CHANGE_CATEGORY;
13078 d->set_category(c);
13079 }
13080 }
13081};// end struct category_propagation_visitor
13082
13083/// Visit all the nodes of a given sub-tree. For each node that has a
13084/// particular category set, propagate that category set up to its
13085/// parent nodes.
13086///
13087/// @param diff_tree the diff sub-tree to walk for categorization
13088/// purpose;
13089void
13091{
13092 category_propagation_visitor v;
13093 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13094 diff_tree->context()->forbid_visiting_a_node_twice(true);
13095 diff_tree->context()->forget_visited_diffs();
13096 diff_tree->traverse(v);
13097 diff_tree->context()->forbid_visiting_a_node_twice(s);
13098}
13099
13100/// Visit all the nodes of a given sub-tree. For each node that has a
13101/// particular category set, propagate that category set up to its
13102/// parent nodes.
13103///
13104/// @param diff_tree the diff sub-tree to walk for categorization
13105/// purpose;
13106void
13108{propagate_categories(diff_tree.get());}
13109
13110/// Visit all the nodes of a given corpus tree. For each node that
13111/// has a particular category set, propagate that category set up to
13112/// its parent nodes.
13113///
13114/// @param diff_tree the corpus_diff tree to walk for categorization
13115/// purpose;
13116void
13118{
13119 category_propagation_visitor v;
13120 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13121 diff_tree->context()->forbid_visiting_a_node_twice(false);
13122 diff_tree->traverse(v);
13123 diff_tree->context()->forbid_visiting_a_node_twice(s);
13124}
13125
13126/// Visit all the nodes of a given corpus tree. For each node that
13127/// has a particular category set, propagate that category set up to
13128/// its parent nodes.
13129///
13130/// @param diff_tree the corpus_diff tree to walk for categorization
13131/// purpose;
13132void
13134{propagate_categories(diff_tree.get());}
13135
13136/// A tree node visitor that knows how to categorizes a given diff
13137/// node in the SUPPRESSED_CATEGORY category and how to propagate that
13138/// categorization.
13139struct suppression_categorization_visitor : public diff_node_visitor
13140{
13141
13142 /// Before visiting the children of the diff node, check if the node
13143 /// is suppressed by a suppression specification. If it is, mark
13144 /// the node as belonging to the SUPPRESSED_CATEGORY category.
13145 ///
13146 /// @param p the diff node to visit.
13147 virtual void
13148 visit_begin(diff* d)
13149 {
13150 bool is_private_type = false;
13151 if (d->is_suppressed(is_private_type))
13152 {
13153 diff_category c = is_private_type
13157
13158 // If a node was suppressed, all the other nodes of its class
13159 // of equivalence are suppressed too.
13160 diff *canonical_diff = d->get_canonical_diff();
13161 if (canonical_diff != d)
13162 canonical_diff->add_to_category(c);
13163 }
13165 {
13166 // This diff node is specifically allowed by a
13167 // negated_suppression, then mark it as being in the
13168 // HAS_ALLOWED_CHANGE_CATEGORY.
13171 diff *canonical_diff = d->get_canonical_diff();
13172 canonical_diff->add_to_category(c);
13173
13174 // Note that some complementary code later down below does
13175 // categorize the descendants and parents nodes of this node
13176 // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
13177 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
13178 }
13179
13180 // If a parent node has been allowed by a negated suppression
13181 // specification, then categorize the current node as
13182 // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
13183 if (d->parent_node())
13184 {
13189 else
13190 {
13191 c = d->parent_node()->get_category();
13195 }
13196 }
13197
13198 }
13199
13200 /// After visiting the children nodes of a given diff node,
13201 /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
13202 /// diff node, if need be.
13203 ///
13204 /// That is, if all children nodes carry a suppressed change the
13205 /// current node should be marked as suppressed as well.
13206 ///
13207 /// In practice, this might be too strong of a condition. If the
13208 /// current node carries a local change (i.e, a change not carried
13209 /// by any of its children node) and if that change is not
13210 /// suppressed, then the current node should *NOT* be suppressed.
13211 ///
13212 /// But right now, the IR doesn't let us know about local vs
13213 /// children-carried changes. So we cannot be that precise yet.
13214 virtual void
13215 visit_end(diff* d)
13216 {
13217 bool has_non_suppressed_child = false;
13218 bool has_non_empty_child = false;
13219 bool has_suppressed_child = false;
13220 bool has_non_private_child = false;
13221 bool has_private_child = false;
13222 bool has_descendant_with_allowed_change = false;
13223
13224 if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
13225 // (or the PRIVATE_TYPE_CATEGORY for the same matter)
13226 // category from its children is a node which:
13227 //
13228 // 1/ hasn't been suppressed already
13229 //
13230 // 2/ and has no local change (unless it's a pointer,
13231 // reference or qualified diff node).
13232 //
13233 // Note that qualified type and typedef diff nodes are a bit
13234 // special. The local changes of the underlying type are
13235 // considered local for the qualified/typedef type, just like
13236 // for pointer/reference types. But then the qualified or
13237 // typedef type itself can have local changes of its own, and
13238 // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
13239 // So a qualified type which have local changes that are
13240 // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
13241 // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
13242 // or SUPPRESSED_CATEGORY can see these categories be
13243 // propagated.
13244 //
13245 // Note that all pointer/reference diff node changes are
13246 // potentially considered local, i.e, local changes of the
13247 // pointed-to-type are considered local to the pointer itself.
13248 //
13249 // Similarly, changes local to the type of function parameters,
13250 // variables (and data members) and classes (that are not of
13251 // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
13252 // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
13253 // those kinds of diff node.
13254 !(d->get_category() & SUPPRESSED_CATEGORY)
13255 && (!d->has_local_changes()
13256 || is_pointer_diff(d)
13257 || is_reference_diff(d)
13259 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13260 || (is_typedef_diff(d)
13261 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13263 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13264 || (is_fn_parm_diff(d)
13265 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13267 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13268 || (is_var_diff(d)
13269 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13270 || (is_class_diff(d)
13271 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
13272 {
13273 // Note that we handle private diff nodes differently from
13274 // generally suppressed diff nodes. E.g, it's not because a
13275 // type is private (and suppressed because of that; i.e, in
13276 // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
13277 // type should also be private and so suppressed. Private
13278 // diff nodes thus have different propagation rules than
13279 // generally suppressed rules.
13280 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
13281 i != d->children_nodes().end();
13282 ++i)
13283 {
13284 diff* child = *i;
13285 if (child->has_changes())
13286 {
13287 has_non_empty_child = true;
13288 if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
13289 has_suppressed_child = true;
13290 else if (child->get_class_of_equiv_category()
13292 // Propagation of the PRIVATE_TYPE_CATEGORY is going
13293 // to be handled later below.
13294 ;
13295 else
13296 has_non_suppressed_child = true;
13297
13298 if (child->get_class_of_equiv_category()
13300 has_private_child = true;
13301 else if (child->get_class_of_equiv_category()
13303 // Propagation of the SUPPRESSED_CATEGORY has been
13304 // handled above already.
13305 ;
13306 else
13307 has_non_private_child = true;
13308 }
13309 }
13310
13311 if (has_non_empty_child
13312 && has_suppressed_child
13313 && !has_non_suppressed_child)
13314 {
13316 // If a node was suppressed, all the other nodes of its class
13317 // of equivalence are suppressed too.
13318 diff *canonical_diff = d->get_canonical_diff();
13319 if (canonical_diff != d)
13320 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
13321 }
13322
13323 // Note that the private-ness of a an underlying type won't be
13324 // propagated to its parent typedef, by virtue of the big "if"
13325 // clause at the beginning of this function. So we don't have
13326 // to handle that case here. So the idiom of defining
13327 // typedefs of private (opaque) types will be respected;
13328 // meaning that changes to opaque underlying type will be
13329 // flagged as private and the typedef will be flagged private
13330 // as well, unless the typedef itself has local non-type
13331 // changes. In the later case, changes to the typedef will be
13332 // emitted because the typedef won't inherit the privateness
13333 // of its underlying type. So in practise, the typedef
13334 // remains public for the purpose of change reporting.
13335 if (has_non_empty_child
13336 && has_private_child
13337 && !has_non_private_child)
13338 {
13339 d->add_to_category(PRIVATE_TYPE_CATEGORY);
13340 // If a node was suppressed, all the other nodes of its class
13341 // of equivalence are suppressed too.
13342 diff *canonical_diff = d->get_canonical_diff();
13343 if (canonical_diff != d)
13344 canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
13345 }
13346
13347 // If the underlying type of a typedef is private and carries
13348 // changes (that are implicitely suppressed because it's
13349 // private) then the typedef must be suppressed too, so that
13350 // those changes to the underlying type are not seen.
13351 if (is_typedef_diff(d)
13352 && !d->has_local_changes()
13353 && has_private_child
13354 && has_non_empty_child)
13355 {
13356 d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
13357 // If a node was suppressed, all the other nodes of its class
13358 // of equivalence are suppressed too.
13359 diff *canonical_diff = d->get_canonical_diff();
13360 if (canonical_diff != d)
13361 canonical_diff->add_to_category
13363 }
13364
13365 if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
13366 if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
13367 {
13368 // d is a function diff that carries a local *type*
13369 // change (that means it's a change to the function
13370 // type). Let's see if the child function type diff
13371 // node is suppressed. That would mean that we are
13372 // instructed to show details of a diff that is deemed
13373 // suppressed; this means the suppression conflicts with
13374 // a local type change. In that case, let's follow what
13375 // the user asked and suppress the function altogether,
13376 if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
13377 if (fn_type_diff->is_suppressed())
13378 {
13379 d->add_to_category(SUPPRESSED_CATEGORY);
13380 // If a node was suppressed, all the other nodes
13381 // of its class of equivalence are suppressed too.
13382 diff *canonical_diff = d->get_canonical_diff();
13383 if (canonical_diff != d)
13384 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
13385 }
13386 }
13387 }
13388
13389 // If any descendant node was selected by a negated suppression
13390 // specification then categorize the current one as
13391 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
13392 for (auto child_node : d->children_nodes())
13393 {
13394 diff *canonical_diff = child_node->get_canonical_diff();
13395 diff_category c = canonical_diff->get_category();
13398 has_descendant_with_allowed_change = true;
13399 }
13400 if (has_descendant_with_allowed_change)
13401 {
13403 d->add_to_category(c);
13404 d->get_canonical_diff()->add_to_category(c);
13405 }
13406 }
13407}; //end struct suppression_categorization_visitor
13408
13409/// Walk a given diff-sub tree and appply the suppressions carried by
13410/// the context. If the suppression applies to a given node than
13411/// categorize the node into the SUPPRESSED_CATEGORY category and
13412/// propagate that categorization.
13413///
13414/// @param diff_tree the diff-sub tree to apply the suppressions to.
13415void
13417{
13418 if (diff_tree && !diff_tree->context()->suppressions().empty())
13419 {
13420 // Apply suppressions to functions and variables that have
13421 // changed sub-types.
13422 suppression_categorization_visitor v;
13423 diff_tree->context()->forget_visited_diffs();
13424 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13425 diff_tree->context()->forbid_visiting_a_node_twice(true);
13426 diff_tree->traverse(v);
13427 diff_tree->context()->forbid_visiting_a_node_twice(s);
13428 }
13429}
13430
13431/// Walk a given diff-sub tree and appply the suppressions carried by
13432/// the context. If the suppression applies to a given node than
13433/// categorize the node into the SUPPRESSED_CATEGORY category and
13434/// propagate that categorization.
13435///
13436/// @param diff_tree the diff-sub tree to apply the suppressions to.
13437void
13439{apply_suppressions(diff_tree.get());}
13440
13441/// Walk a @ref corpus_diff tree and appply the suppressions carried
13442/// by the context. If the suppression applies to a given node then
13443/// categorize the node into the SUPPRESSED_CATEGORY category and
13444/// propagate that categorization.
13445///
13446/// @param diff_tree the diff tree to apply the suppressions to.
13447void
13449{
13450 if (diff_tree && !diff_tree->context()->suppressions().empty())
13451 {
13452 // First, visit the children trees of changed constructs:
13453 // changed functions, variables, as well as sub-types of these,
13454 // and apply suppression specifications to these ...
13455 suppression_categorization_visitor v;
13456 diff_tree->context()->forget_visited_diffs();
13457 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13458 diff_tree->context()->forbid_visiting_a_node_twice(true);
13459 const_cast<corpus_diff*>(diff_tree)->traverse(v);
13460 diff_tree->context()->forbid_visiting_a_node_twice(s);
13461
13462 // ... then also visit the set of added and removed functions,
13463 // variables, symbols, and types not reachable from global
13464 // functions and variables.
13465 diff_tree->priv_->
13466 apply_supprs_to_added_removed_fns_vars_unreachable_types();
13467 }
13468}
13469
13470/// Walk a diff tree and appply the suppressions carried by the
13471/// context. If the suppression applies to a given node than
13472/// categorize the node into the SUPPRESSED_CATEGORY category and
13473/// propagate that categorization.
13474///
13475/// @param diff_tree the diff tree to apply the suppressions to.
13476void
13478{apply_suppressions(diff_tree.get());}
13479
13480// </diff tree category propagation>
13481
13482// <diff tree printing stuff>
13483
13484/// A visitor to print (to an output stream) a pretty representation
13485/// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
13486struct diff_node_printer : public diff_node_visitor
13487{
13488 ostream& out_;
13489 unsigned level_;
13490
13491 /// Emit a certain number of spaces to the output stream associated
13492 /// to this diff_node_printer.
13493 ///
13494 /// @param level half of the numver of spaces to emit.
13495 void
13496 do_indent(unsigned level)
13497 {
13498 for (unsigned i = 0; i < level; ++i)
13499 out_ << " ";
13500 }
13501
13502 diff_node_printer(ostream& out)
13503 : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
13504 out_(out),
13505 level_(0)
13506 {}
13507
13508 virtual void
13509 visit_begin(diff*)
13510 {
13511 ++level_;
13512 }
13513
13514 virtual void
13515 visit_end(diff*)
13516 {
13517 --level_;
13518 }
13519
13520 virtual void
13521 visit_begin(corpus_diff*)
13522 {
13523 ++level_;
13524 }
13525
13526 virtual void
13527 visit_end(corpus_diff*)
13528 {
13529 --level_;
13530 }
13531
13532 virtual bool
13533 visit(diff* d, bool pre)
13534 {
13535 if (!pre)
13536 // We are post-visiting the diff node D. Which means, we have
13537 // printed a pretty representation for it already. So do
13538 // nothing now.
13539 return true;
13540
13541 do_indent(level_);
13542 out_ << d->get_pretty_representation();
13543 out_ << "\n";
13544 do_indent(level_);
13545 out_ << "{\n";
13546 do_indent(level_ + 1);
13547 out_ << "category: "<< d->get_category() << "\n";
13548 do_indent(level_ + 1);
13549 out_ << "local category: "<< d->get_local_category() << "\n";
13550 do_indent(level_ + 1);
13551 out_ << "@: " << std::hex << d << std::dec << "\n";
13552 do_indent(level_ + 1);
13553 out_ << "@-canonical: " << std::hex
13554 << d->get_canonical_diff()
13555 << std::dec << "\n";
13556 do_indent(level_);
13557 out_ << "}\n";
13558
13559 return true;
13560 }
13561
13562 virtual bool
13563 visit(corpus_diff* d, bool pre)
13564 {
13565 if (!pre)
13566 // We are post-visiting the diff node D. Which means, we have
13567 // printed a pretty representation for it already. So do
13568 // nothing now.
13569 return true;
13570
13571 // indent
13572 for (unsigned i = 0; i < level_; ++i)
13573 out_ << ' ';
13574 out_ << d->get_pretty_representation();
13575 out_ << '\n';
13576 return true;
13577 }
13578}; // end struct diff_printer_visitor
13579
13580// </ diff tree printing stuff>
13581
13582/// Emit a textual representation of a @ref diff sub-tree to an
13583/// output stream.
13584///
13585/// @param diff_tree the sub-tree to emit the textual representation
13586/// for.
13587///
13588/// @param out the output stream to emit the textual representation
13589/// for @p diff_tree to.
13590void
13591print_diff_tree(diff* diff_tree, ostream& out)
13592{
13593 diff_node_printer p(out);
13594 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13595 diff_tree->context()->forbid_visiting_a_node_twice(false);
13596 diff_tree->traverse(p);
13597 diff_tree->context()->forbid_visiting_a_node_twice(s);
13598}
13599
13600/// Emit a textual representation of a @ref corpus_diff tree to an
13601/// output stream.
13602///
13603/// @param diff_tree the @ref corpus_diff tree to emit the textual
13604/// representation for.
13605///
13606/// @param out the output stream to emit the textual representation
13607/// for @p diff_tree to.
13608void
13609print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
13610{
13611 diff_node_printer p(out);
13612 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13613 diff_tree->context()->forbid_visiting_a_node_twice(false);
13614 diff_tree->traverse(p);
13615 diff_tree->context()->forbid_visiting_a_node_twice(s);
13616}
13617
13618/// Emit a textual representation of a @ref diff sub-tree to an
13619/// output stream.
13620///
13621/// @param diff_tree the sub-tree to emit the textual representation
13622/// for.
13623///
13624/// @param out the output stream to emit the textual representation
13625/// for @p diff_tree to.
13626void
13628 std::ostream& o)
13629{print_diff_tree(diff_tree.get(), o);}
13630
13631/// Emit a textual representation of a @ref corpus_diff tree to an
13632/// output stream.
13633///
13634/// @param diff_tree the @ref corpus_diff tree to emit the textual
13635/// representation for.
13636///
13637/// @param out the output stream to emit the textual representation
13638/// for @p diff_tree to.
13639void
13641 std::ostream& o)
13642{print_diff_tree(diff_tree.get(), o);}
13643
13644/// Print a given category out to stdout for debuging purposes
13645///
13646/// @param c the category to print to stdout.
13647void
13649{
13650 std::cout << c << std::endl;
13651}
13652
13653// <redundancy_marking_visitor>
13654
13655/// A tree visitor to categorize nodes with respect to the
13656/// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
13657/// present on several spots of the tree) and mark such nodes
13658/// appropriatly. This visitor also takes care of propagating the
13659/// REDUNDANT_CATEGORY of a given node to its parent nodes as
13660/// appropriate.
13661struct redundancy_marking_visitor : public diff_node_visitor
13662{
13663 bool skip_children_nodes_;
13664
13665 redundancy_marking_visitor()
13666 : skip_children_nodes_()
13667 {}
13668
13669 virtual void
13670 visit_begin(diff* d)
13671 {
13672 if (d->to_be_reported())
13673 {
13674 // A diff node that carries a change and that has been already
13675 // traversed elsewhere is considered redundant. So let's mark
13676 // it as such and let's not traverse it; that is, let's not
13677 // visit its children.
13678 if ((d->context()->diff_has_been_visited(d)
13679 || d->get_canonical_diff()->is_traversing())
13680 && d->has_changes())
13681 {
13682 // But if two diff nodes are redundant sibbling that carry
13683 // changes of base types, do not mark them as being
13684 // redundant. This is to avoid marking nodes as redundant
13685 // in this case:
13686 //
13687 // int foo(int a, int b);
13688 // compared with:
13689 // float foo(float a, float b); (in C).
13690 //
13691 // In this case, we want to report all the occurences of
13692 // the int->float change because logically, they are at
13693 // the same level in the diff tree.
13694
13695 bool redundant_with_sibling_node = false;
13696 const diff* p = d->parent_node();
13697
13698 // If this is a child node of a fn_parm_diff, look through
13699 // the fn_parm_diff node to get the function diff node.
13700 if (p && dynamic_cast<const fn_parm_diff*>(p))
13701 p = p->parent_node();
13702
13703 if (p)
13704 for (vector<diff*>::const_iterator s =
13705 p->children_nodes().begin();
13706 s != p->children_nodes().end();
13707 ++s)
13708 {
13709 if (*s == d)
13710 continue;
13711 diff* sib = *s;
13712 // If this is a fn_parm_diff, look through the
13713 // fn_parm_diff node to get at the real type node.
13714 if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
13715 sib = f->type_diff().get();
13716 if (sib == d)
13717 continue;
13718 if (sib->get_canonical_diff() == d->get_canonical_diff()
13719 // Sibbling diff nodes that carry base type
13720 // changes are to be marked as redundant.
13721 && (is_base_diff(sib) || is_distinct_diff(sib)))
13722 {
13723 redundant_with_sibling_node = true;
13724 break;
13725 }
13726 }
13727 if (!redundant_with_sibling_node
13728 // Changes to basic types should never be considered
13729 // redundant. For instance, if a member of integer
13730 // type is changed into a char type in both a struct A
13731 // and a struct B, we want to see both changes.
13733 // The same goes for distinct type changes
13735 // Functions with similar *local* changes are never marked
13736 // redundant because otherwise one could miss important
13737 // similar local changes that are applied to different
13738 // functions.
13740 // Changes involving variadic parameters of functions
13741 // should never be marked redundant because we want to see
13742 // them all.
13745 // If the canonical diff itself has been filtered out,
13746 // then this one is not marked redundant, unless the
13747 // canonical diff was already redundant.
13748 && (!d->get_canonical_diff()->is_filtered_out()
13749 || (d->get_canonical_diff()->get_category()
13751 // If the *same* diff node (not one that is merely
13752 // equivalent to this one) has already been visited
13753 // the do not mark it as beind redundant. It's only
13754 // the other nodes that are equivalent to this one
13755 // that must be marked redundant.
13756 && d->context()->diff_has_been_visited(d) != d
13757 // If the diff node is a function parameter and is not
13758 // a reference/pointer (to a non basic or a non
13759 // distinct type diff) then do not mark it as
13760 // redundant.
13761 //
13762 // Children nodes of base class diff nodes are never
13763 // redundant either, we want to see them all.
13767 {
13769 // As we said in preamble, as this node is marked as
13770 // being redundant, let's not visit its children.
13771 // This is not an optimization; it's needed for
13772 // correctness. In the case of a diff node involving
13773 // a class type that refers to himself, visiting the
13774 // children nodes might cause them to be wrongly
13775 // marked as redundant.
13778 skip_children_nodes_ = true;
13779 }
13780 }
13781 }
13782 else
13783 {
13784 // If the node is not to be reported, do not look at it children.
13786 skip_children_nodes_ = true;
13787 }
13788 }
13789
13790 virtual void
13791 visit_begin(corpus_diff*)
13792 {
13793 }
13794
13795 virtual void
13796 visit_end(diff* d)
13797 {
13798 if (skip_children_nodes_)
13799 // When visiting this node, we decided to skip its children
13800 // node. Now that we are done visiting the node, lets stop
13801 // avoiding the children nodes visiting for the other tree
13802 // nodes.
13803 {
13805 skip_children_nodes_ = false;
13806 }
13807 else
13808 {
13809 // Propagate the redundancy categorization of the children
13810 // nodes to this node. But if this node has local harmful
13811 // changes then it doesn't inherit redundancy from its
13812 // children nodes.
13813 if (!(d->get_category() & REDUNDANT_CATEGORY)
13814 && ((!d->has_local_changes_to_be_reported()
13815 || !is_harmful_category(d->get_local_category()))
13816 // By default, pointer, reference, array and qualified
13817 // types consider that a local changes to their
13818 // underlying type is always a local change for
13819 // themselves.
13820 //
13821 // This is as if those types don't have local changes
13822 // in the same sense as other types. So we always
13823 // propagate redundancy to them, regardless of if they
13824 // have local changes or not.
13825 //
13826 // We also propagate redundancy to typedef types if
13827 // these /only/ carry changes to their underlying
13828 // type.
13829 //
13830 // Note that changes to the underlying type of a
13831 // typedef is considered local of
13832 // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
13833 // typedef itself are considered local of
13834 // LOCAL_NON_TYPE_CHANGE_KIND kind.
13835 || is_pointer_diff(d)
13836 || is_array_diff(d)
13838 // A typedef with local non-type changes should not
13839 // see redundancy propagation from its underlying
13840 // type, otherwise, the non-type change might be
13841 // "suppressed" away.
13842 || (is_typedef_diff(d)
13843 && (!(d->has_local_changes()
13845 // A (member) variable with non-type local changes
13846 // should not see redundacy propagation from its type.
13847 // If redundant local-type changes are carried by its
13848 // type however, then that redundancy is propagated to
13849 // the variable. This is key to keep the redundancy
13850 // consistency in the system; otherwise, a type change
13851 // would be rightfully considered redundant at some
13852 // places but not at others.
13853 || (is_var_diff(d)
13854 && (!(d->has_local_changes()
13856 // A function parameter with non-type local changes
13857 // should not see redundancy propagation either. But
13858 // a function parameter with local type changes can
13859 // definitely be redundant.
13860 || (is_fn_parm_diff(d)
13861 && (!(d->has_local_changes()
13863 ))
13864 {
13865 bool has_non_redundant_child = false;
13866 bool has_non_empty_child = false;
13867 bool is_array_diff_node = is_array_diff(d);
13868 for (vector<diff*>::const_iterator i =
13869 d->children_nodes().begin();
13870 i != d->children_nodes().end();
13871 ++i)
13872 {
13873 if ((*i)->has_changes())
13874 {
13875 // If we are looking at a child node of an array,
13876 // do not take a subrange diff node change into
13877 // account when considering redundancy. In other
13878 // words, a subrange diff node that carries a
13879 // change should not be considered as a non-empty
13880 // child node. This is because we want to report
13881 // all subrange diff node changes and not consider
13882 // them as redundant.
13883 if (!is_array_diff_node || !is_subrange_diff(*i))
13884 has_non_empty_child = true;
13885 // Let's see if the current child node '*i' is
13886 // "non-redundant".
13887 //
13888 // A non-redundant node would be a node that
13889 // carries a change to be reported and has not
13890 // been marked as being redundant.
13891 if ((*i)->to_be_reported()
13892 && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
13893 has_non_redundant_child = true;
13894 }
13895 if (has_non_redundant_child)
13896 break;
13897 }
13898
13899 // A diff node for which at least a child node carries a
13900 // change, and for which all the children are redundant is
13901 // deemed redundant too, unless it has local changes.
13902 if (has_non_empty_child
13903 && !has_non_redundant_child)
13904 d->add_to_category(REDUNDANT_CATEGORY);
13905 }
13906 }
13907 }
13908
13909 virtual void
13910 visit_end(corpus_diff*)
13911 {
13912 }
13913
13914 virtual bool
13915 visit(diff*, bool)
13916 {return true;}
13917
13918 virtual bool
13919 visit(corpus_diff*, bool)
13920 {
13921 return true;
13922 }
13923};// end struct redundancy_marking_visitor
13924
13925/// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13926/// category out of the nodes.
13927struct redundancy_clearing_visitor : public diff_node_visitor
13928{
13929 bool
13930 visit(corpus_diff*, bool)
13931 {return true;}
13932
13933 bool
13934 visit(diff* d, bool)
13935 {
13936 // clear the REDUNDANT_CATEGORY out of the current node.
13937 diff_category c = d->get_category();
13938 c &= ~REDUNDANT_CATEGORY;
13939 d->set_category(c);
13940 return true;
13941 }
13942}; // end struct redundancy_clearing_visitor
13943
13944/// Walk a given @ref diff sub-tree to categorize each of the nodes
13945/// with respect to the REDUNDANT_CATEGORY.
13946///
13947/// @param diff_tree the @ref diff sub-tree to walk.
13948void
13950{
13951 if (diff_tree->context()->show_redundant_changes())
13952 return;
13953 redundancy_marking_visitor v;
13954 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13955 diff_tree->context()->forbid_visiting_a_node_twice(false);
13956 diff_tree->traverse(v);
13957 diff_tree->context()->forbid_visiting_a_node_twice(s);
13958}
13959
13960/// Walk a given @ref diff sub-tree to categorize each of the nodes
13961/// with respect to the REDUNDANT_CATEGORY.
13962///
13963/// @param diff_tree the @ref diff sub-tree to walk.
13964void
13966{categorize_redundancy(diff_tree.get());}
13967
13968/// Walk a given @ref corpus_diff tree to categorize each of the nodes
13969/// with respect to the REDUNDANT_CATEGORY.
13970///
13971/// @param diff_tree the @ref corpus_diff tree to walk.
13972void
13974{
13975 redundancy_marking_visitor v;
13976 diff_tree->context()->forget_visited_diffs();
13977 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13978 diff_tree->context()->forbid_visiting_a_node_twice(false);
13979 diff_tree->traverse(v);
13980 diff_tree->context()->forbid_visiting_a_node_twice(s);
13981}
13982
13983/// Walk a given @ref corpus_diff tree to categorize each of the nodes
13984/// with respect to the REDUNDANT_CATEGORY.
13985///
13986/// @param diff_tree the @ref corpus_diff tree to walk.
13987void
13989{categorize_redundancy(diff_tree.get());}
13990
13991// </redundancy_marking_visitor>
13992
13993/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13994/// out of the category of the nodes.
13995///
13996/// @param diff_tree the @ref diff sub-tree to walk.
13997void
13999{
14000 redundancy_clearing_visitor v;
14001 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
14002 diff_tree->context()->forbid_visiting_a_node_twice(false);
14003 diff_tree->traverse(v);
14004 diff_tree->context()->forbid_visiting_a_node_twice(s);
14005 diff_tree->context()->forget_visited_diffs();
14006}
14007
14008/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
14009/// out of the category of the nodes.
14010///
14011/// @param diff_tree the @ref diff sub-tree to walk.
14012void
14014{clear_redundancy_categorization(diff_tree.get());}
14015
14016/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
14017/// out of the category of the nodes.
14018///
14019/// @param diff_tree the @ref corpus_diff tree to walk.
14020void
14022{
14023 redundancy_clearing_visitor v;
14024 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
14025 diff_tree->context()->forbid_visiting_a_node_twice(false);
14026 diff_tree->traverse(v);
14027 diff_tree->context()->forbid_visiting_a_node_twice(s);
14028 diff_tree->context()->forget_visited_diffs();
14029}
14030
14031/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
14032/// out of the category of the nodes.
14033///
14034/// @param diff_tree the @ref corpus_diff tree to walk.
14035void
14037{clear_redundancy_categorization(diff_tree.get());}
14038
14039/// Apply the @ref diff tree filters that have been associated with
14040/// the context of the a given @ref diff, categorize the diff nodes
14041/// subsequently. As a result, the nodes of the @p diff_tree tree are
14042/// going to be properly filtered out at reporting time.
14043///
14044/// @param diff_tree the @ref diff instance to consider.
14045void
14047{
14048 if (!diff_tree)
14049 return;
14050
14051 diff_context_sptr ctxt = diff_tree->context();
14052 ABG_ASSERT(ctxt);
14053
14054 if (!ctxt->perform_change_categorization())
14055 return;
14056
14057 apply_suppressions(diff_tree);
14058 ctxt->maybe_apply_filters(diff_tree);
14059 categorize_redundancy(diff_tree);
14060}
14061
14062/// Apply the @ref diff tree filters that have been associated with
14063/// the context of the a given @ref corpus_diff, categorize the diff
14064/// nodes subsequently. As a result, the nodes of the @p c tree are
14065/// going to be properly filtered out at reporting time.
14066///
14067/// @param c the @ref corpus_diff instance to consider.
14068void
14070{
14071 if (c)
14072 c->apply_filters_and_suppressions_before_reporting();
14073}
14074
14075/// Test if a diff node represents the difference between a variadic
14076/// parameter type and something else.
14077///
14078/// @param d the diff node to consider.
14079///
14080/// @return true iff @p d is a diff node that represents the
14081/// difference between a variadic parameter type and something else.
14082bool
14084{
14085 if (!d)
14086 return false;
14087
14088 type_base_sptr t = is_type(d->first_subject());
14089 if (t && t->get_environment().is_variadic_parameter_type(t))
14090 return true;
14091
14092 t = is_type(d->second_subject());
14093 if (t && t->get_environment().is_variadic_parameter_type(t))
14094 return true;
14095
14096 return false;
14097}
14098
14099/// Test if a diff node represents the difference between a variadic
14100/// parameter type and something else.
14101///
14102/// @param d the diff node to consider.
14103///
14104/// @return true iff @p d is a diff node that represents the
14105/// difference between a variadic parameter type and something else.
14106bool
14108{return is_diff_of_variadic_parameter_type(d.get());}
14109
14110/// Test if a diff node represents the difference between a variadic
14111/// parameter and something else.
14112///
14113/// @param d the diff node to consider.
14114///
14115/// @return true iff @p d is a diff node that represents the
14116/// difference between a variadic parameter and something else.
14117bool
14119{
14121 dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
14122 return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
14123}
14124
14125/// Test if a diff node represents the difference between a variadic
14126/// parameter and something else.
14127///
14128/// @param d the diff node to consider.
14129///
14130/// @return true iff @p d is a diff node that represents the
14131/// difference between a variadic parameter and something else.
14132bool
14134{return is_diff_of_variadic_parameter(d.get());}
14135
14136/// Test if a diff node represents a diff between two basic types.
14137///
14138/// @param d the diff node to consider.
14139///
14140/// @return true iff @p d is a diff between two basic types.
14141const type_decl_diff*
14143{return dynamic_cast<const type_decl_diff*>(d);}
14144
14145/// Test if a diff node represents a diff between two basic types, or
14146/// between pointers, references or qualified type to basic types.
14147///
14148/// @param diff the diff node to consider.
14149///
14150/// @param allow_indirect_type if true, then this function looks into
14151/// pointer, reference or qualified diff types to see if they "point
14152/// to" basic types.
14153///
14154/// @return true iff @p d is a diff between two basic types.
14155const type_decl_diff*
14156is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
14157{
14158 if (allow_indirect_type)
14161}
14162
14163/// If a diff node is about changes between two typedef types, get the
14164/// diff node about changes between the underlying types.
14165///
14166/// Note that this function walks the tree of underlying diff nodes
14167/// returns the first diff node about types that are not typedefs.
14168///
14169/// @param dif the dif node to consider.
14170///
14171/// @return the underlying diff node of @p dif, or just return @p dif
14172/// if it's not a typedef diff node.
14173const diff*
14175{
14176 const typedef_diff *d = 0;
14177 while ((d = is_typedef_diff(dif)))
14178 dif = d->underlying_type_diff().get();
14179 return dif;
14180}
14181
14182/// If a diff node is about changes between two pointer types, get the
14183/// diff node about changes between the underlying (pointed-to) types.
14184///
14185/// Note that this function walks the tree of underlying diff nodes
14186/// returns the first diff node about types that are not pointers.
14187///
14188/// @param dif the dif node to consider.
14189///
14190/// @return the underlying diff node of @p dif, or just return @p dif
14191/// if it's not a pointer diff node.
14192const diff*
14194{
14195 const pointer_diff *d = 0;
14196 while ((d = is_pointer_diff(dif)))
14197 dif = d->underlying_type_diff().get();
14198 return dif;
14199}
14200
14201/// If a diff node is about changes between two reference types, get
14202/// the diff node about changes between the underlying (pointed-to)
14203/// types.
14204///
14205/// Note that this function walks the tree of underlying diff nodes
14206/// returns the first diff node about types that are not references.
14207///
14208/// @param dif the dif node to consider.
14209///
14210/// @return the underlying diff node of @p dif, or just return @p dif
14211/// if it's not a reference diff node.
14212const diff*
14214{
14215 const reference_diff *d = 0;
14216 while ((d = is_reference_diff(dif)))
14217 dif = d->underlying_type_diff().get();
14218 return dif;
14219}
14220
14221/// If a diff node is about changes between two qualified types, get
14222/// the diff node about changes between the underlying (non-qualified)
14223/// types.
14224///
14225/// Note that this function walks the tree of underlying diff nodes
14226/// returns the first diff node about types that are not qualified.
14227///
14228/// @param dif the dif node to consider.
14229///
14230/// @return the underlying diff node of @p dif, or just return @p dif
14231/// if it's not a qualified diff node.
14232const diff*
14234{
14235 const qualified_type_diff *d = 0;
14236 while ((d = is_qualified_type_diff(dif)))
14237 dif = d->underlying_type_diff().get();
14238 return dif;
14239}
14240
14241/// If a diff node is about changes between two function parameters
14242/// get the diff node about changes between the types of the parameters.
14243///
14244/// @param dif the dif node to consider.
14245///
14246/// @return the diff of the types of the parameters.
14247const diff*
14249{
14250 const fn_parm_diff *d = 0;
14251 while ((d = is_fn_parm_diff(dif)))
14252 dif = d->type_diff().get();
14253 return dif;
14254}
14255
14256/// If a diff node is about changes between two pointer, reference or
14257/// qualified types, get the diff node about changes between the
14258/// underlying types.
14259///
14260/// Note that this function walks the tree of underlying diff nodes
14261/// returns the first diff node about types that are not pointer,
14262/// reference or qualified.
14263///
14264/// @param dif the dif node to consider.
14265///
14266/// @return the underlying diff node of @p dif, or just return @p dif
14267/// if it's not a pointer, reference or qualified diff node.
14268const diff*
14270{
14271 while (true)
14272 {
14273 if (const pointer_diff *d = is_pointer_diff(dif))
14274 dif = peel_pointer_diff(d);
14275 else if (const reference_diff *d = is_reference_diff(dif))
14276 dif = peel_reference_diff(d);
14277 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14278 dif = peel_qualified_diff(d);
14279 else
14280 break;
14281 }
14282 return dif;
14283}
14284
14285/// If a diff node is about changes between two typedefs or qualified
14286/// types, get the diff node about changes between the underlying
14287/// types.
14288///
14289/// Note that this function walks the tree of underlying diff nodes
14290/// returns the first diff node about types that are not typedef or
14291/// qualified types.
14292///
14293/// @param dif the dif node to consider.
14294///
14295/// @return the underlying diff node of @p dif, or just return @p dif
14296/// if it's not typedef or qualified diff node.
14297const diff*
14299{
14300 while (true)
14301 {
14302 if (const typedef_diff *d = is_typedef_diff(dif))
14303 dif = peel_typedef_diff(d);
14304 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14305 dif = peel_qualified_diff(d);
14306 else
14307 break;
14308 }
14309 return dif;
14310}
14311
14312/// If a diff node is about changes between two typedefs or qualified
14313/// types, get the diff node about changes between the underlying
14314/// types.
14315///
14316/// Note that this function walks the tree of underlying diff nodes
14317/// returns the first diff node about types that are neither typedef,
14318/// qualified type nor parameters.
14319///
14320/// @param dif the dif node to consider.
14321///
14322/// @return the diff node about changes between the underlying types.
14323const diff*
14325{
14326 while (true)
14327 {
14328 if (const typedef_diff *d = is_typedef_diff(dif))
14329 dif = peel_typedef_diff(d);
14330 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14331 dif = peel_qualified_diff(d);
14332 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
14333 dif = peel_fn_parm_diff(d);
14334 else
14335 break;
14336 }
14337 return dif;
14338}
14339
14340/// Test if a diff node represents a diff between two class or union
14341/// types.
14342///
14343/// @param d the diff node to consider.
14344///
14345/// @return iff @p is a diff between two class or union types then
14346/// return the instance of @ref class_or_union_diff that @p derives
14347/// from. Otherwise, return nil.
14350{return dynamic_cast<const class_or_union_diff*>(d);}
14351
14352/// Test if a given diff node carries *only* a local type change.
14353///
14354/// @param d the diff node to consider.
14355///
14356/// @return true iff @p has a change and that change is a local type
14357/// change.
14358static bool
14359has_local_type_change_only(const diff *d)
14360{
14361 if (enum change_kind k = d->has_local_changes())
14362 if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
14363 && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
14364 return true;
14365
14366 return false;
14367}
14368
14369/// Test if a diff node is a decl diff that only carries a basic type
14370/// change on its type diff sub-node.
14371///
14372///Note that that pointers/references/qualified types diffs to basic
14373/// type diffs are considered as having basic type change only.
14374///
14375/// @param d the diff node to consider.
14376///
14377/// @return true iff @p d is a decl diff that only carries a basic
14378/// type change on its type diff sub-node.
14379bool
14381{
14383
14384 if (is_diff_of_basic_type(d, true) && d->has_changes())
14385 return true;
14386 else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
14387 return (has_local_type_change_only(v)
14388 && is_diff_of_basic_type(v->type_diff().get(), true));
14389 else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
14390 return (has_local_type_change_only(p)
14391 && is_diff_of_basic_type(p->type_diff().get(), true));
14392 else if (const function_decl_diff* f =
14393 dynamic_cast<const function_decl_diff*>(d))
14394 return (has_local_type_change_only(f)
14395 && f->type_diff()
14396 && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
14397 true));
14398 return false;
14399}
14400}// end namespace comparison
14401} // 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:1743
#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.
bool soname_changed() const
Test if the soname of the underlying corpus has changed.
friend corpus_diff_sptr compute_diff(const corpus_sptr f, const corpus_sptr s, diff_context_sptr ctxt)
Compute the diff between two instances of corpus.
const vector< type_base_sptr > & deleted_unreachable_types_sorted() const
Getter of a sorted vector of deleted types that are not reachable from global functions/variables.
edit_script & function_changes() const
edit_script & variable_changes() const
const vector< diff * > & children_nodes() const
const string_diff_sptr_map & changed_unreachable_types() const
Getter for a map of changed types that are not reachable from global functions/variables.
const var_diff_sptrs_type & changed_variables_sorted()
Getter for the sorted vector of variables which signature didn't change but which do have some indire...
const string_elf_symbol_map & deleted_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got deleted.
const string_elf_symbol_map & deleted_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got deleted.
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()
Apply the different filters that are registered to be applied to the diff tree; that includes the cat...
const string_var_diff_sptr_map & changed_variables()
Getter for the non-sorted map of variables which signature didn't change but which do have some indir...
const string_function_ptr_map & added_functions()
Getter for the added functions of the diff.
void mark_leaf_diff_nodes()
Walks the diff nodes associated to the current corpus diff and mark those that carry local changes....
const string_type_base_sptr_map & deleted_unreachable_types() const
Getter for a map of deleted types that are not reachable from global functions/variables.
const vector< type_base_sptr > & added_unreachable_types_sorted() const
Getter of a sorted vector of added types that are not reachable from global functions/variables.
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 string & get_pretty_representation() const
const string_function_ptr_map & deleted_functions() const
Getter for the deleted functions of the diff.
void append_child_node(diff_sptr)
Append a new child node to the vector of children nodes for the current instance of corpus_diff node.
friend void apply_suppressions(const corpus_diff *diff_tree)
Walk a corpus_diff tree and appply the suppressions carried by the context. If the suppression applie...
const 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.
Definition: abg-reporter.h:159
The context of the diff. This type holds various bits of information that is going to be used through...
void add_suppressions(const suppr::suppressions_type &supprs)
Add new suppression specifications that specify which diff node reports should be dropped on the floo...
diff_category get_allowed_category() const
Getter for the bitmap that represents the set of categories that the user wants to see reported.
void forget_visited_diffs()
Unmark all the diff nodes that were marked as being traversed.
corpus_sptr get_first_corpus() const
Getter for the first corpus of the corpus diff of the current context.
bool show_architecture_change() const
Getter for the property that says if the comparison module should show the architecture changes in it...
bool show_offsets_sizes_in_bits() const
Get the flag that indicates if diff reports using this context should show sizes and offsets in bits,...
void forbid_visiting_a_node_twice(bool f)
This sets a flag that, if it's true, then during the traversing of a diff nodes tree each node is vis...
void initialize_canonical_diff(const diff_sptr diff)
Set the canonical diff node property of a given diff node appropriately.
bool show_redundant_changes() const
A getter for the flag that says if we should report about functions or variables diff nodes that have...
void forbid_visiting_a_node_twice_per_interface(bool)
This function sets a flag os that if forbid_visiting_a_node_twice() returns true, then each time the ...
void keep_diff_alive(diff_sptr &)
Add a diff node to the set of diff nodes that are kept alive for the life time of the current instanc...
diff * diff_has_been_visited(const diff *) const
Test if a diff node has been traversed.
bool visiting_a_node_twice_is_forbidden_per_interface() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
void set_corpus_diff(const corpus_diff_sptr &)
Set the corpus diff relevant to this context.
bool show_leaf_changes_only() const
Get the flag that indicates if the diff using this context should show only leaf changes or not.
bool perform_change_categorization() const
Test if it's requested to perform diff node categorization.
bool show_impacted_interfaces() const
Getter of the flag that indicates if the leaf reporter should display a summary of the interfaces imp...
bool show_soname_change() const
Getter for the property that says if the comparison module should show the soname changes in its repo...
reporter_base_sptr get_reporter() const
Getter of the reporter to be used in this context.
void add_diff_filter(filtering::filter_base_sptr)
Setter for the diff filters to apply to a given diff sub-tree.
bool do_log() const
Test if logging was requested.
const suppr::suppressions_type & direct_suppressions() const
Getter of the direct suppression specification (those that are not negated) comprised in the general ...
void maybe_apply_filters(diff_sptr diff)
Apply the diff filters to a given diff sub-tree.
const suppr::suppressions_type & suppressions() const
Getter for the vector of suppressions that specify which diff node reports should be dropped on the f...
bool show_relative_offset_changes(void)
Get the flag saying if offset changes should be reported in a relative way. That is,...
bool visiting_a_node_twice_is_forbidden() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
void do_dump_diff_tree(const diff_sptr) const
Emit a textual representation of a diff tree to the error output stream of the current context,...
const suppr::suppressions_type & negated_suppressions() const
Getter of the negated suppression specifications that are comprised in the general vector of suppress...
void add_suppression(const suppr::suppression_sptr suppr)
Add a new suppression specification that specifies which diff node reports should be dropped on the f...
bool show_hex_values() const
Get the flag that indicates if the diff reports using this context should show sizes and offsets in a...
void switch_categories_off(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
bool show_stats_only() const
Test if the comparison module should only show the diff stats.
const filtering::filters & diff_filters() const
Getter for the diff tree nodes filters to apply to diff sub-trees.
bool show_unreachable_types()
Getter for the flag that indicates if changes on types unreachable from global functions and variable...
const corpus_diff_sptr & get_corpus_diff() const
Get the corpus diff for the current context.
void mark_diff_as_visited(const diff *)
Mark a diff node as traversed by a traversing algorithm.
diff_sptr get_canonical_diff_for(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second) const
Getter for the canonical diff node for the diff represented by their two subjects.
void switch_categories_on(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
ostream * default_output_stream()
Getter for the default output stream used by code of the comparison engine. By default the default ou...
bool dump_diff_tree() const
Test if the comparison engine should dump the diff tree for the changed functions and variables it ha...
bool show_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info are to be compared and...
bool show_added_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info and that got added are...
corpus_sptr get_second_corpus() const
Getter for the second corpus of the corpus diff of the current context.
void set_allowed_category(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
void set_reporter(reporter_base_sptr &)
Setter of the reporter to be used in this context.
ostream * error_output_stream() const
Getter for the errror output stream used by code of the comparison engine. By default the error outpu...
This type contains maps. Each map associates a type name to a diff of that type. Not all kinds of dif...
const string_diff_ptr_map & get_function_decl_diff_map() const
Getter of the map that contains function decl diffs.
const string_diff_ptr_map & get_var_decl_diff_map() const
Getter of the map that contains var decl diffs.
const string_diff_ptr_map & get_enum_diff_map() const
Getter of the map that contains enum type diffs.
bool insert_diff_node(const diff *d, const type_or_decl_base_sptr &impacted_iface)
Insert a new diff node into the current instance of diff_maps.
diff_maps()
Default constructor of the diff_maps type.
const string_diff_ptr_map & get_union_diff_map() const
Getter of the map that contains union type diffs.
artifact_sptr_set_type * lookup_impacted_interfaces(const diff *d) const
Lookup the interfaces that are impacted by a given leaf diff node.
const string_diff_ptr_map & get_function_type_diff_map() const
Getter of the map that contains function type diffs.
const string_diff_ptr_map & get_typedef_diff_map() const
Getter of the map that contains typedef type diffs.
const string_diff_ptr_map & get_distinct_diff_map() const
Getter of the map that contains distinct diffs.
const string_diff_ptr_map & get_subrange_diff_map() const
Getter of the map that contains subrange type diffs.
const string_diff_ptr_map & get_reference_diff_map() const
Getter of the map that contains reference type diffs.
const string_diff_ptr_map & get_array_diff_map() const
Getter of the map that contains array type diffs.
const string_diff_ptr_map & get_type_decl_diff_map() const
Getter of the map that contains basic type diffs.
const string_diff_ptr_map & get_fn_parm_diff_map() const
Getter of the map that contains function parameter diffs.
const string_diff_ptr_map & get_class_diff_map() const
Getter of the map that contains class type diffs.
The base class for the node visitors. These are the types used to visit each node traversed by the di...
void or_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor....
virtual bool visit(diff *, bool)
Default visitor implementation.
virtual bool visit(distinct_diff *, bool)
Default visitor implementation.
virtual void visit_end(corpus_diff *)
This is called by the traversing code on a corpus_diff node just after visiting it....
void set_current_topmost_iface_diff(diff *)
Setter of the diff current topmost interface which is impacted by the current diff node being visited...
virtual void visit_begin(diff *)
This is called by the traversing code on a diff node just before visiting it. That is,...
visiting_kind get_visiting_kind() const
Getter for the visiting policy of the traversing code while invoking this visitor.
virtual void visit_end(diff *)
This is called by the traversing code on a diff node just after visiting it. That is after visiting i...
diff_node_visitor()
Default constructor of the diff_node_visitor type.
void set_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor.
diff * get_current_topmost_iface_diff() const
Getter of the diff current topmost interface which is impacted by the current diff node being visited...
virtual bool traverse(diff_node_visitor &v)
The default traverse function.
The abstraction of a change between two ABI artifacts, a.k.a an artifact change.
void begin_traversing()
Flag a given diff node as being traversed.
void set_category(diff_category c)
Set the category of the current diff node. This category includes the categories inherited from the c...
virtual void finish_diff_type()
Finish the insertion of a diff tree node into the diff graph.
virtual void chain_into_hierarchy()
This constructs the relation between this diff node and its detail diff nodes, in the generic view of...
diff_category remove_from_category(diff_category c)
Remove the current diff tree node from an a existing sef of categories. The categories include those ...
type_or_decl_base_sptr second_subject() const
Getter of the second subject of the diff.
bool is_traversing() const
Tell if a given node is being traversed or not.
type_or_decl_base_sptr first_subject() const
Getter of the first subject of the diff.
bool is_suppressed() const
Test if the current diff node has been suppressed by a user-provided suppression specification.
bool is_filtered_out_without_looking_at_allowed_changes() const
Test if this diff tree node is to be filtered out for reporting purposes, but without considering the...
diff * get_canonical_diff() const
Getter for the canonical diff of the current instance of diff.
bool has_parent_allowed_by_specific_negated_suppression() const
Test if the current diff node has a parent node which is specifically allowed by a negated suppressio...
bool has_local_changes_to_be_reported() const
Test if this diff tree node should be reported when considering the categories that were *NOT* inheri...
const vector< diff * > & children_nodes() const
Getter for the children nodes of the current diff node.
diff_category get_category() const
Getter for the category of the current diff tree node.
bool is_allowed_by_specific_negated_suppression() const
Test if this diff node is allowed (prevented from being suppressed) by at least one negated suppressi...
diff_category remove_from_local_category(diff_category c)
Remove the current diff tree node from the categories resulting from the local changes.
void add_to_local_and_inherited_categories(diff_category c)
Adds the current diff tree node to the categories resulting from the local and inherited changes of t...
bool do_log() const
Test if logging was requested.
diff_category get_local_category() const
Getter for the local category of the current diff tree node.
diff_category add_to_category(diff_category c)
Adds the current diff tree node to an additional set of categories. Note that the categories include ...
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.
diff_sptr underlying_type_diff() const
const string_changed_enumerator_map & changed_enumerators() const
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const enum_type_decl_sptr first_enum() const
const string_enumerator_map & deleted_enumerators() const
const enum_type_decl_sptr second_enum() const
const string_enumerator_map & inserted_enumerators() const
virtual void report(ostream &, const string &indent="") const
Report the differences between the two enums.
A filter that walks the diff nodes tree and tags relevant diff nodes into categories considered to re...
Abstraction of a diff between two function parameters.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children nodes of the diff base type sub-object of this instance of fn_parm_di...
const function_decl::parameter_sptr first_parameter() const
Getter for the first subject of this diff node.
virtual enum change_kind has_local_changes() const
Check if the current diff node carries a local change.
virtual const string & get_pretty_representation() const
Build and return a textual representation of the current instance of fn_parm_diff.
const function_decl::parameter_sptr second_parameter() const
Getter for the second subject of this diff node.
diff_sptr type_diff() const
Getter for the diff representing the changes on the type of the function parameter involved in the cu...
virtual void report(ostream &, const string &indent="") const
Emit a textual report about the current fn_parm_diff instance.
Abstraction of a diff between two function_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_de...
const function_decl_sptr second_function_decl() const
function_decl_diff(const function_decl_sptr first, const function_decl_sptr second, diff_context_sptr ctxt)
Constructor for function_decl_diff.
virtual enum change_kind has_local_changes() const
const function_decl_sptr first_function_decl() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Serialize a report of the changes encapsulated in the current instance of function_decl_diff over to ...
Abstraction of a diff between two function types.
virtual bool has_changes() const
Test if the current diff node carries changes.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_ty...
const string_fn_parm_diff_sptr_map & subtype_changed_parms() const
Getter for the map of function parameter changes of the current diff.
const diff_sptr return_type_diff() const
Getter for the diff of the return types of the two function types of the current diff.
const string_parm_map & removed_parms() const
Getter for the map of parameters that got removed.
const string_parm_map & added_parms() const
Getter for the map of parameters that got added.
friend function_type_diff_sptr compute_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of function_type.
const vector< function_decl::parameter_sptr > & sorted_added_parms() const
Getter for the sorted vector of added parameters .
const function_type_sptr first_function_type() const
Getter for the first subject of the diff.
const function_type_sptr second_function_type() const
Getter for the second subject of the diff.
function_type_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Consutrctor of the function_type type.
virtual enum change_kind has_local_changes() const
Test if the current diff node carries local changes.
virtual const string & get_pretty_representation() const
Build and return a copy of a pretty representation of the current instance of function_type_diff.
const vector< function_decl::parameter_sptr > & sorted_deleted_parms() const
Getter for the sorted vector of deleted parameters.
virtual void report(ostream &, const string &indent="") const
Build and emit a textual report about the current function_type_diff instance.
A reporter that only reports leaf changes.
Definition: abg-reporter.h:281
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.
shared_ptr< subrange_type > subrange_sptr
Convenience typedef for a shared pointer on a function_decl::subrange.
Definition: abg-ir.h:2566
shared_ptr< base_spec > base_spec_sptr
Convenience typedef.
Definition: abg-ir.h:4193
vector< base_spec_sptr > base_specs
Convenience typedef.
Definition: abg-ir.h:4194
vector< method_decl_sptr > member_functions
Convenience typedef.
Definition: abg-ir.h:4008
bool get_is_anonymous() const
Test if the current declaration is anonymous.
Definition: abg-ir.cc:4668
The abstraction of the version of an ELF symbol.
Definition: abg-ir.h:1232
Abstraction of an elf symbol.
Definition: abg-ir.h:961
const string & get_id_string() const
Get a string that is representative of a given elf_symbol.
Definition: abg-ir.cc:2616
std::vector< enumerator > enumerators
Convenience typedef for a list of enumerator.
Definition: abg-ir.h:2801
Abstraction for a function declaration.
Definition: abg-ir.h:3165
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3187
const function_type_sptr get_type() const
Return the type of the current instance of function_decl.
Definition: abg-ir.cc:22966
interned_string get_id() const
Return an ID that tries to uniquely identify the function inside a program or a library.
Definition: abg-ir.cc:23302
An abstraction helper for type declarations.
Definition: abg-ir.h:2003
The base class of both types and declarations.
Definition: abg-ir.h:1406
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_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_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 has_decl_only_def_change(const decl_base_sptr &first, const decl_base_sptr &second)
Test if two decl_base_sptr are different just by the fact that one is decl-only and the other one is ...
bool has_basic_or_class_type_name_change(const diff *d)
Test if a diff node carries a basic or class type name change.
void apply_filter(filter_base &filter, corpus_diff_sptr d)
Walk the diff sub-trees of a a corpus_diff and apply a filter to the nodes visted....
bool is_mostly_distinct_diff(const diff *d)
Test if a diff node carries a distinct type change or a pointer/reference/typedef to distinct type ch...
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:78
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.
Definition: abg-reporter.h:54
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:70
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 apply_suppressions(diff *diff_tree)
Walk a given diff-sub tree and appply the suppressions carried by the context. If the suppression app...
void sort_string_parm_map(const string_parm_map &map, vector< function_decl::parameter_sptr > &sorted)
Sort a map of string -> function parameters.
void sort_string_type_base_sptr_map(string_type_base_sptr_map &map, vector< type_base_sptr > &sorted)
Sort a map of string to type_base_sptr entities.
const enum_diff * is_enum_diff(const diff *diff)
Test if a diff node is a enum_diff node.
unordered_map< string, base_diff_sptr > string_base_diff_sptr_map
Convenience typedef for a map of string and base_diff_sptr.
void sort_data_members(const string_decl_base_sptr_map &data_members, vector< decl_base_sptr > &sorted)
Sort a map of data members by the offset of their initial value.
const class_or_union_diff * is_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff node.
const corpus_diff * is_corpus_diff(const diff *diff)
Test if a diff node is a corpus_diff node.
const diff * get_typedef_diff_underlying_type_diff(const diff *diff)
Return the leaf underlying diff node of a typedef_diff node.
const typedef_diff * is_typedef_diff(const diff *diff)
Test if a diff node is a typedef_diff node.
unordered_map< unsigned, var_diff_sptr > unsigned_var_diff_sptr_map
Convenience typedef for a map whose key is an unsigned int and whose value is a changed variable of t...
type_base_sptr get_leaf_type(qualified_type_def_sptr t)
Return the first underlying type that is not a qualified type.
const diff * peel_typedef_qualified_type_or_parameter_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
shared_ptr< array_diff > array_diff_sptr
Convenience typedef for a shared pointer on a array_diff type.
bool is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff *diff)
Test if a diff node is a reference or pointer diff node to a change that is neither basic type change...
const class_diff * is_class_diff(const diff *diff)
Test if a diff node is a class_diff node.
const type_decl_diff * is_diff_of_basic_type(const diff *d)
Test if a diff node represents a diff between two basic types.
unordered_map< string, diff_sptr > string_diff_sptr_map
Convenience typedef for a map which value is a diff_sptr. The key of the map is the qualified name of...
unordered_map< const diff *, artifact_sptr_set_type, diff_hash, diff_equal > diff_artifact_set_map_type
A convenience typedef for an unordered_map which key is a diff* and which value is a artifact_sptr_se...
const qualified_type_diff * is_qualified_type_diff(const diff *diff)
Test if a diff node is about differences between two qualified types.
diff_sptr compute_diff(const decl_base_sptr first, const decl_base_sptr second, diff_context_sptr ctxt)
Compute the difference between two decls. The decls can represent either type declarations,...
unordered_map< string, diff * > string_diff_ptr_map
Convenience typedef for a map which value is a diff*. The key of the map is the qualified name of the...
void sort_string_base_diff_sptr_map(const string_base_diff_sptr_map &map, base_diff_sptrs_type &sorted)
Sort a map of string -> base_diff_sptr into a sorted vector of base_diff_sptr. The base_diff_sptr are...
void sort_changed_enumerators(const string_changed_enumerator_map &enumerators_map, changed_enumerators_type &sorted)
Sort a map of changed enumerators.
void print_diff_tree(diff *diff_tree, ostream &out)
Emit a textual representation of a diff sub-tree to an output stream.
vector< changed_enumerator > changed_enumerators_type
Convenience typedef for a vector of changed enumerators.
vector< function_decl_diff_sptr > function_decl_diff_sptrs_type
Convenience typedef for a vector of function_decl_diff_sptr.
bool is_child_node_of_function_parm_diff(const diff *diff)
Test if a diff node is a child node of a function parameter diff node.
void sort_string_virtual_member_function_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort an map of string -> virtual member function into a vector of virtual member functions....
shared_ptr< function_type_diff > function_type_diff_sptr
A convenience typedef for a shared pointer to function_type_type_diff.
const function_type_diff * is_function_type_diff_with_local_changes(const diff *diff)
Test if a given diff node carries a function type change with local changes.
const var_diff * is_var_diff(const diff *diff)
Test if a diff node is about differences between variables.
const type_diff_base * is_type_diff(const diff *diff)
Test if a diff node is about differences between types.
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:235
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc:6454
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:5575
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition: abg-fwd.h:269
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:559
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition: abg-ir.cc:10807
bool is_anonymous_data_member(const decl_base &d)
Test if a decl is an anonymous data member.
Definition: abg-ir.cc:5872
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:12215
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:926
change_kind
A bitfield that gives callers of abigail::ir::equals() some insight about how different two internal ...
Definition: abg-ir.h:1361
@ LOCAL_TYPE_CHANGE_KIND
This means that a given IR artifact has a local type change.
Definition: abg-ir.h:1365
@ ALL_LOCAL_CHANGES_MASK
Testing (anding) against this mask means that a given IR artifact has local differences,...
Definition: abg-ir.h:1376
@ 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:1370
bool is_user_defined_type(const type_base *t)
Test if a type is user-defined.
Definition: abg-ir.cc:5479
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:5815
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:11165
shared_ptr< array_type_def > array_type_def_sptr
Convenience typedef for a shared pointer on a array_type_def.
Definition: abg-fwd.h:244
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:9286
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:11396
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:5742
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:193
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition: abg-fwd.h:210
shared_ptr< typedef_decl > typedef_decl_sptr
Convenience typedef for a shared pointer on a typedef_decl.
Definition: abg-fwd.h:167
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:11100
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:10650
const global_scope * get_global_scope(const decl_base &decl)
return the global scope as seen by a given declaration.
Definition: abg-ir.cc:8543
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition: abg-fwd.h:256
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:239
shared_ptr< scope_decl > scope_decl_sptr
Convenience typedef for a shared pointer on a scope_decl.
Definition: abg-fwd.h:264
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:120
shared_ptr< translation_unit > translation_unit_sptr
Convenience typedef for a shared pointer on a translation_unit type.
Definition: abg-fwd.h:136
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:157
bool equals(const decl_base &l, const decl_base &r, change_kind *k)
Compares two instances of decl_base.
Definition: abg-ir.cc:5138
shared_ptr< pointer_type_def > pointer_type_def_sptr
Convenience typedef for a shared pointer on a pointer_type_def.
Definition: abg-fwd.h:226
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:20548
uint64_t get_absolute_data_member_offset(const var_decl &m)
Get the absolute offset of a data member.
Definition: abg-ir.cc:6273
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition: abg-ir.cc:6368
var_decl * is_var_decl(const type_or_decl_base *tod)
Tests if a declaration is a variable declaration.
Definition: abg-ir.cc:12059
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition: abg-ir.cc:10747
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition: abg-fwd.h:175
uint64_t get_data_member_offset(const var_decl &m)
Get the offset of a data member.
Definition: abg-ir.cc:6184
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6641
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:6030
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:11918
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition: abg-ir.cc:11445
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition: abg-ir.cc:5613
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition: abg-ir.cc:10229
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:29028
interned_string get_function_id_or_pretty_representation(const function_decl *fn)
Get the ID of a function, or, if the ID can designate several different functions,...
Definition: abg-ir.cc:9180
shared_ptr< type_decl > type_decl_sptr
Convenience typedef for a shared pointer on a type_decl.
Definition: abg-fwd.h:161
bool is_unique_type(const type_base_sptr &t)
Test if a type is unique in the entire environment.
Definition: abg-ir.cc:28598
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:10397
function_decl * is_function_decl(const type_or_decl_base *d)
Test whether a declaration is a function_decl.
Definition: abg-ir.cc:10695
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:11888
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:11417
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:7358
bool is_at_global_scope(const decl_base &decl)
Tests whether a given declaration is at global scope.
Definition: abg-ir.cc:10580
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition: abg-ir.cc:5417
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:1687
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:1684
bool is_negated_suppression(const suppression_base &s)
Test if a suppression specification is a negated suppression.
Toplevel namespace for libabigail.
A comparison function for instances of base_diff.
A functor to compare instances of class_decl::base_spec.
A functor to compare two changed enumerators, based on their initial value.
size_t count_filtered_bases()
Count the number of bases classes whose changes got filtered out.
class_decl::base_spec_sptr base_has_changed(class_decl::base_spec_sptr) const
Test whether a given base class has changed. A base class has changed if it's in both in deleted *and...
The type of private data of class_or_union_diff.
size_t count_filtered_changed_dm(bool local_only=false)
Get the number of data member changes carried by the current diff node that were filtered out.
size_t count_filtered_subtype_changed_dm(bool local_only=false)
Get the number of data member sub-type changes carried by the current diff node that were filtered ou...
size_t get_deleted_non_static_data_members_number() const
Get the number of non static data members that were deleted.
size_t count_filtered_changed_mem_fns(const diff_context_sptr &)
Get the number of member functions changes carried by the current diff node that were filtered out.
decl_base_sptr subtype_changed_dm(decl_base_sptr) const
Test if the current diff node carries a data member change for a data member which name is the same a...
type_or_decl_base_sptr member_type_has_changed(decl_base_sptr) const
Test if the current diff node carries a member type change for a member type which name is the same a...
decl_base_sptr member_class_tmpl_has_changed(decl_base_sptr) const
Test if the current diff node carries a member class template change for a member class template whic...
size_t count_filtered_inserted_mem_fns(const diff_context_sptr &)
Get the number of member functions insertions carried by the current diff node that were filtered out...
size_t count_filtered_deleted_mem_fns(const diff_context_sptr &)
Get the number of member functions deletions carried by the current diff node that were filtered out.
size_t get_inserted_non_static_data_members_number() const
Get the number of non static data members that were inserted.
The type of the private data of corpus_diff::diff_stats.
bool added_unreachable_type_is_suppressed(const type_base *t) const
Test if an added type that is unreachable from public interface has been suppressed by a suppression ...
void ensure_lookup_tables_populated()
If the lookup tables are not yet built, walk the differences and fill the lookup tables.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Get the sorted vector of diff nodes representing changed unreachable types.
diff_context_sptr get_context()
Getter of the context associated with this corpus.
void categorize_redundant_changed_sub_nodes()
Walk the changed functions and variables diff nodes to categorize redundant nodes.
const string_diff_sptr_map & changed_unreachable_types() const
Get the map of diff nodes representing changed unreachable types.
bool added_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added variable symbol (that is not referenced by any debug inf...
bool lookup_tables_empty() const
Tests if the lookup tables are empty.
bool deleted_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted function symbol (that is not referenced by any debug i...
void apply_filters_and_compute_diff_stats(corpus_diff::diff_stats &)
Compute the diff stats.
bool 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 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_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...
An equality functor to deeply compare pointers.
A comparison functor to compare pointer to instances of type_or_decl_base.
Definition: abg-ir.h:3294
A deleter for shared pointers that ... doesn't delete the object managed by the shared pointer.