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 {
2958 type_base_sptr fs = strip_typedef(is_type(first())),
2959 ss = strip_typedef(is_type(second()));
2960
2961 if (fs && ss
2964 && *fs == *ss)
2965 priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2967 context());
2968 }
2969 return priv_->compatible_child_diff;
2970}
2971
2972/// Test if the two arguments are of different kind, or that are both
2973/// NULL.
2974///
2975/// @param first the first argument to test for similarity in kind.
2976///
2977/// @param second the second argument to test for similarity in kind.
2978///
2979/// @return true iff the two arguments are of different kind.
2980bool
2983{
2984 if (!!first != !!second)
2985 return true;
2986 if (!first && !second)
2987 // We do consider diffs of two empty decls as a diff of distinct
2988 // kinds, for now.
2989 return true;
2990 if (first == second)
2991 return false;
2992
2993 const type_or_decl_base &f = *first, &s = *second;
2994 return typeid(f) != typeid(s);
2995}
2996
2997/// @return true if the two subjects of the diff are different, false
2998/// otherwise.
2999bool
3001{return first() != second();}
3002
3003/// @return the kind of local change carried by the current diff node.
3004/// The value returned is zero if the current node carries no local
3005/// change.
3006enum change_kind
3008{
3009 // Changes on a distinct_diff are all local.
3010 if (has_changes())
3012 return NO_CHANGE_KIND;
3013}
3014
3015/// Emit a report about the current diff instance.
3016///
3017/// @param out the output stream to send the diff report to.
3018///
3019/// @param indent the indentation string to use in the report.
3020void
3021distinct_diff::report(ostream& out, const string& indent) const
3022{
3023 context()->get_reporter()->report(*this, out, indent);
3024}
3025
3026/// Try to diff entities that are of distinct kinds.
3027///
3028/// @param first the first entity to consider for the diff.
3029///
3030/// @param second the second entity to consider for the diff.
3031///
3032/// @param ctxt the context of the diff.
3033///
3034/// @return a non-null diff if a diff object could be built, null
3035/// otherwise.
3038 const type_or_decl_base_sptr second,
3039 diff_context_sptr ctxt)
3040{
3042 return distinct_diff_sptr();
3043
3044 distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
3045
3046 ctxt->initialize_canonical_diff(result);
3047
3048 return result;
3049}
3050
3051/// </distinct_diff stuff>
3052
3053/// Try to compute a diff on two instances of DiffType representation.
3054///
3055/// The function template performs the diff if and only if the decl
3056/// representations are of a DiffType.
3057///
3058/// @tparm DiffType the type of instances to diff.
3059///
3060/// @param first the first representation of decl to consider in the
3061/// diff computation.
3062///
3063/// @param second the second representation of decl to consider in the
3064/// diff computation.
3065///
3066/// @param ctxt the diff context to use.
3067///
3068///@return the diff of the two types @p first and @p second if and
3069///only if they represent the parametrized type DiffType. Otherwise,
3070///returns a NULL pointer value.
3071template<typename DiffType>
3074 const type_or_decl_base_sptr second,
3075 diff_context_sptr ctxt)
3076{
3077 if (shared_ptr<DiffType> f =
3078 dynamic_pointer_cast<DiffType>(first))
3079 {
3080 shared_ptr<DiffType> s =
3081 dynamic_pointer_cast<DiffType>(second);
3082 if (!s)
3083 return diff_sptr();
3084 return compute_diff(f, s, ctxt);
3085 }
3086 return diff_sptr();
3087}
3088
3089
3090/// This is a specialization of @ref try_to_diff() template to diff
3091/// instances of @ref class_decl.
3092///
3093/// @param first the first representation of decl to consider in the
3094/// diff computation.
3095///
3096/// @param second the second representation of decl to consider in the
3097/// diff computation.
3098///
3099/// @param ctxt the diff context to use.
3100template<>
3103 const type_or_decl_base_sptr second,
3104 diff_context_sptr ctxt)
3105{
3106 if (class_decl_sptr f =
3107 dynamic_pointer_cast<class_decl>(first))
3108 {
3109 class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
3110 if (!s)
3111 return diff_sptr();
3112
3113 if (f->get_is_declaration_only())
3114 {
3115 class_decl_sptr f2 =
3116 is_class_type (f->get_definition_of_declaration());
3117 if (f2)
3118 f = f2;
3119 }
3120 if (s->get_is_declaration_only())
3121 {
3122 class_decl_sptr s2 =
3123 is_class_type(s->get_definition_of_declaration());
3124 if (s2)
3125 s = s2;
3126 }
3127 return compute_diff(f, s, ctxt);
3128 }
3129 return diff_sptr();
3130}
3131
3132/// Try to diff entities that are of distinct kinds.
3133///
3134/// @param first the first entity to consider for the diff.
3135///
3136/// @param second the second entity to consider for the diff.
3137///
3138/// @param ctxt the context of the diff.
3139///
3140/// @return a non-null diff if a diff object could be built, null
3141/// otherwise.
3142static diff_sptr
3143try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3144 const type_or_decl_base_sptr second,
3145 diff_context_sptr ctxt)
3146{return compute_diff_for_distinct_kinds(first, second, ctxt);}
3147
3148/// Compute the difference between two types.
3149///
3150/// The function considers every possible types known to libabigail
3151/// and runs the appropriate diff function on them.
3152///
3153/// Whenever a new kind of type decl is supported by abigail, if we
3154/// want to be able to diff two instances of it, we need to update
3155/// this function to support it.
3156///
3157/// @param first the first type decl to consider for the diff
3158///
3159/// @param second the second type decl to consider for the diff.
3160///
3161/// @param ctxt the diff context to use.
3162///
3163/// @return the resulting diff. It's a pointer to a descendent of
3164/// abigail::comparison::diff.
3165static diff_sptr
3166compute_diff_for_types(const type_or_decl_base_sptr& first,
3167 const type_or_decl_base_sptr& second,
3168 const diff_context_sptr& ctxt)
3169{
3170 type_or_decl_base_sptr f = first;
3171 type_or_decl_base_sptr s = second;
3172
3173 diff_sptr d;
3174
3175 ((d = try_to_diff<type_decl>(f, s, ctxt))
3176 ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3177 ||(d = try_to_diff<union_decl>(f, s,ctxt))
3178 ||(d = try_to_diff<class_decl>(f, s,ctxt))
3179 ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3180 ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3181 ||(d = try_to_diff<ptr_to_mbr_type>(f, s, ctxt))
3182 ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3183 ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3184 ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3185 ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3186 ||(d = try_to_diff<function_type>(f, s, ctxt))
3187 ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3188
3189 ABG_ASSERT(d);
3190
3191 return d;
3192}
3193
3196{return static_cast<diff_category>(static_cast<unsigned>(c1)
3197 | static_cast<unsigned>(c2));}
3198
3200operator|=(diff_category& c1, diff_category c2)
3201{
3202 c1 = c1 | c2;
3203 return c1;
3204}
3205
3207operator&=(diff_category& c1, diff_category c2)
3208{
3209 c1 = c1 & c2;
3210 return c1;
3211}
3212
3214operator^(diff_category c1, diff_category c2)
3215{return static_cast<diff_category>(static_cast<unsigned>(c1)
3216 ^ static_cast<unsigned>(c2));}
3217
3220{return static_cast<diff_category>(static_cast<unsigned>(c1)
3221 & static_cast<unsigned>(c2));}
3222
3225{return static_cast<diff_category>(~static_cast<unsigned>(c));}
3226
3227
3228/// Getter of a bitmap made of the set of change categories that are
3229/// considered harmless.
3230///
3231/// @return the bitmap made of the set of change categories that are
3232/// considered harmless.
3235{
3252}
3253
3254/// Getter of a bitmap made of the set of change categories that are
3255/// considered harmful.
3256///
3257/// @return the bitmap made of the set of change categories that are
3258/// considered harmful.
3261{
3264 | abigail::comparison::REFERENCE_LVALUENESS_CHANGE_CATEGORY
3268}
3269
3270/// Test if an instance of @ref diff_category (a category bit-field)
3271/// is harmful or not.
3272///
3273/// A harmful change is a change that is not harmless. OK, that
3274/// smells bit like a tasteless tautology, but bear with me please.
3275///
3276/// A harmless change is a change that should be filtered out by
3277/// default to avoid unnecessarily cluttering the change report.
3278///
3279/// A harmful change is thus a change that SHOULD NOT be filtered out
3280/// by default because it CAN represent an incompatible ABI change.
3281///
3282/// An incompatbile ABI change is a harmful change that makes the new
3283/// ABI incompatible with the previous one.
3284///
3285/// @param c the instance of @ref diff_category to consider. It is a
3286/// bit-field of the categories of a given diff node.
3287///
3288/// @return true
3289bool
3291{
3293 return c & dc;
3294}
3295
3296/// Serialize an instance of @ref diff_category to an output stream.
3297///
3298/// @param o the output stream to serialize @p c to.
3299///
3300/// @param c the instance of diff_category to serialize.
3301///
3302/// @return the output stream to serialize @p c to.
3303ostream&
3304operator<<(ostream& o, diff_category c)
3305{
3306 bool emitted_a_category = false;
3307
3308 if (c == NO_CHANGE_CATEGORY)
3309 {
3310 o << "NO_CHANGE_CATEGORY";
3311 emitted_a_category = true;
3312 }
3313
3314 if (c & ACCESS_CHANGE_CATEGORY)
3315 {
3316 if (emitted_a_category)
3317 o << "|";
3318 o << "ACCESS_CHANGE_CATEGORY";
3319 emitted_a_category |= true;
3320 }
3321
3323 {
3324 if (emitted_a_category)
3325 o << "|";
3326 o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3327 emitted_a_category |= true;
3328 }
3329
3331 {
3332 if (emitted_a_category)
3333 o << "|";
3334 o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3335 emitted_a_category |= true;
3336 }
3337
3339 {
3340 if (emitted_a_category)
3341 o << "|";
3342 o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3343 emitted_a_category |= true;
3344 }
3345
3347 {
3348 if (emitted_a_category)
3349 o << "|";
3350 o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3351 emitted_a_category |= true;
3352 }
3353
3355 {
3356 if (emitted_a_category)
3357 o << "|";
3358 o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3359 emitted_a_category |= true;
3360 }
3361
3363 {
3364 if (emitted_a_category)
3365 o << "|";
3366 o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3367 emitted_a_category |= true;
3368 }
3369
3371 {
3372 if (emitted_a_category)
3373 o << "|";
3374 o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3375 emitted_a_category |= true;
3376 }
3377
3379 {
3380 if (emitted_a_category)
3381 o << "|";
3382 o << "HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY";
3383 emitted_a_category |= true;
3384 }
3385
3386 if (c & SUPPRESSED_CATEGORY)
3387 {
3388 if (emitted_a_category)
3389 o << "|";
3390 o << "SUPPRESSED_CATEGORY";
3391 emitted_a_category |= true;
3392 }
3393
3394 if (c & PRIVATE_TYPE_CATEGORY)
3395 {
3396 if (emitted_a_category)
3397 o << "|";
3398 o << "PRIVATE_TYPE_CATEGORY";
3399 emitted_a_category |= true;
3400 }
3401
3403 {
3404 if (emitted_a_category)
3405 o << "|";
3406 o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3407 emitted_a_category |= true;
3408 }
3409
3411 {
3412 if (emitted_a_category)
3413 o << "|";
3414 o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3415 emitted_a_category |= true;
3416 }
3417
3418 if (c & REFERENCE_LVALUENESS_CHANGE_CATEGORY)
3419 {
3420 if (emitted_a_category)
3421 o << "|";
3422 o << "REFERENCE_LVALUENESS_CHANGE_CATEGORY";
3423 emitted_a_category |= true;
3424 }
3425
3427 {
3428 if (emitted_a_category)
3429 o << "|";
3430 o << "NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY";
3431 emitted_a_category |= true;
3432 }
3433
3435 {
3436 if (emitted_a_category)
3437 o << "|";
3438 o << "NON_COMPATIBLE_NAME_CHANGE_CATEGORY";
3439 emitted_a_category |= true;
3440 }
3441
3442 if (c & REDUNDANT_CATEGORY)
3443 {
3444 if (emitted_a_category)
3445 o << "|";
3446 o << "REDUNDANT_CATEGORY";
3447 emitted_a_category |= true;
3448 }
3449
3451 {
3452 if (emitted_a_category)
3453 o << "|";
3454 o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3455 emitted_a_category |= true;
3456 }
3457
3459 {
3460 if (emitted_a_category)
3461 o << "|";
3462 o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3463 emitted_a_category |= true;
3464 }
3465
3467 {
3468 if (emitted_a_category)
3469 o << "|";
3470 o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3471 emitted_a_category |= true;
3472 }
3473
3475 {
3476 if (emitted_a_category)
3477 o << "|";
3478 o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3479 emitted_a_category |= true;
3480 }
3481
3483 {
3484 if (emitted_a_category)
3485 o << "|";
3486 o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3487 emitted_a_category |= true;
3488 }
3489
3491 {
3492 if (emitted_a_category)
3493 o << "|";
3494 o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3495 emitted_a_category |= true;
3496 }
3497
3499 {
3500 if (emitted_a_category)
3501 o << "|";
3502 o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3503 emitted_a_category |= true;
3504 }
3505
3507 {
3508 if (emitted_a_category)
3509 o << "|";
3510 o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3511 emitted_a_category |= true;
3512 }
3513
3515 {
3516 if (emitted_a_category)
3517 o << "|";
3518 o << "HAS_ALLOWED_CHANGE_CATEGORY";
3519 emitted_a_category |= true;
3520 }
3521
3523 {
3524 if (emitted_a_category)
3525 o << "|";
3526 o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3527 emitted_a_category |= true;
3528 }
3529
3531 {
3532 if (emitted_a_category)
3533 o << "|";
3534 o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3535 emitted_a_category |= true;
3536 }
3537
3538 return o;
3539}
3540
3541/// Compute the difference between two decls.
3542///
3543/// The function consider every possible decls known to libabigail and
3544/// runs the appropriate diff function on them.
3545///
3546/// Whenever a new kind of non-type decl is supported by abigail, if
3547/// we want to be able to diff two instances of it, we need to update
3548/// this function to support it.
3549///
3550/// @param first the first decl to consider for the diff
3551///
3552/// @param second the second decl to consider for the diff.
3553///
3554/// @param ctxt the diff context to use.
3555///
3556/// @return the resulting diff.
3557static diff_sptr
3558compute_diff_for_decls(const decl_base_sptr first,
3559 const decl_base_sptr second,
3560 diff_context_sptr ctxt)
3561{
3562
3563 diff_sptr d;
3564
3565 ((d = try_to_diff<function_decl>(first, second, ctxt))
3566 || (d = try_to_diff<var_decl>(first, second, ctxt))
3567 || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3568
3569 ABG_ASSERT(d);
3570
3571 return d;
3572}
3573
3574/// Compute the difference between two decls. The decls can represent
3575/// either type declarations, or non-type declaration.
3576///
3577/// Note that the two decls must have been created in the same @ref
3578/// environment, otherwise, this function aborts.
3579///
3580/// @param first the first decl to consider.
3581///
3582/// @param second the second decl to consider.
3583///
3584/// @param ctxt the diff context to use.
3585///
3586/// @return the resulting diff, or NULL if the diff could not be
3587/// computed.
3589compute_diff(const decl_base_sptr first,
3590 const decl_base_sptr second,
3591 diff_context_sptr ctxt)
3592{
3593 if (!first || !second)
3594 return diff_sptr();
3595
3596 diff_sptr d;
3597 if (is_type(first) && is_type(second))
3598 d = compute_diff_for_types(first, second, ctxt);
3599 else
3600 d = compute_diff_for_decls(first, second, ctxt);
3601 ABG_ASSERT(d);
3602 return d;
3603}
3604
3605/// Compute the difference between two types.
3606///
3607/// Note that the two types must have been created in the same @ref
3608/// environment, otherwise, this function aborts.
3609///
3610/// @param first the first type to consider.
3611///
3612/// @param second the second type to consider.
3613///
3614/// @param ctxt the diff context to use.
3615///
3616/// @return the resulting diff, or NULL if the diff couldn't be
3617/// computed.
3619compute_diff(const type_base_sptr first,
3620 const type_base_sptr second,
3621 diff_context_sptr ctxt)
3622{
3623 decl_base_sptr f = get_type_declaration(first),
3624 s = get_type_declaration(second);
3625
3626 diff_sptr d = compute_diff_for_types(f,s, ctxt);
3627 ABG_ASSERT(d);
3628 return d;
3629}
3630
3631/// Get a copy of the pretty representation of a diff node.
3632///
3633/// @param d the diff node to consider.
3634///
3635/// @return the pretty representation string.
3636string
3638{
3639 if (!d)
3640 return "";
3641 string prefix= "diff of ";
3642 return prefix + get_pretty_representation(d->first_subject());
3643}
3644
3645// <var_diff stuff>
3646
3647/// Populate the vector of children node of the @ref diff base type
3648/// sub-object of this instance of @ref var_diff.
3649///
3650/// The children node can then later be retrieved using
3651/// diff::children_node().
3652void
3655
3656/// @return the pretty representation for this current instance of
3657/// @ref var_diff.
3658const string&
3660{
3661 if (diff::priv_->pretty_representation_.empty())
3662 {
3663 std::ostringstream o;
3664 o << "var_diff["
3665 << first_subject()->get_pretty_representation()
3666 << ", "
3667 << second_subject()->get_pretty_representation()
3668 << "]";
3669 diff::priv_->pretty_representation_ = o.str();
3670 }
3671 return diff::priv_->pretty_representation_;
3672}
3673/// Constructor for @ref var_diff.
3674///
3675/// @param first the first instance of @ref var_decl to consider in
3676/// the diff.
3677///
3678/// @param second the second instance of @ref var_decl to consider in
3679/// the diff.
3680///
3681/// @param type_diff the diff between types of the instances of
3682/// var_decl.
3683///
3684/// @param ctxt the diff context to use.
3686 var_decl_sptr second,
3687 diff_sptr type_diff,
3688 diff_context_sptr ctxt)
3689 : decl_diff_base(first, second, ctxt),
3690 priv_(new priv)
3691{priv_->type_diff_ = type_diff;}
3692
3693/// Getter for the first @ref var_decl of the diff.
3694///
3695/// @return the first @ref var_decl of the diff.
3698{return dynamic_pointer_cast<var_decl>(first_subject());}
3699
3700/// Getter for the second @ref var_decl of the diff.
3701///
3702/// @return the second @ref var_decl of the diff.
3705{return dynamic_pointer_cast<var_decl>(second_subject());}
3706
3707/// Getter for the diff of the types of the instances of @ref
3708/// var_decl.
3709///
3710/// @return the diff of the types of the instances of @ref var_decl.
3713{
3714 if (diff_sptr result = priv_->type_diff_.lock())
3715 return result;
3716 else
3717 {
3718 result = compute_diff(first_var()->get_type(),
3719 second_var()->get_type(),
3720 context());
3721 context()->keep_diff_alive(result);
3722 priv_->type_diff_ = result;
3723 return result;
3724 }
3725}
3726
3727/// Return true iff the diff node has a change.
3728///
3729/// @return true iff the diff node has a change.
3730bool
3732{return *first_var() != *second_var();}
3733
3734/// @return the kind of local change carried by the current diff node.
3735/// The value returned is zero if the current node carries no local
3736/// change.
3737enum change_kind
3739{
3740 ir::change_kind k = ir::NO_CHANGE_KIND;
3741 if (!equals(*first_var(), *second_var(), &k))
3742 return k & ir::ALL_LOCAL_CHANGES_MASK;
3743 return ir::NO_CHANGE_KIND;
3744}
3745
3746/// Report the diff in a serialized form.
3747///
3748/// @param out the stream to serialize the diff to.
3749///
3750/// @param indent the prefix to use for the indentation of this
3751/// serialization.
3752void
3753var_diff::report(ostream& out, const string& indent) const
3754{
3755 context()->get_reporter()->report(*this, out, indent);
3756}
3757
3758/// Compute the diff between two instances of @ref var_decl.
3759///
3760/// Note that the two decls must have been created in the same @ref
3761/// environment, otherwise, this function aborts.
3762///
3763/// @param first the first @ref var_decl to consider for the diff.
3764///
3765/// @param second the second @ref var_decl to consider for the diff.
3766///
3767/// @param ctxt the diff context to use.
3768///
3769/// @return the resulting diff between the two @ref var_decl.
3772 const var_decl_sptr second,
3773 diff_context_sptr ctxt)
3774{
3775 var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3776 ctxt->initialize_canonical_diff(d);
3777
3778 return d;
3779}
3780
3781// </var_diff stuff>
3782
3783// <pointer_type_def stuff>
3784
3785/// Populate the vector of children node of the @ref diff base type
3786/// sub-object of this instance of @ref pointer_diff.
3787///
3788/// The children node can then later be retrieved using
3789/// diff::children_node().
3790void
3793
3794/// Constructor for a pointer_diff.
3795///
3796/// @param first the first pointer to consider for the diff.
3797///
3798/// @param second the secon pointer to consider for the diff.
3799///
3800/// @param ctxt the diff context to use.
3802 pointer_type_def_sptr second,
3803 diff_sptr underlying,
3804 diff_context_sptr ctxt)
3805 : type_diff_base(first, second, ctxt),
3806 priv_(new priv(underlying))
3807{}
3808
3809/// Getter for the first subject of a pointer diff
3810///
3811/// @return the first pointer considered in this pointer diff.
3814{return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3815
3816/// Getter for the second subject of a pointer diff
3817///
3818/// @return the second pointer considered in this pointer diff.
3821{return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3822
3823/// @return the pretty represenation for the current instance of @ref
3824/// pointer_diff.
3825const string&
3827{
3828 if (diff::priv_->pretty_representation_.empty())
3829 {
3830 std::ostringstream o;
3831 o << "pointer_diff["
3832 << first_subject()->get_pretty_representation()
3833 << ", "
3834 << second_subject()->get_pretty_representation()
3835 << "]";
3836 diff::priv_->pretty_representation_ = o.str();
3837 }
3838 return diff::priv_->pretty_representation_;
3839}
3840
3841/// Return true iff the current diff node carries a change.
3842///
3843/// @return true iff the current diff node carries a change.
3844bool
3846{return first_pointer() != second_pointer();}
3847
3848/// @return the kind of local change carried by the current diff node.
3849/// The value returned is zero if the current node carries no local
3850/// change.
3851enum change_kind
3853{
3854 ir::change_kind k = ir::NO_CHANGE_KIND;
3855 if (!equals(*first_pointer(), *second_pointer(), &k))
3856 return k & ir::ALL_LOCAL_CHANGES_MASK;
3857 return ir::NO_CHANGE_KIND;
3858}
3859
3860/// Getter for the diff between the pointed-to types of the pointers
3861/// of this diff.
3862///
3863/// @return the diff between the pointed-to types.
3866{return priv_->underlying_type_diff_;}
3867
3868/// Setter for the diff between the pointed-to types of the pointers
3869/// of this diff.
3870///
3871/// @param d the new diff between the pointed-to types of the pointers
3872/// of this diff.
3873void
3875{priv_->underlying_type_diff_ = d;}
3876
3877/// Report the diff in a serialized form.
3878///
3879/// @param out the stream to serialize the diff to.
3880///
3881/// @param indent the prefix to use for the indentation of this
3882/// serialization.
3883void
3884pointer_diff::report(ostream& out, const string& indent) const
3885{
3886 context()->get_reporter()->report(*this, out, indent);
3887}
3888
3889/// Compute the diff between between two pointers.
3890///
3891/// Note that the two types must have been created in the same @ref
3892/// environment, otherwise, this function aborts.
3893///
3894/// @param first the pointer to consider for the diff.
3895///
3896/// @param second the pointer to consider for the diff.
3897///
3898/// @return the resulting diff between the two pointers.
3899///
3900/// @param ctxt the diff context to use.
3903 pointer_type_def_sptr second,
3904 diff_context_sptr ctxt)
3905{
3906 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3907 second->get_pointed_to_type(),
3908 ctxt);
3909 pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3910 ctxt->initialize_canonical_diff(result);
3911
3912 return result;
3913}
3914
3915// </pointer_type_def>
3916
3917// <subrange_diff >
3918
3919/// Constructor of the @ref subrange_diff diff node type.
3920///
3921/// @param first the first subrange type to consider for the diff.
3922///
3923/// @param second the second subrange type to consider for the diff.
3924///
3925/// @param underlying_type_diff the underlying type diff between @p
3926/// first and @p second.
3927///
3928/// @param ctxt the diff context to use.
3930(const array_type_def::subrange_sptr& first,
3931 const array_type_def::subrange_sptr& second,
3932 const diff_sptr& underlying_type_diff,
3933 const diff_context_sptr ctxt)
3934 : type_diff_base(first, second, ctxt),
3935 priv_(new priv(underlying_type_diff))
3936{}
3937
3938
3939/// Getter of the first subrange of the current instance @ref
3940/// subrange_diff.
3941///
3942/// @return The first subrange of the current instance @ref subrange_diff.
3946
3947/// Getter of the second subrange of the current instance @ref
3948/// subrange_diff.
3949///
3950/// @return The second subrange of the current instance @ref
3951/// subrange_diff.
3955
3956/// Getter of the diff node of the underlying types of the current
3957/// @ref subrange_diff diff node.
3958///
3959/// @return The diff node of the underlying types of the current @ref
3960/// subrange_diff diff node.
3961const diff_sptr
3963{return priv_->underlying_type_diff_;}
3964
3965/// Getter the pretty representation of the @ref subrange_diff diff
3966/// node.
3967///
3968/// @return The pretty representation of the @ref subrange_diff diff node.
3969const string&
3971{
3972 if (diff::priv_->pretty_representation_.empty())
3973 {
3974 std::ostringstream o;
3975 o << "subrange_diff["
3976 << first_subject()->get_pretty_representation()
3977 << ","
3978 << second_subject()->get_pretty_representation()
3979 << "]";
3980 diff::priv_->pretty_representation_ = o.str();
3981 }
3982 return diff::priv_->pretty_representation_;
3983}
3984
3985/// Test if the current @ref subrange_diff node carries any change.
3986///
3987/// @return true iff the current @ref subrange_diff node carries any
3988/// change.
3989bool
3991{return *first_subrange() != *second_subrange();}
3992
3993/// Test if the current @ref subrange_diff node carries any local
3994/// change.
3995///
3996/// @return true iff the current @ref subrange_diff node carries any
3997/// local change.
3998enum change_kind
4000{
4001 ir::change_kind k = ir::NO_CHANGE_KIND;
4002 if (!equals(*first_subrange(), *second_subrange(), &k))
4003 return k & ir::ALL_LOCAL_CHANGES_MASK;
4004 return ir::NO_CHANGE_KIND;
4005}
4006
4007/// Report about the changes carried by this node.
4008///
4009/// @param out the output stream to send the report to.
4010///
4011/// @param indent the indentation string to use.
4012void
4013subrange_diff::report(ostream& out, const string& indent) const
4014{context()->get_reporter()->report(*this, out, indent);}
4015
4016/// Populate the vector of children node of the @ref diff base type
4017/// sub-object of this instance of @ref subrange_diff.
4018///
4019/// The children node can then later be retrieved using
4020/// diff::children_node().
4021void
4024
4025/// Compute the diff between two instances of @ref subrange_diff.
4026///
4027/// Note that the two decls must have been created in the same @ref
4028/// environment, otherwise, this function aborts.
4029///
4030/// @param first the first @ref subrange_diff to consider for the diff.
4031///
4032/// @param second the second @ref subrange_diff to consider for the diff.
4033///
4034/// @param ctxt the diff context to use.
4035///
4036/// @return the resulting diff between the two @ref subrange_diff.
4040 diff_context_sptr ctxt)
4041{
4042 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4043 second->get_underlying_type(),
4044 ctxt);
4045
4046 subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
4047 ctxt->initialize_canonical_diff(result);
4048 return result;
4049}
4050
4051//</subrange_diff >
4052
4053
4054// <array_type_def>
4055
4056/// Populate the vector of children node of the @ref diff base type
4057/// sub-object of this instance of @ref array_diff.
4058///
4059/// The children node can then later be retrieved using
4060/// diff::children_node().
4061void
4063{
4065 for (const auto& subrange_diff : subrange_diffs())
4067}
4068
4069/// Constructor for array_diff
4070///
4071/// @param first the first array_type of the diff.
4072///
4073/// @param second the second array_type of the diff.
4074///
4075/// @param element_type_diff the diff between the two array element
4076/// types.
4077///
4078/// @param ctxt the diff context to use.
4080 const array_type_def_sptr second,
4081 diff_sptr element_type_diff,
4082 vector<subrange_diff_sptr>& subrange_diffs,
4083 diff_context_sptr ctxt)
4084 : type_diff_base(first, second, ctxt),
4085 priv_(new priv(element_type_diff, subrange_diffs))
4086{}
4087
4088/// Getter for the first array of the diff.
4089///
4090/// @return the first array of the diff.
4093{return dynamic_pointer_cast<array_type_def>(first_subject());}
4094
4095/// Getter for the second array of the diff.
4096///
4097/// @return for the second array of the diff.
4100{return dynamic_pointer_cast<array_type_def>(second_subject());}
4101
4102/// Getter for the diff between the two types of array elements.
4103///
4104/// @return the diff between the two types of array elements.
4105const diff_sptr&
4107{return priv_->element_type_diff_;}
4108
4109/// Getter for the diffs between the array subranges.
4110///
4111/// @return the diffs between the array subranges.
4112const vector<subrange_diff_sptr>&
4114{return priv_->subrange_diffs_;}
4115
4116/// Test if any subrange diff is to be reported.
4117///
4118/// @return true if any subrange diff is to be reported, false
4119/// otherwise.
4120bool
4122{
4123 for (const auto& diff: subrange_diffs())
4124 if (diff->to_be_reported())
4125 return true;
4126
4127 return false;
4128}
4129
4130/// Setter for the diff between the two array element types.
4131///
4132/// @param d the new diff between the two array element types.
4133void
4135{priv_->element_type_diff_ = d;}
4136
4137/// Setter for the diff between the two sets of array sub-ranges.
4138///
4139/// @param d the new diff between the two sets of array sub-ranges.
4140void
4141array_diff::subrange_diffs(const vector<subrange_diff_sptr>& d)
4142{priv_->subrange_diffs_ = d;}
4143
4144/// @return the pretty representation for the current instance of @ref
4145/// array_diff.
4146const string&
4148{
4149 if (diff::priv_->pretty_representation_.empty())
4150 {
4151 std::ostringstream o;
4152 o << "array_diff["
4153 << first_subject()->get_pretty_representation()
4154 << ", "
4155 << second_subject()->get_pretty_representation()
4156 << "]";
4157 diff::priv_->pretty_representation_ = o.str();
4158 }
4159 return diff::priv_->pretty_representation_;
4160}
4161
4162/// Return true iff the current diff node carries a change.
4163///
4164/// @return true iff the current diff node carries a change.
4165bool
4167{
4168 bool l = false;
4169
4170 // the array element types match check for differing dimensions
4171 // etc...
4173 f = dynamic_pointer_cast<array_type_def>(first_subject()),
4174 s = dynamic_pointer_cast<array_type_def>(second_subject());
4175
4176 if (f->get_name() != s->get_name())
4177 l |= true;
4178 if (f->get_size_in_bits() != s->get_size_in_bits())
4179 l |= true;
4180 if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
4181 l |= true;
4182
4183 l |= element_type_diff()
4184 ? element_type_diff()->has_changes()
4185 : false;
4186
4187 for (const auto& subrange_diff : subrange_diffs())
4188 l |= subrange_diff->has_changes();
4189
4190 return l;
4191}
4192
4193
4194/// @return the kind of local change carried by the current diff node.
4195/// The value returned is zero if the current node carries no local
4196/// change.
4197enum change_kind
4199{
4200 ir::change_kind k = ir::NO_CHANGE_KIND;
4201 if (!equals(*first_array(), *second_array(), &k))
4202 return k & ir::ALL_LOCAL_CHANGES_MASK;
4203 return ir::NO_CHANGE_KIND;
4204}
4205
4206/// Report the diff in a serialized form.
4207///
4208/// @param out the output stream to serialize the dif to.
4209///
4210/// @param indent the string to use for indenting the report.
4211void
4212array_diff::report(ostream& out, const string& indent) const
4213{
4214 context()->get_reporter()->report(*this, out, indent);
4215}
4216
4217/// Compute the diff between two arrays.
4218///
4219/// Note that the two types must have been created in the same @ref
4220/// environment, otherwise, this function aborts.
4221///
4222/// @param first the first array to consider for the diff.
4223///
4224/// @param second the second array to consider for the diff.
4225///
4226/// @param ctxt the diff context to use.
4229 array_type_def_sptr second,
4230 diff_context_sptr ctxt)
4231{
4232 diff_sptr element_diff = compute_diff_for_types(first->get_element_type(),
4233 second->get_element_type(),
4234 ctxt);
4235 vector<subrange_diff_sptr> subrange_diffs;
4236 if (first->get_subranges().size() == first->get_subranges().size())
4237 {
4238 for (unsigned i = 0; i < first->get_subranges().size(); ++i)
4239 {
4241 compute_diff(first->get_subranges()[i],
4242 second->get_subranges()[i],
4243 ctxt);
4244 subrange_diffs.push_back(subrange_diff);
4245 }
4246 }
4247 array_diff_sptr result(new array_diff(first, second,
4248 element_diff,
4249 subrange_diffs,
4250 ctxt));
4251 ctxt->initialize_canonical_diff(result);
4252 return result;
4253}
4254// </array_type_def>
4255
4256// <reference_type_def>
4257
4258/// Populate the vector of children node of the @ref diff base type
4259/// sub-object of this instance of @ref reference_diff.
4260///
4261/// The children node can then later be retrieved using
4262/// diff::children_node().
4263void
4266
4267/// Constructor for reference_diff
4268///
4269/// @param first the first reference_type of the diff.
4270///
4271/// @param second the second reference_type of the diff.
4272///
4273/// @param ctxt the diff context to use.
4275 const reference_type_def_sptr second,
4276 diff_sptr underlying,
4277 diff_context_sptr ctxt)
4278 : type_diff_base(first, second, ctxt),
4279 priv_(new priv(underlying))
4280{}
4281
4282/// Getter for the first reference of the diff.
4283///
4284/// @return the first reference of the diff.
4287{return dynamic_pointer_cast<reference_type_def>(first_subject());}
4288
4289/// Getter for the second reference of the diff.
4290///
4291/// @return for the second reference of the diff.
4294{return dynamic_pointer_cast<reference_type_def>(second_subject());}
4295
4296
4297/// Getter for the diff between the two referred-to types.
4298///
4299/// @return the diff between the two referred-to types.
4300const diff_sptr&
4302{return priv_->underlying_type_diff_;}
4303
4304/// Setter for the diff between the two referred-to types.
4305///
4306/// @param d the new diff betweend the two referred-to types.
4307diff_sptr&
4309{
4310 priv_->underlying_type_diff_ = d;
4311 return priv_->underlying_type_diff_;
4312}
4313
4314/// @return the pretty representation for the current instance of @ref
4315/// reference_diff.
4316const string&
4318{
4319 if (diff::priv_->pretty_representation_.empty())
4320 {
4321 std::ostringstream o;
4322 o << "reference_diff["
4323 << first_subject()->get_pretty_representation()
4324 << ", "
4325 << second_subject()->get_pretty_representation()
4326 << "]";
4327 diff::priv_->pretty_representation_ = o.str();
4328 }
4329 return diff::priv_->pretty_representation_;
4330}
4331
4332/// Return true iff the current diff node carries a change.
4333///
4334/// @return true iff the current diff node carries a change.
4335bool
4337{
4338 return first_reference() != second_reference();
4339}
4340
4341/// @return the kind of local change carried by the current diff node.
4342/// The value returned is zero if the current node carries no local
4343/// change.
4344enum change_kind
4346{
4347 ir::change_kind k = ir::NO_CHANGE_KIND;
4348 if (!equals(*first_reference(), *second_reference(), &k))
4349 return k & ir::ALL_LOCAL_CHANGES_MASK;
4350 return ir::NO_CHANGE_KIND;
4351}
4352
4353/// Report the diff in a serialized form.
4354///
4355/// @param out the output stream to serialize the dif to.
4356///
4357/// @param indent the string to use for indenting the report.
4358void
4359reference_diff::report(ostream& out, const string& indent) const
4360{
4361 context()->get_reporter()->report(*this, out, indent);
4362}
4363
4364/// Compute the diff between two references.
4365///
4366/// Note that the two types must have been created in the same @ref
4367/// environment, otherwise, this function aborts.
4368///
4369/// @param first the first reference to consider for the diff.
4370///
4371/// @param second the second reference to consider for the diff.
4372///
4373/// @param ctxt the diff context to use.
4377 diff_context_sptr ctxt)
4378{
4379 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4380 second->get_pointed_to_type(),
4381 ctxt);
4382 reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4383 ctxt->initialize_canonical_diff(result);
4384 return result;
4385}
4386// </reference_type_def>
4387
4388// <ptr_to_mbr_diff stuff>
4389
4390
4391/// Constructor of @ref ptr_to_mbr_diff.
4392///
4393/// @param first the first pointer-to-member subject of the diff.
4394///
4395/// @param second the second pointer-to-member subject of the diff.
4396///
4397/// @param member_type_diff the diff node carrying changes to the
4398/// member type of the pointer-to-member we are considering.
4399///
4400/// @param containing_type_diff the diff node carrying changes to the
4401/// containing type of the pointer-to-member we are considering.
4402///
4403/// @param ctxt the context of the diff we are considering.
4404ptr_to_mbr_diff::ptr_to_mbr_diff(const ptr_to_mbr_type_sptr& first,
4405 const ptr_to_mbr_type_sptr& second,
4406 const diff_sptr& member_type_diff,
4407 const diff_sptr& containing_type_diff,
4408 diff_context_sptr ctxt)
4409 : type_diff_base(first, second, ctxt),
4410 priv_(new priv(member_type_diff, containing_type_diff))
4411{}
4412
4413/// Getter of the first pointer-to-member subject of the current diff
4414/// node.
4415///
4416/// @return the first pointer-to-member subject of the current diff
4417/// node.
4420{return dynamic_pointer_cast<ptr_to_mbr_type>(first_subject());}
4421
4422/// Getter of the second pointer-to-member subject of the current diff
4423/// node.
4424///
4425/// @return the second pointer-to-member subject of the current diff
4426/// node.
4429{return dynamic_pointer_cast<ptr_to_mbr_type>(second_subject());}
4430
4431/// Getter of the diff node carrying changes to the member type of
4432/// first subject of the current diff node.
4433///
4434/// @return The diff node carrying changes to the member type of first
4435/// subject of the current diff node.
4436const diff_sptr
4438{return priv_->member_type_diff_;}
4439
4440/// Getter of the diff node carrying changes to the containing type of
4441/// first subject of the current diff node.
4442///
4443/// @return The diff node carrying changes to the containing type of
4444/// first subject of the current diff node.
4445const diff_sptr
4447{return priv_->containing_type_diff_;}
4448
4449/// Test whether the current diff node carries any change.
4450///
4451/// @return true iff the current diff node carries any change.
4452bool
4454{
4456}
4457
4458/// Test whether the current diff node carries any local change.
4459///
4460/// @return true iff the current diff node carries any local change.
4461enum change_kind
4463{
4464 ir::change_kind k = ir::NO_CHANGE_KIND;
4466 return k & ir::ALL_LOCAL_CHANGES_MASK;
4467 return ir::NO_CHANGE_KIND;
4468}
4469
4470/// Get the pretty representation of the current @ref ptr_to_mbr_diff
4471/// node.
4472///
4473/// @return the pretty representation of the current diff node.
4474const string&
4476{
4477 if (diff::priv_->pretty_representation_.empty())
4478 {
4479 std::ostringstream o;
4480 o << "ptr_to_mbr_diff["
4481 << first_subject()->get_pretty_representation()
4482 << ", "
4483 << second_subject()->get_pretty_representation()
4484 << "]";
4485 diff::priv_->pretty_representation_ = o.str();
4486 }
4487 return diff::priv_->pretty_representation_;
4488}
4489
4490void
4491ptr_to_mbr_diff::report(ostream& out, const string& indent) const
4492{
4493 context()->get_reporter()->report(*this, out, indent);
4494}
4495
4496/// Populate the vector of children node of the @ref diff base type
4497/// sub-object of this instance of @ref ptr_to_mbr_diff.
4498///
4499/// The children node can then later be retrieved using
4500/// diff::children_node().
4501void
4503{
4506}
4507
4508/// Destructor of @ref ptr_to_mbr_diff.
4510{
4511}
4512
4513/// Compute the diff between two @ref ptr_to_mbr_type types.
4514///
4515/// Note that the two types must have been created in the same @ref
4516/// environment, otherwise, this function aborts.
4517///
4518/// @param first the first pointer-to-member type to consider for the diff.
4519///
4520/// @param second the second pointer-to-member type to consider for the diff.
4521///
4522/// @param ctxt the diff context to use.
4525 const ptr_to_mbr_type_sptr& second,
4526 diff_context_sptr& ctxt)
4527{
4528 diff_sptr member_type_diff =
4529 compute_diff(is_type(first->get_member_type()),
4530 is_type(second->get_member_type()),
4531 ctxt);
4532
4533 diff_sptr containing_type_diff =
4534 compute_diff(is_type(first->get_containing_type()),
4535 is_type(second->get_containing_type()),
4536 ctxt);
4537
4538 ptr_to_mbr_diff_sptr result(new ptr_to_mbr_diff(first, second,
4539 member_type_diff,
4540 containing_type_diff,
4541 ctxt));
4542 ctxt->initialize_canonical_diff(result);
4543 return result;
4544}
4545
4546// </ptr_to_mbr_diff stuff>
4547
4548// <qualified_type_diff stuff>
4549
4550/// Populate the vector of children node of the @ref diff base type
4551/// sub-object of this instance of @ref qualified_type_diff.
4552///
4553/// The children node can then later be retrieved using
4554/// diff::children_node().
4555void
4558
4559/// Constructor for qualified_type_diff.
4560///
4561/// @param first the first qualified type of the diff.
4562///
4563/// @param second the second qualified type of the diff.
4564///
4565/// @param ctxt the diff context to use.
4566qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4567 qualified_type_def_sptr second,
4568 diff_sptr under,
4569 diff_context_sptr ctxt)
4570 : type_diff_base(first, second, ctxt),
4571 priv_(new priv(under))
4572{}
4573
4574/// Getter for the first qualified type of the diff.
4575///
4576/// @return the first qualified type of the diff.
4577const qualified_type_def_sptr
4579{return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4580
4581/// Getter for the second qualified type of the diff.
4582///
4583/// @return the second qualified type of the diff.
4584const qualified_type_def_sptr
4586{return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4587
4588/// Getter for the diff between the underlying types of the two
4589/// qualified types.
4590///
4591/// @return the diff between the underlying types of the two qualified
4592/// types.
4595{return priv_->underlying_type_diff;}
4596
4597/// Getter for the diff between the most underlying non-qualified
4598/// types of two qualified types.
4599///
4600/// @return the diff between the most underlying non-qualified types
4601/// of two qualified types.
4604{
4605 if (!priv_->leaf_underlying_type_diff)
4606 priv_->leaf_underlying_type_diff
4607 = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4609 context());
4610
4611 return priv_->leaf_underlying_type_diff;
4612}
4613
4614/// Setter for the diff between the underlying types of the two
4615/// qualified types.
4616///
4617/// @return the diff between the underlying types of the two qualified
4618/// types.
4619void
4621{priv_->underlying_type_diff = d;}
4622
4623/// @return the pretty representation of the current instance of @ref
4624/// qualified_type_diff.
4625const string&
4627{
4628 if (diff::priv_->pretty_representation_.empty())
4629 {
4630 std::ostringstream o;
4631 o << "qualified_type_diff["
4632 << first_subject()->get_pretty_representation()
4633 << ", "
4634 << second_subject()->get_pretty_representation()
4635 << "]";
4636 diff::priv_->pretty_representation_ = o.str();
4637 }
4638 return diff::priv_->pretty_representation_;
4639}
4640
4641/// Return true iff the current diff node carries a change.
4642///
4643/// @return true iff the current diff node carries a change.
4644bool
4647
4648/// @return the kind of local change carried by the current diff node.
4649/// The value returned is zero if the current node carries no local
4650/// change.
4651enum change_kind
4653{
4654 ir::change_kind k = ir::NO_CHANGE_KIND;
4656 return k & ir::ALL_LOCAL_CHANGES_MASK;
4657 return ir::NO_CHANGE_KIND;
4658}
4659
4660/// Report the diff in a serialized form.
4661///
4662/// @param out the output stream to serialize to.
4663///
4664/// @param indent the string to use to indent the lines of the report.
4665void
4666qualified_type_diff::report(ostream& out, const string& indent) const
4667{
4668 context()->get_reporter()->report(*this, out, indent);
4669}
4670
4671/// Compute the diff between two qualified types.
4672///
4673/// Note that the two types must have been created in the same @ref
4674/// environment, otherwise, this function aborts.
4675///
4676/// @param first the first qualified type to consider for the diff.
4677///
4678/// @param second the second qualified type to consider for the diff.
4679///
4680/// @param ctxt the diff context to use.
4681qualified_type_diff_sptr
4682compute_diff(const qualified_type_def_sptr first,
4683 const qualified_type_def_sptr second,
4684 diff_context_sptr ctxt)
4685{
4686 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4687 second->get_underlying_type(),
4688 ctxt);
4689 qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4690 d, ctxt));
4691 ctxt->initialize_canonical_diff(result);
4692 return result;
4693}
4694
4695// </qualified_type_diff stuff>
4696
4697// <enum_diff stuff>
4698
4699/// Clear the lookup tables useful for reporting an enum_diff.
4700///
4701/// This function must be updated each time a lookup table is added or
4702/// removed from the class_diff::priv.
4703void
4704enum_diff::clear_lookup_tables()
4705{
4706 priv_->deleted_enumerators_.clear();
4707 priv_->inserted_enumerators_.clear();
4708 priv_->changed_enumerators_.clear();
4709}
4710
4711/// Tests if the lookup tables are empty.
4712///
4713/// @return true if the lookup tables are empty, false otherwise.
4714bool
4715enum_diff::lookup_tables_empty() const
4716{
4717 return (priv_->deleted_enumerators_.empty()
4718 && priv_->inserted_enumerators_.empty()
4719 && priv_->changed_enumerators_.empty());
4720}
4721
4722/// If the lookup tables are not yet built, walk the differences and
4723/// fill the lookup tables.
4724void
4725enum_diff::ensure_lookup_tables_populated()
4726{
4727 if (!lookup_tables_empty())
4728 return;
4729
4730 {
4731 edit_script e = priv_->enumerators_changes_;
4732
4733 for (vector<deletion>::const_iterator it = e.deletions().begin();
4734 it != e.deletions().end();
4735 ++it)
4736 {
4737 unsigned i = it->index();
4738 const enum_type_decl::enumerator& n =
4739 first_enum()->get_enumerators()[i];
4740 const string& name = n.get_name();
4741 ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4742 == priv_->deleted_enumerators_.end());
4743 priv_->deleted_enumerators_[name] = n;
4744 }
4745
4746 for (vector<insertion>::const_iterator it = e.insertions().begin();
4747 it != e.insertions().end();
4748 ++it)
4749 {
4750 for (vector<unsigned>::const_iterator iit =
4751 it->inserted_indexes().begin();
4752 iit != it->inserted_indexes().end();
4753 ++iit)
4754 {
4755 unsigned i = *iit;
4756 const enum_type_decl::enumerator& n =
4757 second_enum()->get_enumerators()[i];
4758 const string& name = n.get_name();
4759 ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4760 == priv_->inserted_enumerators_.end());
4761 string_enumerator_map::const_iterator j =
4762 priv_->deleted_enumerators_.find(name);
4763 if (j == priv_->deleted_enumerators_.end())
4764 priv_->inserted_enumerators_[name] = n;
4765 else
4766 {
4767 if (j->second != n)
4768 priv_->changed_enumerators_[j->first] =
4769 std::make_pair(j->second, n);
4770 priv_->deleted_enumerators_.erase(j);
4771 }
4772 }
4773 }
4774
4775 // If a new enumerator is added with a value that already existed
4776 // in the old enum but with a new name, then populate the
4777 // enum_diff::priv_::changed_enumerators_ data member with a
4778 // change that represents a change to an enumerator name. The
4779 // enum_diff::priv_::inserted_enumerators_ is adjusted accordingly
4780 // an the 'new' enumerator is removed in this case.
4781
4782 enum_type_decl::enumerators enums_to_erase;
4783 for (auto& entry : priv_->inserted_enumerators_)
4784 {
4785 enum_type_decl::enumerator& final_enumerator = entry.second;
4786 enum_type_decl::enumerator initial_enumerator;
4787 if (first_enum()->find_enumerator_by_value(entry.second.get_value(),
4788 initial_enumerator))
4789 {
4790 enum_type_decl::enumerator foo;
4791 if (!second_enum()->
4792 find_enumerator_by_name(initial_enumerator.get_name(),
4793 foo))
4794 {
4795 priv_->changed_enumerators_[initial_enumerator.get_name()] =
4796 std::make_pair(initial_enumerator, final_enumerator);
4797 enums_to_erase.push_back(final_enumerator);
4798 }
4799 }
4800 }
4801
4802 for (auto& enomerator : enums_to_erase)
4803 priv_->inserted_enumerators_.erase(enomerator.get_name());
4804
4805 // If an enumerator is deleted yet its value (with a new name) is
4806 // still present among enumerators of the newer enum then populate
4807 // the enum_diff::priv_::changed_enumerators_ data member with a
4808 // change that represents a change to an enumerator name. The
4809 // enum_diff::priv_::deleted_enumerators_ is adjusted accordingly
4810 // an the 'new' enumerator is removed in this case.
4811
4812 enums_to_erase.clear();
4813 for (auto& entry : priv_->deleted_enumerators_)
4814 {
4815 enum_type_decl::enumerator& initial_enumerator = entry.second;
4816 enum_type_decl::enumerator final_enumerator;
4817 if (second_enum()->find_enumerator_by_value(entry.second.get_value(),
4818 final_enumerator))
4819 {
4820 enum_type_decl::enumerator foo;
4821 if (!first_enum()->
4822 find_enumerator_by_name(final_enumerator.get_name(),
4823 foo))
4824 {
4825 priv_->changed_enumerators_[initial_enumerator.get_name()] =
4826 std::make_pair(initial_enumerator, final_enumerator);
4827 enums_to_erase.push_back(initial_enumerator);
4828 }
4829 }
4830 }
4831
4832 for (auto& enomerator : enums_to_erase)
4833 priv_->deleted_enumerators_.erase(enomerator.get_name());
4834 }
4835}
4836
4837/// Populate the vector of children node of the @ref diff base type
4838/// sub-object of this instance of @ref enum_diff.
4839///
4840/// The children node can then later be retrieved using
4841/// diff::children_node().
4842void
4845
4846/// Constructor for enum_diff.
4847///
4848/// @param first the first enum type of the diff.
4849///
4850/// @param second the second enum type of the diff.
4851///
4852/// @param underlying_type_diff the diff of the two underlying types
4853/// of the two enum types.
4854///
4855/// @param ctxt the diff context to use.
4857 const enum_type_decl_sptr second,
4858 const diff_sptr underlying_type_diff,
4859 const diff_context_sptr ctxt)
4860 : type_diff_base(first, second, ctxt),
4861 priv_(new priv(underlying_type_diff))
4862{}
4863
4864/// @return the first enum of the diff.
4867{return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4868
4869/// @return the second enum of the diff.
4872{return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4873
4874/// @return the diff of the two underlying enum types.
4877{return priv_->underlying_type_diff_;}
4878
4879/// @return a map of the enumerators that were deleted.
4882{return priv_->deleted_enumerators_;}
4883
4884/// @return a map of the enumerators that were inserted
4887{return priv_->inserted_enumerators_;}
4888
4889/// @return a map of the enumerators that were changed
4892{return priv_->changed_enumerators_;}
4893
4894/// @return the pretty representation of the current instance of @ref
4895/// enum_diff.
4896const string&
4898{
4899 if (diff::priv_->pretty_representation_.empty())
4900 {
4901 std::ostringstream o;
4902 o << "enum_diff["
4903 << first_subject()->get_pretty_representation()
4904 << ", "
4905 << second_subject()->get_pretty_representation()
4906 << "]";
4907 diff::priv_->pretty_representation_ = o.str();
4908 }
4909 return diff::priv_->pretty_representation_;
4910}
4911
4912/// Return true iff the current diff node carries a change.
4913///
4914/// @return true iff the current diff node carries a change.
4915bool
4917{return first_enum() != second_enum();}
4918
4919/// @return the kind of local change carried by the current diff node.
4920/// The value returned is zero if the current node carries no local
4921/// change.
4922enum change_kind
4924{
4925 ir::change_kind k = ir::NO_CHANGE_KIND;
4926 if (!equals(*first_enum(), *second_enum(), &k))
4927 return k & ir::ALL_LOCAL_CHANGES_MASK;
4928 return ir::NO_CHANGE_KIND;
4929}
4930
4931/// Report the differences between the two enums.
4932///
4933/// @param out the output stream to send the report to.
4934///
4935/// @param indent the string to use for indentation.
4936void
4937enum_diff::report(ostream& out, const string& indent) const
4938{
4939 context()->get_reporter()->report(*this, out, indent);
4940}
4941
4942/// Compute the set of changes between two instances of @ref
4943/// enum_type_decl.
4944///
4945/// Note that the two types must have been created in the same @ref
4946/// environment, otherwise, this function aborts.
4947///
4948/// @param first a pointer to the first enum_type_decl to consider.
4949///
4950/// @param second a pointer to the second enum_type_decl to consider.
4951///
4952/// @return the resulting diff of the two enums @p first and @p
4953/// second.
4954///
4955/// @param ctxt the diff context to use.
4956enum_diff_sptr
4958 const enum_type_decl_sptr second,
4959 diff_context_sptr ctxt)
4960{
4961 diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4962 second->get_underlying_type(),
4963 ctxt);
4964 enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4965 if (first != second)
4966 {
4967 compute_diff(first->get_enumerators().begin(),
4968 first->get_enumerators().end(),
4969 second->get_enumerators().begin(),
4970 second->get_enumerators().end(),
4971 d->priv_->enumerators_changes_);
4972 d->ensure_lookup_tables_populated();
4973 }
4974 ctxt->initialize_canonical_diff(d);
4975
4976 return d;
4977}
4978// </enum_diff stuff>
4979
4980// <class_or_union_diff stuff>
4981
4982/// Test if the current diff node carries a member type change for a
4983/// member type which name is the same as the name of a given type
4984/// declaration.
4985///
4986/// @param d the type declaration which name should be equal to the
4987/// name of the member type that might have changed.
4988///
4989/// @return the member type that has changed, iff there were a member
4990/// type (which name is the same as the name of @p d) that changed.
4991/// Note that the member type that is returned is the new value of the
4992/// member type that changed.
4995{
4996 string qname = d->get_qualified_name();
4997 string_diff_sptr_map::const_iterator it =
4998 changed_member_types_.find(qname);
4999
5000 return ((it == changed_member_types_.end())
5002 : it->second->second_subject());
5003}
5004
5005/// Test if the current diff node carries a data member change for a
5006/// data member which name is the same as the name of a given type
5007/// declaration.
5008///
5009/// @param d the type declaration which name should be equal to the
5010/// name of the data member that might have changed.
5011///
5012/// @return the data member that has changed, iff there were a data
5013/// member type (which name is the same as the name of @p d) that
5014/// changed. Note that the data member that is returned is the new
5015/// value of the data member that changed.
5016decl_base_sptr
5018{
5019 string qname = d->get_qualified_name();
5020 string_var_diff_sptr_map::const_iterator it =
5021 subtype_changed_dm_.find(qname);
5022
5023 if (it == subtype_changed_dm_.end())
5024 return decl_base_sptr();
5025 return it->second->second_var();
5026}
5027
5028/// Test if the current diff node carries a member class template
5029/// change for a member class template which name is the same as the
5030/// name of a given type declaration.
5031///
5032/// @param d the type declaration which name should be equal to the
5033/// name of the member class template that might have changed.
5034///
5035/// @return the member class template that has changed, iff there were
5036/// a member class template (which name is the same as the name of @p
5037/// d) that changed. Note that the member class template that is
5038/// returned is the new value of the member class template that
5039/// changed.
5040decl_base_sptr
5042{
5043 string qname = d->get_qualified_name();
5044 string_diff_sptr_map::const_iterator it =
5045 changed_member_class_tmpls_.find(qname);
5046
5047 return ((it == changed_member_class_tmpls_.end())
5048 ? decl_base_sptr()
5049 : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
5050}
5051
5052/// Get the number of non static data members that were deleted.
5053///
5054/// @return the number of non static data members that were deleted.
5055size_t
5057{
5058 size_t result = 0;
5059
5060 for (string_decl_base_sptr_map::const_iterator i =
5061 deleted_data_members_.begin();
5062 i != deleted_data_members_.end();
5063 ++i)
5064 if (is_member_decl(i->second)
5065 && !get_member_is_static(i->second))
5066 ++result;
5067
5068 return result;
5069}
5070
5071/// Get the number of non static data members that were inserted.
5072///
5073/// @return the number of non static data members that were inserted.
5074size_t
5076{
5077 size_t result = 0;
5078
5079 for (string_decl_base_sptr_map::const_iterator i =
5080 inserted_data_members_.begin();
5081 i != inserted_data_members_.end();
5082 ++i)
5083 if (is_member_decl(i->second)
5084 && !get_member_is_static(i->second))
5085 ++result;
5086
5087 return result;
5088}
5089
5090/// Get the number of data member sub-type changes carried by the
5091/// current diff node that were filtered out.
5092///
5093/// @param local_only if true, it means that only (filtered) local
5094/// changes are considered.
5095///
5096/// @return the number of data member sub-type changes carried by the
5097/// current diff node that were filtered out.
5098size_t
5100{
5101 size_t num_filtered= 0;
5102 for (var_diff_sptrs_type::const_iterator i =
5103 sorted_subtype_changed_dm_.begin();
5104 i != sorted_subtype_changed_dm_.end();
5105 ++i)
5106 {
5107 if (local_only)
5108 {
5109 if ((*i)->has_local_changes() && (*i)->is_filtered_out())
5110 ++num_filtered;
5111 }
5112 else
5113 {
5114 if ((*i)->is_filtered_out())
5115 ++num_filtered;
5116 }
5117 }
5118 return num_filtered;
5119}
5120
5121/// Get the number of data member changes carried by the current diff
5122/// node that were filtered out.
5123///
5124/// @param local_only if true, it means that only (filtered) local
5125/// changes are considered.
5126///
5127/// @return the number of data member changes carried by the current
5128/// diff node that were filtered out.
5129size_t
5131{
5132 size_t num_filtered= 0;
5133
5134 for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
5135 i != changed_dm_.end();
5136 ++i)
5137 {
5138 diff_sptr diff = i->second;
5139 if (local_only)
5140 {
5141 if (diff->has_changes() && diff->is_filtered_out())
5142 ++num_filtered;
5143 }
5144 else
5145 {
5146 if (diff->is_filtered_out())
5147 ++num_filtered;
5148 }
5149 }
5150 return num_filtered;
5151}
5152
5153/// Skip the processing of the current member function if its
5154/// virtual-ness is disallowed by the user.
5155///
5156/// This is to be used in the member functions below that are used to
5157/// count the number of filtered inserted, deleted and changed member
5158/// functions.
5159#define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
5160 do { \
5161 if (get_member_function_is_virtual(f) \
5162 || get_member_function_is_virtual(s)) \
5163 { \
5164 if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
5165 continue; \
5166 } \
5167 else \
5168 { \
5169 if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
5170 continue; \
5171 } \
5172 } while (false)
5173
5174/// Get the number of member functions changes carried by the current
5175/// diff node that were filtered out.
5176///
5177/// @return the number of member functions changes carried by the
5178/// current diff node that were filtered out.
5179size_t
5181(const diff_context_sptr& ctxt)
5182{
5183 size_t count = 0;
5184 diff_category allowed_category = ctxt->get_allowed_category();
5185
5186 for (function_decl_diff_sptrs_type::const_iterator i =
5187 sorted_changed_member_functions_.begin();
5188 i != sorted_changed_member_functions_.end();
5189 ++i)
5190 {
5191 method_decl_sptr f =
5192 dynamic_pointer_cast<method_decl>
5193 ((*i)->first_function_decl());
5194 ABG_ASSERT(f);
5195
5196 method_decl_sptr s =
5197 dynamic_pointer_cast<method_decl>
5198 ((*i)->second_function_decl());
5199 ABG_ASSERT(s);
5200
5202
5203 diff_sptr diff = *i;
5204 ctxt->maybe_apply_filters(diff);
5205
5206 if (diff->is_filtered_out())
5207 ++count;
5208 }
5209
5210 return count;
5211}
5212
5213/// Get the number of member functions insertions carried by the current
5214/// diff node that were filtered out.
5215///
5216/// @return the number of member functions insertions carried by the
5217/// current diff node that were filtered out.
5218size_t
5220(const diff_context_sptr& ctxt)
5221{
5222 size_t count = 0;
5223 diff_category allowed_category = ctxt->get_allowed_category();
5224
5225 for (string_member_function_sptr_map::const_iterator i =
5226 inserted_member_functions_.begin();
5227 i != inserted_member_functions_.end();
5228 ++i)
5229 {
5230 method_decl_sptr f = i->second,
5231 s = i->second;
5232
5234
5235 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5236 ctxt->maybe_apply_filters(diff);
5237
5239 && diff->is_filtered_out())
5240 ++count;
5241 }
5242
5243 return count;
5244}
5245
5246/// Get the number of member functions deletions carried by the current
5247/// diff node that were filtered out.
5248///
5249/// @return the number of member functions deletions carried by the
5250/// current diff node that were filtered out.
5251size_t
5253(const diff_context_sptr& ctxt)
5254{
5255 size_t count = 0;
5256 diff_category allowed_category = ctxt->get_allowed_category();
5257
5258 for (string_member_function_sptr_map::const_iterator i =
5259 deleted_member_functions_.begin();
5260 i != deleted_member_functions_.end();
5261 ++i)
5262 {
5263 method_decl_sptr f = i->second,
5264 s = i->second;
5265
5267
5268 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5269 ctxt->maybe_apply_filters(diff);
5270
5272 && diff->is_filtered_out())
5273 ++count;
5274 }
5275
5276 return count;
5277}
5278
5279/// Clear the lookup tables useful for reporting.
5280///
5281/// This function must be updated each time a lookup table is added or
5282/// removed from the class_or_union_diff::priv.
5283void
5285{
5286 priv_->deleted_member_types_.clear();
5287 priv_->inserted_member_types_.clear();
5288 priv_->changed_member_types_.clear();
5289 priv_->deleted_data_members_.clear();
5290 priv_->inserted_data_members_.clear();
5291 priv_->subtype_changed_dm_.clear();
5292 priv_->deleted_member_functions_.clear();
5293 priv_->inserted_member_functions_.clear();
5294 priv_->changed_member_functions_.clear();
5295 priv_->deleted_member_class_tmpls_.clear();
5296 priv_->inserted_member_class_tmpls_.clear();
5297 priv_->changed_member_class_tmpls_.clear();
5298}
5299
5300/// Tests if the lookup tables are empty.
5301///
5302/// @return true if the lookup tables are empty, false otherwise.
5303bool
5305{
5306 return (priv_->deleted_member_types_.empty()
5307 && priv_->inserted_member_types_.empty()
5308 && priv_->changed_member_types_.empty()
5309 && priv_->deleted_data_members_.empty()
5310 && priv_->inserted_data_members_.empty()
5311 && priv_->subtype_changed_dm_.empty()
5312 && priv_->inserted_member_functions_.empty()
5313 && priv_->deleted_member_functions_.empty()
5314 && priv_->changed_member_functions_.empty()
5315 && priv_->deleted_member_class_tmpls_.empty()
5316 && priv_->inserted_member_class_tmpls_.empty()
5317 && priv_->changed_member_class_tmpls_.empty());
5318}
5319
5320/// If the lookup tables are not yet built, walk the differences and
5321/// fill them.
5322void
5324{
5325 {
5326 edit_script& e = priv_->member_types_changes_;
5327
5328 for (vector<deletion>::const_iterator it = e.deletions().begin();
5329 it != e.deletions().end();
5330 ++it)
5331 {
5332 unsigned i = it->index();
5333 decl_base_sptr d =
5334 get_type_declaration(first_class_or_union()->get_member_types()[i]);
5335 class_or_union_sptr record_type = is_class_or_union_type(d);
5336 if (record_type && record_type->get_is_declaration_only())
5337 continue;
5338 string name = d->get_name();
5339 priv_->deleted_member_types_[name] = d;
5340 }
5341
5342 for (vector<insertion>::const_iterator it = e.insertions().begin();
5343 it != e.insertions().end();
5344 ++it)
5345 {
5346 for (vector<unsigned>::const_iterator iit =
5347 it->inserted_indexes().begin();
5348 iit != it->inserted_indexes().end();
5349 ++iit)
5350 {
5351 unsigned i = *iit;
5352 decl_base_sptr d =
5353 get_type_declaration(second_class_or_union()->get_member_types()[i]);
5354 class_or_union_sptr record_type = is_class_or_union_type(d);
5355 if (record_type && record_type->get_is_declaration_only())
5356 continue;
5357 string name = d->get_name();
5358 string_decl_base_sptr_map::const_iterator j =
5359 priv_->deleted_member_types_.find(name);
5360 if (j != priv_->deleted_member_types_.end())
5361 {
5362 if (*j->second != *d)
5363 priv_->changed_member_types_[name] =
5364 compute_diff(j->second, d, context());
5365
5366 priv_->deleted_member_types_.erase(j);
5367 }
5368 else
5369 priv_->inserted_member_types_[name] = d;
5370 }
5371 }
5372 }
5373
5374 {
5375 edit_script& e = priv_->data_members_changes_;
5376
5377 for (vector<deletion>::const_iterator it = e.deletions().begin();
5378 it != e.deletions().end();
5379 ++it)
5380 {
5381 unsigned i = it->index();
5382 var_decl_sptr data_member =
5383 is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
5384 string name = data_member->get_anon_dm_reliable_name();
5385
5386 ABG_ASSERT(priv_->deleted_data_members_.find(name)
5387 == priv_->deleted_data_members_.end());
5388 priv_->deleted_data_members_[name] = data_member;
5389 }
5390
5391 for (vector<insertion>::const_iterator it = e.insertions().begin();
5392 it != e.insertions().end();
5393 ++it)
5394 {
5395 for (vector<unsigned>::const_iterator iit =
5396 it->inserted_indexes().begin();
5397 iit != it->inserted_indexes().end();
5398 ++iit)
5399 {
5400 unsigned i = *iit;
5401 decl_base_sptr d =
5402 second_class_or_union()->get_non_static_data_members()[i];
5403 var_decl_sptr added_dm = is_var_decl(d);
5404 string name = added_dm->get_anon_dm_reliable_name();
5405 ABG_ASSERT(priv_->inserted_data_members_.find(name)
5406 == priv_->inserted_data_members_.end());
5407
5408 bool ignore_added_anonymous_data_member = false;
5409 if (is_anonymous_data_member(added_dm))
5410 {
5411 //
5412 // Handle insertion of anonymous data member to
5413 // replace existing data members.
5414 //
5415 // For instance consider this:
5416 // struct S
5417 // {
5418 // int a;
5419 // int b;
5420 // int c;
5421 // };// end struct S
5422 //
5423 // Where the data members 'a' and 'b' are replaced
5424 // by an anonymous data member without changing the
5425 // effective bit layout of the structure:
5426 //
5427 // struct S
5428 // {
5429 // struct
5430 // {
5431 // union
5432 // {
5433 // int a;
5434 // char a_1;
5435 // };
5436 // union
5437 // {
5438 // int b;
5439 // char b_1;
5440 // };
5441 // };
5442 // int c;
5443 // }; // end struct S
5444 //
5445 var_decl_sptr replaced_dm, replacing_dm;
5446 bool added_anon_dm_changes_dm = false;
5447 // The vector of data members replaced by anonymous
5448 // data members.
5449 vector<var_decl_sptr> dms_replaced_by_anon_dm;
5450
5451 //
5452 // Let's start collecting the set of data members
5453 // which have been replaced by anonymous types in a
5454 // harmless way. These are going to be collected into
5455 // dms_replaced_by_anon_dm and, ultimately, into
5456 // priv_->dms_replaced_by_adms_
5457 //
5458 for (string_decl_base_sptr_map::const_iterator it =
5459 priv_->deleted_data_members_.begin();
5460 it != priv_->deleted_data_members_.end();
5461 ++it)
5462 {
5463 // We don't support this pattern for anonymous
5464 // data members themselves being replaced. If
5465 // that occurs then we'll just report it verbatim.
5466 if (is_anonymous_data_member(it->second))
5467 continue;
5468
5469 string deleted_dm_name = it->second->get_name();
5470 if ((replacing_dm =
5472 deleted_dm_name)))
5473 {
5474 // So it looks like replacing_dm might have
5475 // replaced the data member which name is
5476 // 'deleted_dm_name'. Let's look deeper to be
5477 // sure.
5478 //
5479 // Note that replacing_dm is part (member) of
5480 // an anonymous data member that might replace
5481 // replaced_dm.
5482
5483 // So let's get that replaced data member.
5484 replaced_dm = is_var_decl(it->second);
5485 size_t replaced_dm_offset =
5486 get_data_member_offset(replaced_dm),
5487 replacing_dm_offset =
5488 get_absolute_data_member_offset(replacing_dm);
5489
5490 if (replaced_dm_offset != replacing_dm_offset)
5491 {
5492 // So the replacing data member and the
5493 // replaced data member don't have the
5494 // same offset. This is not the pattern we
5495 // are looking for. Rather, it looks like
5496 // the anonymous data member has *changed*
5497 // the data member.
5498 added_anon_dm_changes_dm = true;
5499 break;
5500 }
5501
5502 if (replaced_dm->get_type()->get_size_in_bits()
5503 == replaced_dm->get_type()->get_size_in_bits())
5504 dms_replaced_by_anon_dm.push_back(replaced_dm);
5505 else
5506 {
5507 added_anon_dm_changes_dm = true;
5508 break;
5509 }
5510 }
5511 }
5512
5513 // Now walk dms_replaced_by_anon_dm to fill up
5514 // priv_->dms_replaced_by_adms_ with the set of data
5515 // members replaced by anonymous data members.
5516 if (!added_anon_dm_changes_dm
5517 && !dms_replaced_by_anon_dm.empty())
5518 {
5519 // See if the added data member isn't too big.
5520 type_base_sptr added_dm_type = added_dm->get_type();
5521 ABG_ASSERT(added_dm_type);
5522 var_decl_sptr new_next_dm =
5524 added_dm);
5525 var_decl_sptr old_next_dm =
5526 first_class_or_union()->find_data_member(new_next_dm);
5527
5528 if (!old_next_dm
5529 || (old_next_dm
5530 && (get_absolute_data_member_offset(old_next_dm)
5531 == get_absolute_data_member_offset(new_next_dm))))
5532 {
5533 // None of the data members that are replaced
5534 // by the added union should be considered as
5535 // having been deleted.
5536 ignore_added_anonymous_data_member = true;
5537 for (vector<var_decl_sptr>::const_iterator i =
5538 dms_replaced_by_anon_dm.begin();
5539 i != dms_replaced_by_anon_dm.end();
5540 ++i)
5541 {
5542 string n = (*i)->get_name();
5543 priv_->dms_replaced_by_adms_[n] =
5544 added_dm;
5545 priv_->deleted_data_members_.erase(n);
5546 }
5547 }
5548 }
5549 }
5550
5551 if (!ignore_added_anonymous_data_member)
5552 {
5553 // Detect changed data members.
5554 //
5555 // A changed data member (that we shall name D) is a data
5556 // member that satisfies the conditions below:
5557 //
5558 // 1/ It must have been added.
5559 //
5560 // 2/ It must have been deleted as well.
5561 //
5562 // 3/ There must be a non-empty difference between the
5563 // deleted D and the added D.
5564 string_decl_base_sptr_map::const_iterator j =
5565 priv_->deleted_data_members_.find(name);
5566 if (j != priv_->deleted_data_members_.end())
5567 {
5568 if (*j->second != *d)
5569 {
5570 var_decl_sptr old_dm = is_var_decl(j->second);
5571 priv_->subtype_changed_dm_[name]=
5572 compute_diff(old_dm, added_dm, context());
5573 }
5574 priv_->deleted_data_members_.erase(j);
5575 }
5576 else
5577 priv_->inserted_data_members_[name] = d;
5578 }
5579 }
5580 }
5581
5582 // Now detect when a data member is deleted from offset N and
5583 // another one is added to offset N. In that case, we want to be
5584 // able to say that the data member at offset N changed.
5585 for (string_decl_base_sptr_map::const_iterator i =
5586 priv_->deleted_data_members_.begin();
5587 i != priv_->deleted_data_members_.end();
5588 ++i)
5589 {
5590 unsigned offset = get_data_member_offset(i->second);
5591 priv_->deleted_dm_by_offset_[offset] = i->second;
5592 }
5593
5594 for (string_decl_base_sptr_map::const_iterator i =
5595 priv_->inserted_data_members_.begin();
5596 i != priv_->inserted_data_members_.end();
5597 ++i)
5598 {
5599 unsigned offset = get_data_member_offset(i->second);
5600 priv_->inserted_dm_by_offset_[offset] = i->second;
5601 }
5602
5603 for (unsigned_decl_base_sptr_map::const_iterator i =
5604 priv_->inserted_dm_by_offset_.begin();
5605 i != priv_->inserted_dm_by_offset_.end();
5606 ++i)
5607 {
5608 unsigned_decl_base_sptr_map::const_iterator j =
5609 priv_->deleted_dm_by_offset_.find(i->first);
5610 if (j != priv_->deleted_dm_by_offset_.end())
5611 {
5612 var_decl_sptr old_dm = is_var_decl(j->second);
5613 var_decl_sptr new_dm = is_var_decl(i->second);
5614 priv_->changed_dm_[i->first] =
5615 compute_diff(old_dm, new_dm, context());
5616 }
5617 }
5618
5619 for (unsigned_var_diff_sptr_map::const_iterator i =
5620 priv_->changed_dm_.begin();
5621 i != priv_->changed_dm_.end();
5622 ++i)
5623 {
5624 priv_->deleted_dm_by_offset_.erase(i->first);
5625 priv_->inserted_dm_by_offset_.erase(i->first);
5626 priv_->deleted_data_members_.erase
5627 (i->second->first_var()->get_anon_dm_reliable_name());
5628 priv_->inserted_data_members_.erase
5629 (i->second->second_var()->get_anon_dm_reliable_name());
5630 }
5631
5632 // Now detect anonymous data members that might appear as deleted
5633 // even though all their data members are still present. Consider
5634 // these as being non-deleted.
5635 string_decl_base_sptr_map non_anonymous_dms_in_second_class;
5637 non_anonymous_dms_in_second_class);
5638 vector<string> deleted_data_members_to_delete;
5639 // Walk data members considered deleted ...
5640 for (auto& entry : priv_->deleted_data_members_)
5641 {
5642 var_decl_sptr data_member = is_var_decl(entry.second);
5643 ABG_ASSERT(data_member);
5644 if (is_anonymous_data_member(data_member))
5645 {
5646 // Let's look at this anonymous data member that is
5647 // considered deleted because it's moved from where it was
5648 // initially, at very least. If its leaf data members are
5649 // still present in the second class then, we won't
5650 // consider it as deleted.
5651 class_or_union_sptr cou = anonymous_data_member_to_class_or_union(data_member);
5652 ABG_ASSERT(cou);
5653 string_decl_base_sptr_map non_anonymous_data_members;
5654 // Lets collect the leaf data members of the anonymous
5655 // data member.
5656 collect_non_anonymous_data_members(cou, non_anonymous_data_members);
5657 bool anonymous_dm_members_present = true;
5658 // Let's see if at least one of the leaf members of the
5659 // anonymous data member is NOT present in the second
5660 // version of the class.
5661 for (auto& e : non_anonymous_data_members)
5662 {
5663 if (non_anonymous_dms_in_second_class.find(e.first)
5664 == non_anonymous_dms_in_second_class.end())
5665 // Grrr, OK, it looks like at least one leaf data
5666 // member of the original anonymous data member was
5667 // removed from the class, so yeah, the anonymous
5668 // data member might have been removed after all.
5669 anonymous_dm_members_present = false;
5670 }
5671 if (anonymous_dm_members_present)
5672 // All leaf data members of the anonymous data member
5673 // are still present in the second version of the class.
5674 // So let's mark that anonymous data member as NOT being
5675 // deleted.
5676 deleted_data_members_to_delete.push_back(data_member->get_anon_dm_reliable_name());
5677 }
5678 }
5679 // All anonymous data members that were recognized as being NOT
5680 // deleted should be removed from the set of deleted data members
5681 // now.
5682 for (string& name_of_dm_to_delete: deleted_data_members_to_delete)
5683 priv_->deleted_data_members_.erase(name_of_dm_to_delete);
5684 }
5685 sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5686 priv_->sorted_subtype_changed_dm_);
5687 sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5688 priv_->sorted_changed_dm_);
5689
5690 {
5691 edit_script& e = priv_->member_class_tmpls_changes_;
5692
5693 for (vector<deletion>::const_iterator it = e.deletions().begin();
5694 it != e.deletions().end();
5695 ++it)
5696 {
5697 unsigned i = it->index();
5698 decl_base_sptr d =
5699 first_class_or_union()->get_member_class_templates()[i]->
5700 as_class_tdecl();
5701 string name = d->get_name();
5702 ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5703 == priv_->deleted_member_class_tmpls_.end());
5704 priv_->deleted_member_class_tmpls_[name] = d;
5705 }
5706
5707 for (vector<insertion>::const_iterator it = e.insertions().begin();
5708 it != e.insertions().end();
5709 ++it)
5710 {
5711 for (vector<unsigned>::const_iterator iit =
5712 it->inserted_indexes().begin();
5713 iit != it->inserted_indexes().end();
5714 ++iit)
5715 {
5716 unsigned i = *iit;
5717 decl_base_sptr d =
5718 second_class_or_union()->get_member_class_templates()[i]->
5719 as_class_tdecl();
5720 string name = d->get_name();
5721 ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5722 == priv_->inserted_member_class_tmpls_.end());
5723 string_decl_base_sptr_map::const_iterator j =
5724 priv_->deleted_member_class_tmpls_.find(name);
5725 if (j != priv_->deleted_member_class_tmpls_.end())
5726 {
5727 if (*j->second != *d)
5728 priv_->changed_member_types_[name]=
5729 compute_diff(j->second, d, context());
5730 priv_->deleted_member_class_tmpls_.erase(j);
5731 }
5732 else
5733 priv_->inserted_member_class_tmpls_[name] = d;
5734 }
5735 }
5736 }
5737 sort_string_diff_sptr_map(priv_->changed_member_types_,
5738 priv_->sorted_changed_member_types_);
5739}
5740
5741/// Allocate the memory for the priv_ pimpl data member of the @ref
5742/// class_or_union_diff class.
5743void
5745{
5746 if (!priv_)
5747 priv_.reset(new priv);
5748}
5749
5750/// Constructor for the @ref class_or_union_diff class.
5751///
5752/// @param first_scope the first @ref class_or_union of the diff node.
5753///
5754/// @param second_scope the second @ref class_or_union of the diff node.
5755///
5756/// @param ctxt the context of the diff.
5757class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5758 class_or_union_sptr second_scope,
5759 diff_context_sptr ctxt)
5760 : type_diff_base(first_scope, second_scope, ctxt)
5761 //priv_(new priv)
5762{}
5763
5764/// Getter of the private data of the @ref class_or_union_diff type.
5765///
5766/// Note that due to an optimization, the private data of @ref
5767/// class_or_union_diff can be shared among several instances of
5768/// class_or_union_diff, so you should never try to access
5769/// class_or_union_diff::priv directly.
5770///
5771/// When class_or_union_diff::priv is shared, this function returns
5772/// the correct shared one.
5773///
5774/// @return the (possibly) shared private data of the current instance
5775/// of @ref class_or_union_diff.
5776const class_or_union_diff::priv_ptr&
5778{
5779 if (priv_)
5780 return priv_;
5781
5782 // If the current class_or_union_diff::priv member is empty, then look for
5783 // the shared one, from the canonical type.
5784 class_or_union_diff *canonical =
5785 dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5786 ABG_ASSERT(canonical);
5787 ABG_ASSERT(canonical->priv_);
5788
5789 return canonical->priv_;
5790}
5791
5792/// Destructor of class_or_union_diff.
5794{
5795}
5796
5797/// @return the first @ref class_or_union involved in the diff.
5798class_or_union_sptr
5801
5802/// @return the second @ref class_or_union involved in the diff.
5803class_or_union_sptr
5806
5807/// @return the edit script of the member types of the two @ref
5808/// class_or_union.
5809const edit_script&
5811{return get_priv()->member_types_changes_;}
5812
5813/// @return the edit script of the member types of the two @ref
5814/// class_or_union.
5817{return get_priv()->member_types_changes_;}
5818
5819/// @return the edit script of the data members of the two @ref
5820/// class_or_union.
5821const edit_script&
5823{return get_priv()->data_members_changes_;}
5824
5825/// @return the edit script of the data members of the two @ref
5826/// class_or_union.
5829{return get_priv()->data_members_changes_;}
5830
5831/// Getter for the data members that got inserted.
5832///
5833/// @return a map of data members that got inserted.
5836{return get_priv()->inserted_data_members_;}
5837
5838/// Getter for the data members that got deleted.
5839///
5840/// @return a map of data members that got deleted.
5843{return get_priv()->deleted_data_members_;}
5844
5845/// @return the edit script of the member functions of the two @ref
5846/// class_or_union.
5847const edit_script&
5849{return get_priv()->member_fns_changes_;}
5850
5851/// Getter for the virtual members functions that have had a change in
5852/// a sub-type, without having a change in their symbol name.
5853///
5854/// @return a sorted vector of virtual member functions that have a
5855/// sub-type change.
5858{return get_priv()->sorted_changed_member_functions_;}
5859
5860/// @return the edit script of the member functions of the two
5861/// classes.
5864{return get_priv()->member_fns_changes_;}
5865
5866/// @return a map of member functions that got deleted.
5869{return get_priv()->deleted_member_functions_;}
5870
5871/// @return a map of member functions that got inserted.
5874{return get_priv()->inserted_member_functions_;}
5875
5876/// Getter of the map of data members that got replaced by another
5877/// data member. The key of the map is the offset at which the
5878/// element got replaced and the value is a pointer to the @ref
5879/// var_diff representing the replacement of the data member.
5880///
5881/// @return sorted vector of changed data member.
5884{return get_priv()->changed_dm_;}
5885
5886/// Getter of the sorted vector of data members that got replaced by
5887/// another data member.
5888///
5889/// @return sorted vector of changed data member.
5892{return get_priv()->sorted_changed_dm_;}
5893
5894/// Count the number of /filtered/ data members that got replaced by
5895/// another data member.
5896///
5897/// @return the number of changed data member that got filtered out.
5898size_t
5900{return get_priv()->count_filtered_changed_dm(local);}
5901
5902/// Getter of the sorted vector of data members with a (sub-)type change.
5903///
5904/// @return sorted vector of changed data member.
5907{return get_priv()->sorted_subtype_changed_dm_;}
5908
5909/// Count the number of /filtered/ data members with a sub-type change.
5910///
5911/// @return the number of changed data member that got filtered out.
5912size_t
5914{return get_priv()->count_filtered_subtype_changed_dm(local);}
5915
5916/// Get the map of data members that got replaced by anonymous data
5917/// members.
5918///
5919/// The key of a map entry is the name of the replaced data member and
5920/// the value is the anonymous data member that replaces it.
5921///
5922/// @return the map of data members replaced by anonymous data
5923/// members.
5926{return get_priv()->dms_replaced_by_adms_;}
5927
5928/// Get an ordered vector of of data members that got replaced by
5929/// anonymous data members.
5930///
5931/// This returns a vector of pair of two data members: the one that
5932/// was replaced, and the anonymous data member that replaced it.
5933///
5934/// @return the sorted vector data members replaced by anonymous data members.
5937{
5938 if (priv_->dms_replaced_by_adms_ordered_.empty())
5939 {
5940 for (string_decl_base_sptr_map::const_iterator it =
5941 priv_->dms_replaced_by_adms_.begin();
5942 it != priv_->dms_replaced_by_adms_.end();
5943 ++it)
5944 {
5945 const var_decl_sptr dm =
5946 first_class_or_union()->find_data_member(it->first);
5947 ABG_ASSERT(dm);
5948 changed_var_sptr changed_dm(dm, is_data_member(it->second));
5949 priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5950 }
5951 sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5952 }
5953
5954 return priv_->dms_replaced_by_adms_ordered_;
5955}
5956
5957/// @return the edit script of the member function templates of the two
5958/// @ref class_or_union.
5959const edit_script&
5961{return get_priv()->member_fn_tmpls_changes_;}
5962
5963/// @return the edit script of the member function templates of the
5964/// two @ref class_or_union.
5967{return get_priv()->member_fn_tmpls_changes_;}
5968
5969/// @return the edit script of the member class templates of the two
5970/// @ref class_or_union.
5971const edit_script&
5973{return get_priv()->member_class_tmpls_changes_;}
5974
5975/// @return the edit script of the member class templates of the two
5976/// @ref class_or_union.
5979{return get_priv()->member_class_tmpls_changes_;}
5980
5981/// Test if the current diff node carries a change.
5982bool
5985
5986/// @return the kind of local change carried by the current diff node.
5987/// The value returned is zero if the current node carries no local
5988/// change.
5989enum change_kind
5991{
5992 ir::change_kind k = ir::NO_CHANGE_KIND;
5994 return k & ir::ALL_LOCAL_CHANGES_MASK;
5995 return ir::NO_CHANGE_KIND;
5996}
5997
5998
5999/// Report the changes carried by the current @ref class_or_union_diff
6000/// node in a textual format.
6001///
6002/// @param out the output stream to write the textual report to.
6003///
6004/// @param indent the number of white space to use as indentation.
6005void
6006class_or_union_diff::report(ostream& out, const string& indent) const
6007{
6008 context()->get_reporter()->report(*this, out, indent);
6009}
6010
6011/// Populate the vector of children node of the @ref diff base type
6012/// sub-object of this instance of @ref class_or_union_diff.
6013///
6014/// The children node can then later be retrieved using
6015/// diff::children_node().
6016void
6018{
6019 // data member changes
6020 for (var_diff_sptrs_type::const_iterator i =
6021 get_priv()->sorted_subtype_changed_dm_.begin();
6022 i != get_priv()->sorted_subtype_changed_dm_.end();
6023 ++i)
6024 if (diff_sptr d = *i)
6026
6027 for (var_diff_sptrs_type::const_iterator i =
6028 get_priv()->sorted_changed_dm_.begin();
6029 i != get_priv()->sorted_changed_dm_.end();
6030 ++i)
6031 if (diff_sptr d = *i)
6033
6034 // member types changes
6035 for (diff_sptrs_type::const_iterator i =
6036 get_priv()->sorted_changed_member_types_.begin();
6037 i != get_priv()->sorted_changed_member_types_.end();
6038 ++i)
6039 if (diff_sptr d = *i)
6041
6042 // member function changes
6043 for (function_decl_diff_sptrs_type::const_iterator i =
6044 get_priv()->sorted_changed_member_functions_.begin();
6045 i != get_priv()->sorted_changed_member_functions_.end();
6046 ++i)
6047 if (diff_sptr d = *i)
6049}
6050
6051// </class_or_union_diff stuff>
6052
6053//<class_diff stuff>
6054
6055/// Clear the lookup tables useful for reporting.
6056///
6057/// This function must be updated each time a lookup table is added or
6058/// removed from the class_diff::priv.
6059void
6060class_diff::clear_lookup_tables(void)
6061{
6062 priv_->deleted_bases_.clear();
6063 priv_->inserted_bases_.clear();
6064 priv_->changed_bases_.clear();
6065}
6066
6067/// Tests if the lookup tables are empty.
6068///
6069/// @return true if the lookup tables are empty, false otherwise.
6070bool
6071class_diff::lookup_tables_empty(void) const
6072{
6073 return (priv_->deleted_bases_.empty()
6074 && priv_->inserted_bases_.empty()
6075 && priv_->changed_bases_.empty());
6076}
6077
6078/// Find a virtual destructor in a map of member functions
6079///
6080/// @param map the map of member functions. Note that the key of the
6081/// map is the member function name. The key is the member function.
6082///
6083/// @return an iterator to the destructor found or, if no virtual destructor
6084/// was found, return map.end()
6085static string_member_function_sptr_map::const_iterator
6086find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
6087{
6088 for (string_member_function_sptr_map::const_iterator i = map.begin();
6089 i !=map.end();
6090 ++i)
6091 {
6092 if (get_member_function_is_dtor(i->second)
6093 && get_member_function_is_virtual(i->second))
6094 return i;
6095 }
6096 return map.end();
6097}
6098
6099/// If the lookup tables are not yet built, walk the differences and
6100/// fill them.
6101void
6102class_diff::ensure_lookup_tables_populated(void) const
6103{
6105
6106 if (!lookup_tables_empty())
6107 return;
6108
6109 {
6110 edit_script& e = get_priv()->base_changes_;
6111
6112 for (vector<deletion>::const_iterator it = e.deletions().begin();
6113 it != e.deletions().end();
6114 ++it)
6115 {
6116 unsigned i = it->index();
6118 first_class_decl()->get_base_specifiers()[i];
6119 string name = b->get_base_class()->get_qualified_name();
6120 ABG_ASSERT(get_priv()->deleted_bases_.find(name)
6121 == get_priv()->deleted_bases_.end());
6122 get_priv()->deleted_bases_[name] = b;
6123 }
6124
6125 for (vector<insertion>::const_iterator it = e.insertions().begin();
6126 it != e.insertions().end();
6127 ++it)
6128 {
6129 for (vector<unsigned>::const_iterator iit =
6130 it->inserted_indexes().begin();
6131 iit != it->inserted_indexes().end();
6132 ++iit)
6133 {
6134 unsigned i = *iit;
6136 second_class_decl()->get_base_specifiers()[i];
6137 string name = b->get_base_class()->get_qualified_name();
6138 ABG_ASSERT(get_priv()->inserted_bases_.find(name)
6139 == get_priv()->inserted_bases_.end());
6140 string_base_sptr_map::const_iterator j =
6141 get_priv()->deleted_bases_.find(name);
6142 if (j != get_priv()->deleted_bases_.end())
6143 {
6144 if (j->second != b)
6145 get_priv()->changed_bases_[name] =
6146 compute_diff(j->second, b, context());
6147 else
6148 // The base class changed place. IOW, the base
6149 // classes got re-arranged. Let's keep track of the
6150 // base classes that moved.
6151 get_priv()->moved_bases_.push_back(b);
6152 get_priv()->deleted_bases_.erase(j);
6153 }
6154 else
6155 get_priv()->inserted_bases_[name] = b;
6156 }
6157 }
6158
6159 // ===============================================================
6160 // Detect when a data member is deleted from the class but is now
6161 // present in one of the bases at the same offset. In that case,
6162 // the data member should not be considered as removed.
6163 // ===============================================================
6165 class_or_union_diff::priv_->deleted_data_members_;
6166
6167 vector<var_decl_sptr> deleted_data_members_present_in_bases;
6168 for (auto entry : deleted_data_members)
6169 {
6170 var_decl_sptr deleted_member = is_var_decl(entry.second);
6171 ABG_ASSERT(deleted_member);
6172 for (class_decl::base_spec_sptr base : second_class_decl()->get_base_specifiers())
6173 {
6174 class_decl_sptr klass = base->get_base_class();
6175 var_decl_sptr member = klass->find_data_member(deleted_member->get_name());
6176 if (member)
6177 deleted_data_members_present_in_bases.push_back(member);
6178 }
6179 }
6180 // Walk the deleted data members that are now in one of the bases,
6181 // of the new type, at the same offset, and let's see if they have
6182 // sub-type changes. In any cases, these should not be considered
6183 // as being deleted.
6184 for (var_decl_sptr m : deleted_data_members_present_in_bases)
6185 {
6186 string name = m->get_name();
6187 auto it = deleted_data_members.find(name);
6188 ABG_ASSERT(it != deleted_data_members.end());
6189 var_decl_sptr deleted_member = is_var_decl(it->second);
6190 if (*deleted_member != *m)
6191 {
6192 var_diff_sptr dif = compute_diff(deleted_member, m, context());
6193 ABG_ASSERT(dif);
6194 class_or_union_diff::priv_->subtype_changed_dm_[name]= dif;
6195 }
6196 deleted_data_members.erase(name);
6197 }
6198 }
6199
6200 sort_string_base_sptr_map(get_priv()->deleted_bases_,
6201 get_priv()->sorted_deleted_bases_);
6202 sort_string_base_sptr_map(get_priv()->inserted_bases_,
6203 get_priv()->sorted_inserted_bases_);
6204 sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
6205 get_priv()->sorted_changed_bases_);
6206
6207 {
6208 const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
6209
6210 edit_script& e = p->member_fns_changes_;
6211
6212 for (vector<deletion>::const_iterator it = e.deletions().begin();
6213 it != e.deletions().end();
6214 ++it)
6215 {
6216 unsigned i = it->index();
6217 method_decl_sptr mem_fn =
6218 first_class_decl()->get_virtual_mem_fns()[i];
6219 string name = mem_fn->get_linkage_name();
6220 if (name.empty())
6221 name = mem_fn->get_pretty_representation();
6222 ABG_ASSERT(!name.empty());
6223 if (p->deleted_member_functions_.find(name)
6224 != p->deleted_member_functions_.end())
6225 continue;
6226 p->deleted_member_functions_[name] = mem_fn;
6227 }
6228
6229 for (vector<insertion>::const_iterator it = e.insertions().begin();
6230 it != e.insertions().end();
6231 ++it)
6232 {
6233 for (vector<unsigned>::const_iterator iit =
6234 it->inserted_indexes().begin();
6235 iit != it->inserted_indexes().end();
6236 ++iit)
6237 {
6238 unsigned i = *iit;
6239
6240 method_decl_sptr mem_fn =
6241 second_class_decl()->get_virtual_mem_fns()[i];
6242 string name = mem_fn->get_linkage_name();
6243 if (name.empty())
6244 name = mem_fn->get_pretty_representation();
6245 ABG_ASSERT(!name.empty());
6246 if (p->inserted_member_functions_.find(name)
6247 != p->inserted_member_functions_.end())
6248 continue;
6249 string_member_function_sptr_map::const_iterator j =
6250 p->deleted_member_functions_.find(name);
6251
6252 if (j != p->deleted_member_functions_.end())
6253 {
6254 if (*j->second != *mem_fn)
6255 p->changed_member_functions_[name] =
6256 compute_diff(static_pointer_cast<function_decl>(j->second),
6257 static_pointer_cast<function_decl>(mem_fn),
6258 context());
6259 p->deleted_member_functions_.erase(j);
6260 }
6261 else
6262 p->inserted_member_functions_[name] = mem_fn;
6263 }
6264 }
6265
6266 // Now walk the allegedly deleted member functions; check if their
6267 // underlying symbols are deleted as well; otherwise, consider
6268 // that the member function in question hasn't been deleted.
6269
6270 // Also, while walking the deleted member functions, we attend at
6271 // a particular cleanup business related to (virtual) C++
6272 // destructors:
6273 //
6274 // In the binary, there can be at least three types of
6275 // destructors, defined in the document
6276 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
6277 //
6278 // 1/ Base object destructor (aka D2 destructor):
6279 //
6280 // "A function that runs the destructors for non-static data
6281 // members of T and non-virtual direct base classes of T. "
6282 //
6283 // 2/ Complete object destructor (aka D1 destructor):
6284 //
6285 // "A function that, in addition to the actions required of a
6286 // base object destructor, runs the destructors for the
6287 // virtual base classes of T."
6288 //
6289 // 3/ Deleting destructor (aka D0 destructor):
6290 //
6291 // "A function that, in addition to the actions required of a
6292 // complete object destructor, calls the appropriate
6293 // deallocation function (i.e,. operator delete) for T."
6294 //
6295 // With binaries generated by GCC, these destructors might be ELF
6296 // clones of each others, meaning, their ELF symbols can be
6297 // aliases.
6298 //
6299 // Also, note that because the actual destructor invoked by user
6300 // code is virtual, it's invoked through the vtable. So the
6301 // presence of the underlying D0, D1, D2 in the binary might vary
6302 // without that variation being an ABI issue, provided that the
6303 // destructor invoked through the vtable is present.
6304 //
6305 // So, a particular virtual destructor implementation for a class
6306 // might disapear and be replaced by another one in a subsequent
6307 // version of the binary. If all versions of the binary have an
6308 // actual virtual destructor, things might be considered fine.
6309 vector<string> to_delete;
6310 corpus_sptr f = context()->get_first_corpus(),
6311 s = context()->get_second_corpus();
6312 if (s)
6313 for (string_member_function_sptr_map::const_iterator i =
6314 deleted_member_fns().begin();
6315 i != deleted_member_fns().end();
6316 ++i)
6317 {
6318 if (get_member_function_is_virtual(i->second))
6319 {
6320 if (get_member_function_is_dtor(i->second))
6321 {
6322 // If a particular virtual destructor is deleted,
6323 // but the new binary still have a virtual
6324 // destructor for that class we consider that things
6325 // are fine. For instance, in the
6326 // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
6327 // test, a new D4 destructor replaces the old ones.
6328 // But because the virtual destructor is still
6329 // there, this is not an ABI issue. So let's detect
6330 // this case.
6331 auto it =
6332 find_virtual_dtor_in_map(p->inserted_member_functions_);
6333 if (it != p->inserted_member_functions_.end())
6334 {
6335 // So the deleted virtual destructor is not
6336 // really deleted, because a proper virtual
6337 // destructor was added to the new version.
6338 // Let's remove the deleted/added virtual
6339 // destructor then.
6340 string name =
6341 (!i->second->get_linkage_name().empty())
6342 ? i->second->get_linkage_name()
6343 : i->second->get_pretty_representation();
6344 to_delete.push_back(name);
6345 p->inserted_member_functions_.erase(it);
6346 }
6347 }
6348 continue;
6349 }
6350 // We assume that all non-virtual member functions functions
6351 // we look at here have ELF symbols.
6352 if (!i->second->get_symbol()
6353 || s->lookup_function_symbol(*i->second->get_symbol()))
6354 to_delete.push_back(i->first);
6355 }
6356
6357
6358 for (vector<string>::const_iterator i = to_delete.begin();
6359 i != to_delete.end();
6360 ++i)
6361 p->deleted_member_functions_.erase(*i);
6362
6363 // Do something similar for added functions.
6364 to_delete.clear();
6365 if (f)
6366 for (string_member_function_sptr_map::const_iterator i =
6367 inserted_member_fns().begin();
6368 i != inserted_member_fns().end();
6369 ++i)
6370 {
6371 if (get_member_function_is_virtual(i->second))
6372 continue;
6373 // We assume that all non-virtual member functions functions
6374 // we look at here have ELF symbols.
6375 if (!i->second->get_symbol()
6376 || f->lookup_function_symbol(*i->second->get_symbol()))
6377 to_delete.push_back(i->first);
6378 }
6379
6380 for (vector<string>::const_iterator i = to_delete.begin();
6381 i != to_delete.end();
6382 ++i)
6383 p->inserted_member_functions_.erase(*i);
6384
6385 sort_string_member_function_sptr_map(p->deleted_member_functions_,
6386 p->sorted_deleted_member_functions_);
6387
6388 sort_string_member_function_sptr_map(p->inserted_member_functions_,
6389 p->sorted_inserted_member_functions_);
6390
6392 (p->changed_member_functions_,
6393 p->sorted_changed_member_functions_);
6394 }
6395}
6396
6397/// Allocate the memory for the priv_ pimpl data member of the @ref
6398/// class_diff class.
6399void
6400class_diff::allocate_priv_data()
6401{
6403 if (!priv_)
6404 priv_.reset(new priv);
6405}
6406
6407/// Test whether a given base class has changed. A base class has
6408/// changed if it's in both in deleted *and* inserted bases.
6409///
6410///@param d the declaration for the base class to consider.
6411///
6412/// @return the new base class if the given base class has changed, or
6413/// NULL if it hasn't.
6416{
6417 string qname = d->get_base_class()->get_qualified_name();
6418 string_base_diff_sptr_map::const_iterator it =
6419 changed_bases_.find(qname);
6420
6421 return (it == changed_bases_.end())
6423 : it->second->second_base();
6424
6425}
6426
6427/// Count the number of bases classes whose changes got filtered out.
6428///
6429/// @return the number of bases classes whose changes got filtered
6430/// out.
6431size_t
6433{
6434 size_t num_filtered = 0;
6435 for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
6436 i != sorted_changed_bases_.end();
6437 ++i)
6438 {
6439 diff_sptr diff = *i;
6440 if (diff && diff->is_filtered_out())
6441 ++num_filtered;
6442 }
6443 return num_filtered;
6444}
6445
6446/// Populate the vector of children node of the @ref diff base type
6447/// sub-object of this instance of @ref class_diff.
6448///
6449/// The children node can then later be retrieved using
6450/// diff::children_node().
6451void
6453{
6455
6456 // base class changes.
6457 for (base_diff_sptrs_type::const_iterator i =
6458 get_priv()->sorted_changed_bases_.begin();
6459 i != get_priv()->sorted_changed_bases_.end();
6460 ++i)
6461 if (diff_sptr d = *i)
6463}
6464
6465/// Constructor of class_diff
6466///
6467/// @param first_scope the first class of the diff.
6468///
6469/// @param second_scope the second class of the diff.
6470///
6471/// @param ctxt the diff context to use.
6473 class_decl_sptr second_scope,
6474 diff_context_sptr ctxt)
6475 : class_or_union_diff(first_scope, second_scope, ctxt)
6476 // We don't initialize the priv_ data member here. This is an
6477 // optimization to reduce memory consumption (and also execution
6478 // time) for cases where there are a lot of instances of
6479 // class_diff in the same equivalence class. In compute_diff(),
6480 // the priv_ is set to the priv_ of the canonical diff node.
6481 // See PR libabigail/17948.
6482{}
6483
6484class_diff::~class_diff()
6485{}
6486
6487/// Getter of the private data of the @ref class_diff type.
6488///
6489/// Note that due to an optimization, the private data of @ref
6490/// class_diff can be shared among several instances of class_diff, so
6491/// you should never try to access class_diff::priv directly.
6492///
6493/// When class_diff::priv is shared, this function returns the correct
6494/// shared one.
6495///
6496/// @return the (possibly) shared private data of the current instance
6497/// of class_diff.
6498const class_diff::priv_ptr&
6499class_diff::get_priv() const
6500{
6501 if (priv_)
6502 return priv_;
6503
6504 // If the current class_diff::priv member is empty, then look for
6505 // the shared one, from the canonical type.
6506 class_diff *canonical =
6507 dynamic_cast<class_diff*>(get_canonical_diff());
6508 ABG_ASSERT(canonical);
6509 ABG_ASSERT(canonical->priv_);
6510
6511 return canonical->priv_;
6512}
6513
6514/// @return the pretty representation of the current instance of @ref
6515/// class_diff.
6516const string&
6518{
6519 if (diff::priv_->pretty_representation_.empty())
6520 {
6521 std::ostringstream o;
6522 o << "class_diff["
6523 << first_subject()->get_pretty_representation()
6524 << ", "
6525 << second_subject()->get_pretty_representation()
6526 << "]";
6527 diff::priv_->pretty_representation_ = o.str();
6528 }
6529 return diff::priv_->pretty_representation_;
6530}
6531
6532/// Return true iff the current diff node carries a change.
6533///
6534/// @return true iff the current diff node carries a change.
6535bool
6537{return (first_class_decl() != second_class_decl());}
6538
6539/// @return the kind of local change carried by the current diff node.
6540/// The value returned is zero if the current node carries no local
6541/// change.
6542enum change_kind
6544{
6545 ir::change_kind k = ir::NO_CHANGE_KIND;
6546 if (!equals(*first_class_decl(), *second_class_decl(), &k))
6547 return k & ir::ALL_LOCAL_CHANGES_MASK;
6548 return ir::NO_CHANGE_KIND;
6549}
6550
6551/// @return the first class invoveld in the diff.
6552shared_ptr<class_decl>
6554{return dynamic_pointer_cast<class_decl>(first_subject());}
6555
6556/// Getter of the second class involved in the diff.
6557///
6558/// @return the second class invoveld in the diff
6559shared_ptr<class_decl>
6561{return dynamic_pointer_cast<class_decl>(second_subject());}
6562
6563/// @return the edit script of the bases of the two classes.
6564const edit_script&
6566{return get_priv()->base_changes_;}
6567
6568/// Getter for the deleted base classes of the diff.
6569///
6570/// @return a map containing the deleted base classes, keyed with
6571/// their pretty representation.
6574{return get_priv()->deleted_bases_;}
6575
6576/// Getter for the inserted base classes of the diff.
6577///
6578/// @return a map containing the inserted base classes, keyed with
6579/// their pretty representation.
6582{return get_priv()->inserted_bases_;}
6583
6584/// Getter for the changed base classes of the diff.
6585///
6586/// @return a sorted vector containing the changed base classes
6589{return get_priv()->sorted_changed_bases_;}
6590
6591/// Getter for the vector of bases that "moved".
6592/// That is, the vector of base types which position changed. If this
6593/// vector is not empty, it means the bases of the underlying class
6594/// type got re-ordered.
6595///
6596/// @return the vector of bases that moved.
6597const vector<class_decl::base_spec_sptr>&
6599{return get_priv()->moved_bases_;}
6600
6601/// @return the edit script of the bases of the two classes.
6604{return get_priv()->base_changes_;}
6605
6606/// Produce a basic report about the changes between two class_decl.
6607///
6608/// @param out the output stream to report the changes to.
6609///
6610/// @param indent the string to use as an indentation prefix in the
6611/// report.
6612void
6613class_diff::report(ostream& out, const string& indent) const
6614{
6615 context()->get_reporter()->report(*this, out, indent);
6616}
6617
6618/// Compute the set of changes between two instances of class_decl.
6619///
6620/// Note that the two types must have been created in the same @ref
6621/// environment, otherwise, this function aborts.
6622///
6623/// @param first the first class_decl to consider.
6624///
6625/// @param second the second class_decl to consider.
6626///
6627/// @return changes the resulting changes.
6628///
6629/// @param ctxt the diff context to use.
6632 const class_decl_sptr second,
6633 diff_context_sptr ctxt)
6634{
6637
6638 class_diff_sptr changes(new class_diff(f, s, ctxt));
6639
6640 ctxt->initialize_canonical_diff(changes);
6641 ABG_ASSERT(changes->get_canonical_diff());
6642
6643 if (!ctxt->get_canonical_diff_for(first, second))
6644 {
6645 // Either first or second is a decl-only class; let's set the
6646 // canonical diff here in that case.
6647 diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6648 ABG_ASSERT(canonical_diff);
6649 ctxt->set_canonical_diff_for(first, second, canonical_diff);
6650 }
6651
6652 // Ok, so this is an optimization. Do not freak out if it looks
6653 // weird, because, well, it does look weird. This speeds up
6654 // greatly, for instance, the test case given at PR
6655 // libabigail/17948.
6656 //
6657 // We are setting the private data of the new instance of class_diff
6658 // (which is 'changes') to the private data of its canonical
6659 // instance. That is, we are sharing the private data of 'changes'
6660 // with the private data of its canonical instance to consume less
6661 // memory in cases where the equivalence class of 'changes' is huge.
6662 //
6663 // But if changes is its own canonical instance, then we initialize
6664 // its private data properly
6665 if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6666 // changes is its own canonical instance, so it gets a brand new
6667 // private data.
6668 changes->allocate_priv_data();
6669 else
6670 {
6671 // changes has a non-empty equivalence class so it's going to
6672 // share its private data with its canonical instance. Next
6673 // time class_diff::get_priv() is invoked, it's going to return
6674 // the shared private data of the canonical instance.
6675 return changes;
6676 }
6677
6678 // Compare base specs
6679 compute_diff(f->get_base_specifiers().begin(),
6680 f->get_base_specifiers().end(),
6681 s->get_base_specifiers().begin(),
6682 s->get_base_specifiers().end(),
6683 changes->base_changes());
6684
6685 // Do *not* compare member types because it generates lots of noise
6686 // and I doubt it's really useful.
6687#if 0
6688 compute_diff(f->get_member_types().begin(),
6689 f->get_member_types().end(),
6690 s->get_member_types().begin(),
6691 s->get_member_types().end(),
6692 changes->member_types_changes());
6693#endif
6694
6695 // Compare data member
6696 compute_diff(f->get_non_static_data_members().begin(),
6697 f->get_non_static_data_members().end(),
6698 s->get_non_static_data_members().begin(),
6699 s->get_non_static_data_members().end(),
6700 changes->data_members_changes());
6701
6702 // Compare virtual member functions
6703 compute_diff(f->get_virtual_mem_fns().begin(),
6704 f->get_virtual_mem_fns().end(),
6705 s->get_virtual_mem_fns().begin(),
6706 s->get_virtual_mem_fns().end(),
6707 changes->member_fns_changes());
6708
6709 // Compare member function templates
6710 compute_diff(f->get_member_function_templates().begin(),
6711 f->get_member_function_templates().end(),
6712 s->get_member_function_templates().begin(),
6713 s->get_member_function_templates().end(),
6714 changes->member_fn_tmpls_changes());
6715
6716 // Likewise, do not compare member class templates
6717#if 0
6718 compute_diff(f->get_member_class_templates().begin(),
6719 f->get_member_class_templates().end(),
6720 s->get_member_class_templates().begin(),
6721 s->get_member_class_templates().end(),
6722 changes->member_class_tmpls_changes());
6723#endif
6724
6725 changes->ensure_lookup_tables_populated();
6726
6727 return changes;
6728}
6729
6730//</class_diff stuff>
6731
6732// <base_diff stuff>
6733
6734/// Populate the vector of children node of the @ref diff base type
6735/// sub-object of this instance of @ref base_diff.
6736///
6737/// The children node can then later be retrieved using
6738/// diff::children_node().
6739void
6742
6743/// @param first the first base spec to consider.
6744///
6745/// @param second the second base spec to consider.
6746///
6747/// @param ctxt the context of the diff. Note that this context
6748/// object must stay alive at least during the life time of the
6749/// current instance of @ref base_diff. Otherwise memory corruption
6750/// issues occur.
6753 class_diff_sptr underlying,
6754 diff_context_sptr ctxt)
6755 : diff(first, second, ctxt),
6756 priv_(new priv(underlying))
6757{}
6758
6759/// Getter for the first base spec of the diff object.
6760///
6761/// @return the first base specifier for the diff object.
6764{return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6765
6766/// Getter for the second base spec of the diff object.
6767///
6768/// @return the second base specifier for the diff object.
6771{return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6772
6773/// Getter for the diff object for the diff of the underlying base
6774/// classes.
6775///
6776/// @return the diff object for the diff of the underlying base
6777/// classes.
6778const class_diff_sptr
6780{return priv_->underlying_class_diff_;}
6781
6782/// Setter for the diff object for the diff of the underlyng base
6783/// classes.
6784///
6785/// @param d the new diff object for the diff of the underlying base
6786/// classes.
6787void
6789{priv_->underlying_class_diff_ = d;}
6790
6791/// @return the pretty representation for the current instance of @ref
6792/// base_diff.
6793const string&
6795{
6796 if (diff::priv_->pretty_representation_.empty())
6797 {
6798 std::ostringstream o;
6799 o << "base_diff["
6800 << first_subject()->get_pretty_representation()
6801 << ", "
6802 << second_subject()->get_pretty_representation()
6803 << "]";
6804 diff::priv_->pretty_representation_ = o.str();
6805 }
6806 return diff::priv_->pretty_representation_;
6807}
6808
6809/// Return true iff the current diff node carries a change.
6810///
6811/// Return true iff the current diff node carries a change.
6812bool
6814{return first_base() != second_base();}
6815
6816/// @return the kind of local change carried by the current diff node.
6817/// The value returned is zero if the current node carries no local
6818/// change.
6819enum change_kind
6821{
6822 ir::change_kind k = ir::NO_CHANGE_KIND;
6823 if (!equals(*first_base(), *second_base(), &k))
6824 return k & ir::ALL_LOCAL_CHANGES_MASK;
6825 return ir::NO_CHANGE_KIND;
6826}
6827
6828/// Generates a report for the current instance of base_diff.
6829///
6830/// @param out the output stream to send the report to.
6831///
6832/// @param indent the string to use for indentation.
6833void
6834base_diff::report(ostream& out, const string& indent) const
6835{
6836 context()->get_reporter()->report(*this, out, indent);
6837}
6838
6839/// Constructs the diff object representing a diff between two base
6840/// class specifications.
6841///
6842/// Note that the two artifacts must have been created in the same
6843/// @ref environment, otherwise, this function aborts.
6844///
6845/// @param first the first base class specification.
6846///
6847/// @param second the second base class specification.
6848///
6849/// @param ctxt the content of the diff.
6850///
6851/// @return the resulting diff object.
6854 const class_decl::base_spec_sptr second,
6855 diff_context_sptr ctxt)
6856{
6857 class_diff_sptr cl = compute_diff(first->get_base_class(),
6858 second->get_base_class(),
6859 ctxt);
6860 base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6861
6862 ctxt->initialize_canonical_diff(changes);
6863
6864 return changes;
6865}
6866
6867// </base_diff stuff>
6868
6869
6870// <union_diff stuff>
6871
6872/// Clear the lookup tables useful for reporting.
6873///
6874/// This function must be updated each time a lookup table is added or
6875/// removed from the union_diff::priv.
6876void
6877union_diff::clear_lookup_tables(void)
6879
6880/// Tests if the lookup tables are empty.
6881///
6882/// @return true if the lookup tables are empty, false otherwise.
6883bool
6884union_diff::lookup_tables_empty(void) const
6886
6887/// If the lookup tables are not yet built, walk the differences and
6888/// fill them.
6889void
6890union_diff::ensure_lookup_tables_populated(void) const
6892
6893/// Allocate the memory for the priv_ pimpl data member of the @ref
6894/// union_diff class.
6895void
6896union_diff::allocate_priv_data()
6897{
6899}
6900
6901/// Constructor for the @ref union_diff type.
6902///
6903/// @param first_union the first object of the comparison.
6904///
6905/// @param second_union the second object of the comparison.
6906///
6907/// @param ctxt the context of the comparison.
6908union_diff::union_diff(union_decl_sptr first_union,
6909 union_decl_sptr second_union,
6910 diff_context_sptr ctxt)
6911 : class_or_union_diff(first_union, second_union, ctxt)
6912{}
6913
6914/// Destructor of the union_diff node.
6916{}
6917
6918/// @return the first object of the comparison.
6919union_decl_sptr
6921{return is_union_type(first_subject());}
6922
6923/// @return the second object of the comparison.
6924union_decl_sptr
6926{return is_union_type(second_subject());}
6927
6928/// @return the pretty representation of the current diff node.
6929const string&
6931{
6932 if (diff::priv_->pretty_representation_.empty())
6933 {
6934 std::ostringstream o;
6935 o << "union_diff["
6936 << first_subject()->get_pretty_representation()
6937 << ", "
6938 << second_subject()->get_pretty_representation()
6939 << "]";
6940 diff::priv_->pretty_representation_ = o.str();
6941 }
6942 return diff::priv_->pretty_representation_;
6943}
6944
6945/// Report the changes carried by the current @ref union_diff node in
6946/// a textual format.
6947///
6948/// @param out the output stream to write the textual report to.
6949///
6950/// @param indent the number of white space to use as indentation.
6951void
6952union_diff::report(ostream& out, const string& indent) const
6953{
6954 context()->get_reporter()->report(*this, out, indent);
6955}
6956
6957/// Compute the difference between two @ref union_decl types.
6958///
6959/// Note that the two types must hav been created in the same
6960/// environment, otherwise, this function aborts.
6961///
6962/// @param first the first @ref union_decl to consider.
6963///
6964/// @param second the second @ref union_decl to consider.
6965///
6966/// @param ctxt the context of the diff to use.
6967union_diff_sptr
6968compute_diff(const union_decl_sptr first,
6969 const union_decl_sptr second,
6970 diff_context_sptr ctxt)
6971{
6972 union_diff_sptr changes(new union_diff(first, second, ctxt));
6973
6974 ctxt->initialize_canonical_diff(changes);
6975 ABG_ASSERT(changes->get_canonical_diff());
6976
6977 // Ok, so this is an optimization. Do not freak out if it looks
6978 // weird, because, well, it does look weird. This speeds up
6979 // greatly, for instance, the test case given at PR
6980 // libabigail/17948.
6981 //
6982 // We are setting the private data of the new instance of class_diff
6983 // (which is 'changes') to the private data of its canonical
6984 // instance. That is, we are sharing the private data of 'changes'
6985 // with the private data of its canonical instance to consume less
6986 // memory in cases where the equivalence class of 'changes' is huge.
6987 //
6988 // But if changes is its own canonical instance, then we initialize
6989 // its private data properly.
6990 if (is_union_diff(changes->get_canonical_diff()) == changes.get())
6991 // changes is its own canonical instance, so it gets a brand new
6992 // private data.
6993 changes->allocate_priv_data();
6994 else
6995 {
6996 // changes has a non-empty equivalence class so it's going to
6997 // share its private data with its canonical instance. Next
6998 // time class_diff::get_priv() is invoked, it's going to return
6999 // the shared private data of the canonical instance.
7000 return changes;
7001 }
7002
7003 // Compare data member
7004 compute_diff(first->get_non_static_data_members().begin(),
7005 first->get_non_static_data_members().end(),
7006 second->get_non_static_data_members().begin(),
7007 second->get_non_static_data_members().end(),
7008 changes->data_members_changes());
7009
7010#if 0
7011 // Compare member functions
7012 compute_diff(first->get_mem_fns().begin(),
7013 first->get_mem_fns().end(),
7014 second->get_mem_fns().begin(),
7015 second->get_mem_fns().end(),
7016 changes->member_fns_changes());
7017
7018 // Compare member function templates
7019 compute_diff(first->get_member_function_templates().begin(),
7020 first->get_member_function_templates().end(),
7021 second->get_member_function_templates().begin(),
7022 second->get_member_function_templates().end(),
7023 changes->member_fn_tmpls_changes());
7024#endif
7025
7026 changes->ensure_lookup_tables_populated();
7027
7028 return changes;
7029}
7030
7031// </union_diff stuff>
7032
7033//<scope_diff stuff>
7034
7035/// Clear the lookup tables that are useful for reporting.
7036///
7037/// This function must be updated each time a lookup table is added or
7038/// removed.
7039void
7040scope_diff::clear_lookup_tables()
7041{
7042 priv_->deleted_types_.clear();
7043 priv_->deleted_decls_.clear();
7044 priv_->inserted_types_.clear();
7045 priv_->inserted_decls_.clear();
7046 priv_->changed_types_.clear();
7047 priv_->changed_decls_.clear();
7048 priv_->removed_types_.clear();
7049 priv_->removed_decls_.clear();
7050 priv_->added_types_.clear();
7051 priv_->added_decls_.clear();
7052}
7053
7054/// Tests if the lookup tables are empty.
7055///
7056/// This function must be updated each time a lookup table is added or
7057/// removed.
7058///
7059/// @return true iff all the lookup tables are empty.
7060bool
7061scope_diff::lookup_tables_empty() const
7062{
7063 return (priv_->deleted_types_.empty()
7064 && priv_->deleted_decls_.empty()
7065 && priv_->inserted_types_.empty()
7066 && priv_->inserted_decls_.empty()
7067 && priv_->changed_types_.empty()
7068 && priv_->changed_decls_.empty()
7069 && priv_->removed_types_.empty()
7070 && priv_->removed_decls_.empty()
7071 && priv_->added_types_.empty()
7072 && priv_->added_decls_.empty());
7073}
7074
7075/// If the lookup tables are not yet built, walk the member_changes_
7076/// member and fill the lookup tables.
7077void
7078scope_diff::ensure_lookup_tables_populated()
7079{
7080 if (!lookup_tables_empty())
7081 return;
7082
7083 edit_script& e = priv_->member_changes_;
7084
7085 // Populate deleted types & decls lookup tables.
7086 for (const auto& deletion : e.deletions())
7087 {
7088 unsigned i = deletion.index();
7089 decl_base_sptr decl = deleted_member_at(i);
7090 string qname = decl->get_qualified_name();
7091 if (is_type(decl))
7092 {
7093 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
7094 if (klass_decl && klass_decl->get_is_declaration_only())
7095 continue;
7096
7097 // Unique types are artifically put in a scope because they
7098 // have to belong somewhere, but they should not be
7099 // considered added/removed from any scope because they are
7100 // artificial and always present in the system.
7101 if (is_unique_type(is_type(decl)))
7102 continue;
7103
7104 ABG_ASSERT(priv_->deleted_types_.find(qname)
7105 == priv_->deleted_types_.end());
7106 priv_->deleted_types_[qname] = decl;
7107 }
7108 else
7109 {
7110 ABG_ASSERT(priv_->deleted_decls_.find(qname)
7111 == priv_->deleted_decls_.end());
7112 priv_->deleted_decls_[qname] = decl;
7113 }
7114 }
7115
7116 // Populate inserted types & decls as well as chagned types & decls
7117 // lookup tables.
7118 for (vector<insertion>::const_iterator it = e.insertions().begin();
7119 it != e.insertions().end();
7120 ++it)
7121 {
7122 for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
7123 i != it->inserted_indexes().end();
7124 ++i)
7125 {
7126 decl_base_sptr decl = inserted_member_at(i);
7127 string qname = decl->get_qualified_name();
7128 if (is_type(decl))
7129 {
7130 class_decl_sptr klass_decl =
7131 dynamic_pointer_cast<class_decl>(decl);
7132 if (klass_decl && klass_decl->get_is_declaration_only())
7133 continue;
7134
7135 // Unique types are artifically put in a scope because they
7136 // have to belong somewhere, but they should not be
7137 // considered added/removed from any scope because they are
7138 // artificial and always present in the system.
7139 if (is_unique_type(is_type(decl)))
7140 continue;
7141
7142 ABG_ASSERT(priv_->inserted_types_.find(qname)
7143 == priv_->inserted_types_.end());
7144 string_decl_base_sptr_map::const_iterator j =
7145 priv_->deleted_types_.find(qname);
7146 if (j != priv_->deleted_types_.end())
7147 {
7148 if (*j->second != *decl)
7149 priv_->changed_types_[qname] =
7150 compute_diff(j->second, decl, context());
7151 priv_->deleted_types_.erase(j);
7152 }
7153 else
7154 priv_->inserted_types_[qname] = decl;
7155 }
7156 else
7157 {
7158 ABG_ASSERT(priv_->inserted_decls_.find(qname)
7159 == priv_->inserted_decls_.end());
7160 string_decl_base_sptr_map::const_iterator j =
7161 priv_->deleted_decls_.find(qname);
7162 if (j != priv_->deleted_decls_.end())
7163 {
7164 if (*j->second != *decl)
7165 priv_->changed_decls_[qname] =
7166 compute_diff(j->second, decl, context());
7167 priv_->deleted_decls_.erase(j);
7168 }
7169 else
7170 priv_->inserted_decls_[qname] = decl;
7171 }
7172 }
7173 }
7174
7175 sort_string_diff_sptr_map(priv_->changed_decls_,
7176 priv_->sorted_changed_decls_);
7177 sort_string_diff_sptr_map(priv_->changed_types_,
7178 priv_->sorted_changed_types_);
7179
7180 // Populate removed types/decls lookup tables
7181 for (string_decl_base_sptr_map::const_iterator i =
7182 priv_->deleted_types_.begin();
7183 i != priv_->deleted_types_.end();
7184 ++i)
7185 {
7186 string_decl_base_sptr_map::const_iterator r =
7187 priv_->inserted_types_.find(i->first);
7188 if (r == priv_->inserted_types_.end())
7189 priv_->removed_types_[i->first] = i->second;
7190 }
7191 for (string_decl_base_sptr_map::const_iterator i =
7192 priv_->deleted_decls_.begin();
7193 i != priv_->deleted_decls_.end();
7194 ++i)
7195 {
7196 string_decl_base_sptr_map::const_iterator r =
7197 priv_->inserted_decls_.find(i->first);
7198 if (r == priv_->inserted_decls_.end())
7199 priv_->removed_decls_[i->first] = i->second;
7200 }
7201
7202 // Populate added types/decls.
7203 for (string_decl_base_sptr_map::const_iterator i =
7204 priv_->inserted_types_.begin();
7205 i != priv_->inserted_types_.end();
7206 ++i)
7207 {
7208 string_decl_base_sptr_map::const_iterator r =
7209 priv_->deleted_types_.find(i->first);
7210 if (r == priv_->deleted_types_.end())
7211 priv_->added_types_[i->first] = i->second;
7212 }
7213 for (string_decl_base_sptr_map::const_iterator i =
7214 priv_->inserted_decls_.begin();
7215 i != priv_->inserted_decls_.end();
7216 ++i)
7217 {
7218 string_decl_base_sptr_map::const_iterator r =
7219 priv_->deleted_decls_.find(i->first);
7220 if (r == priv_->deleted_decls_.end())
7221 priv_->added_decls_[i->first] = i->second;
7222 }
7223}
7224
7225/// Populate the vector of children node of the @ref diff base type
7226/// sub-object of this instance of @ref scope_diff.
7227///
7228/// The children node can then later be retrieved using
7229/// diff::children_node().
7230void
7232{
7233 for (diff_sptrs_type::const_iterator i = changed_types().begin();
7234 i != changed_types().end();
7235 ++i)
7236 if (*i)
7238
7239 for (diff_sptrs_type::const_iterator i = changed_decls().begin();
7240 i != changed_decls().end();
7241 ++i)
7242 if (*i)
7244}
7245
7246/// Constructor for scope_diff
7247///
7248/// @param first_scope the first scope to consider for the diff.
7249///
7250/// @param second_scope the second scope to consider for the diff.
7251///
7252/// @param ctxt the diff context to use. Note that this context
7253/// object must stay alive at least during the life time of the
7254/// current instance of @ref scope_diff. Otherwise memory corruption
7255/// issues occur.
7257 scope_decl_sptr second_scope,
7258 diff_context_sptr ctxt)
7259 : diff(first_scope, second_scope, ctxt),
7260 priv_(new priv)
7261{}
7262
7263/// Getter for the first scope of the diff.
7264///
7265/// @return the first scope of the diff.
7266const scope_decl_sptr
7268{return dynamic_pointer_cast<scope_decl>(first_subject());}
7269
7270/// Getter for the second scope of the diff.
7271///
7272/// @return the second scope of the diff.
7273const scope_decl_sptr
7275{return dynamic_pointer_cast<scope_decl>(second_subject());}
7276
7277/// Accessor of the edit script of the members of a scope.
7278///
7279/// This edit script is computed using the equality operator that
7280/// applies to shared_ptr<decl_base>.
7281///
7282/// That has interesting consequences. For instance, consider two
7283/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7284/// S0'. C0 and C0' have the same qualified name, but have different
7285/// members. The edit script will consider that C0 has been deleted
7286/// from S0 and that S0' has been inserted. This is a low level
7287/// canonical representation of the changes; a higher level
7288/// representation would give us a simpler way to say "the class C0
7289/// has been modified into C0'". But worry not. We do have such
7290/// higher representation as well; that is what changed_types() and
7291/// changed_decls() is for.
7292///
7293/// @return the edit script of the changes encapsulatd in this
7294/// instance of scope_diff.
7295const edit_script&
7297{return priv_->member_changes_;}
7298
7299/// Accessor of the edit script of the members of a scope.
7300///
7301/// This edit script is computed using the equality operator that
7302/// applies to shared_ptr<decl_base>.
7303///
7304/// That has interesting consequences. For instance, consider two
7305/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7306/// S0'. C0 and C0' have the same qualified name, but have different
7307/// members. The edit script will consider that C0 has been deleted
7308/// from S0 and that S0' has been inserted. This is a low level
7309/// canonical representation of the changes; a higher level
7310/// representation would give us a simpler way to say "the class C0
7311/// has been modified into C0'". But worry not. We do have such
7312/// higher representation as well; that is what changed_types() and
7313/// changed_decls() is for.
7314///
7315/// @return the edit script of the changes encapsulatd in this
7316/// instance of scope_diff.
7319{return priv_->member_changes_;}
7320
7321/// Accessor that eases the manipulation of the edit script associated
7322/// to this instance. It returns the scope member that is reported
7323/// (in the edit script) as deleted at a given index.
7324///
7325/// @param i the index (in the edit script) of an element of the first
7326/// scope that has been reported as being delete.
7327///
7328/// @return the scope member that has been reported by the edit script
7329/// as being deleted at index i.
7330const decl_base_sptr
7332{
7333 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
7334 return scope->get_member_decls()[i];
7335}
7336
7337/// Accessor that eases the manipulation of the edit script associated
7338/// to this instance. It returns the scope member (of the first scope
7339/// of this diff instance) that is reported (in the edit script) as
7340/// deleted at a given iterator.
7341///
7342/// @param i the iterator of an element of the first scope that has
7343/// been reported as being delete.
7344///
7345/// @return the scope member of the first scope of this diff that has
7346/// been reported by the edit script as being deleted at iterator i.
7347const decl_base_sptr
7348scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
7349{return deleted_member_at(i->index());}
7350
7351/// Accessor that eases the manipulation of the edit script associated
7352/// to this instance. It returns the scope member (of the second
7353/// scope of this diff instance) that is reported as being inserted
7354/// from a given index.
7355///
7356/// @param i the index of an element of the second scope this diff
7357/// that has been reported by the edit script as being inserted.
7358///
7359/// @return the scope member of the second scope of this diff that has
7360/// been reported as being inserted from index i.
7361const decl_base_sptr
7363{
7364 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
7365 return scope->get_member_decls()[i];
7366}
7367
7368/// Accessor that eases the manipulation of the edit script associated
7369/// to this instance. It returns the scope member (of the second
7370/// scope of this diff instance) that is reported as being inserted
7371/// from a given iterator.
7372///
7373/// @param i the iterator of an element of the second scope this diff
7374/// that has been reported by the edit script as being inserted.
7375///
7376/// @return the scope member of the second scope of this diff that has
7377/// been reported as being inserted from iterator i.
7378const decl_base_sptr
7379scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
7380{return inserted_member_at(*i);}
7381
7382/// @return a sorted vector of the types which content has changed
7383/// from the first scope to the other.
7384const diff_sptrs_type&
7386{return priv_->sorted_changed_types_;}
7387
7388/// @return a sorted vector of the decls which content has changed
7389/// from the first scope to the other.
7390const diff_sptrs_type&
7392{return priv_->sorted_changed_decls_;}
7393
7395scope_diff::removed_types() const
7396{return priv_->removed_types_;}
7397
7399scope_diff::removed_decls() const
7400{return priv_->removed_decls_;}
7401
7403scope_diff::added_types() const
7404{return priv_->added_types_;}
7405
7407scope_diff::added_decls() const
7408{return priv_->added_decls_;}
7409
7410/// @return the pretty representation for the current instance of @ref
7411/// scope_diff.
7412const string&
7414{
7415 if (diff::priv_->pretty_representation_.empty())
7416 {
7417 std::ostringstream o;
7418 o << "scope_diff["
7419 << first_subject()->get_pretty_representation()
7420 << ", "
7421 << second_subject()->get_pretty_representation()
7422 << "]";
7423 diff::priv_->pretty_representation_ = o.str();
7424 }
7425 return diff::priv_->pretty_representation_;
7426}
7427
7428/// Return true iff the current diff node carries a change.
7429///
7430/// Return true iff the current diff node carries a change.
7431bool
7433{
7434 // TODO: add the number of really removed/added stuff.
7435 return changed_types().size() + changed_decls().size();
7436}
7437
7438/// @return the kind of local change carried by the current diff node.
7439/// The value returned is zero if the current node carries no local
7440/// change.
7441enum change_kind
7443{
7444 ir::change_kind k = ir::NO_CHANGE_KIND;
7445 if (!equals(*first_scope(), *second_scope(), &k))
7446 return k & ir::ALL_LOCAL_CHANGES_MASK;
7447 return ir::NO_CHANGE_KIND;
7448}
7449
7450/// Report the changes of one scope against another.
7451///
7452/// @param out the out stream to report the changes to.
7453///
7454/// @param indent the string to use for indentation.
7455void
7456scope_diff::report(ostream& out, const string& indent) const
7457{
7458 context()->get_reporter()->report(*this, out, indent);
7459}
7460
7461/// Compute the diff between two scopes.
7462///
7463/// Note that the two decls must have been created in the same @ref
7464/// environment, otherwise, this function aborts.
7465///
7466/// @param first the first scope to consider in computing the diff.
7467///
7468/// @param second the second scope to consider in the diff
7469/// computation. The second scope is diffed against the first scope.
7470///
7471/// @param d a pointer to the diff object to populate with the
7472/// computed diff.
7473///
7474/// @return return the populated \a d parameter passed to this
7475/// function.
7476///
7477/// @param ctxt the diff context to use.
7480 const scope_decl_sptr second,
7482 diff_context_sptr ctxt)
7483{
7484 ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
7485
7486 compute_diff(first->get_member_decls().begin(),
7487 first->get_member_decls().end(),
7488 second->get_member_decls().begin(),
7489 second->get_member_decls().end(),
7490 d->member_changes());
7491
7492 d->ensure_lookup_tables_populated();
7493 d->context(ctxt);
7494
7495 return d;
7496}
7497
7498/// Compute the diff between two scopes.
7499///
7500/// Note that the two decls must have been created in the same @ref
7501/// environment, otherwise, this function aborts.
7502///
7503/// @param first_scope the first scope to consider in computing the diff.
7504///
7505/// @param second_scope the second scope to consider in the diff
7506/// computation. The second scope is diffed against the first scope.
7507///
7508/// @param ctxt the diff context to use.
7509///
7510/// @return return the resulting diff
7513 const scope_decl_sptr second_scope,
7514 diff_context_sptr ctxt)
7515{
7516 scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
7517 d = compute_diff(first_scope, second_scope, d, ctxt);
7518 ctxt->initialize_canonical_diff(d);
7519 return d;
7520}
7521
7522//</scope_diff stuff>
7523
7524// <fn_parm_diff stuff>
7525
7526/// Constructor for the fn_parm_diff type.
7527///
7528/// @param first the first subject of the diff.
7529///
7530/// @param second the second subject of the diff.
7531///
7532/// @param ctxt the context of the diff. Note that this context
7533/// object must stay alive at least during the life time of the
7534/// current instance of @ref fn_parm_diff. Otherwise memory
7535/// corruption issues occur.
7536fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
7537 const function_decl::parameter_sptr second,
7538 diff_context_sptr ctxt)
7539 : decl_diff_base(first, second, ctxt),
7540 priv_(new priv)
7541{
7542 ABG_ASSERT(first->get_index() == second->get_index());
7543 priv_->type_diff = compute_diff(first->get_type(),
7544 second->get_type(),
7545 ctxt);
7546 ABG_ASSERT(priv_->type_diff);
7547}
7548
7549/// Getter for the first subject of this diff node.
7550///
7551/// @return the first function_decl::parameter_sptr subject of this
7552/// diff node.
7555{return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
7556
7557/// Getter for the second subject of this diff node.
7558///
7559/// @return the second function_decl::parameter_sptr subject of this
7560/// diff node.
7563{return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7564
7565/// Getter for the diff representing the changes on the type of the
7566/// function parameter involved in the current instance of @ref
7567/// fn_parm_diff.
7568///
7569/// @return a diff_sptr representing the changes on the type of the
7570/// function parameter we are interested in.
7573{return priv_->type_diff;}
7574
7575/// Build and return a textual representation of the current instance
7576/// of @ref fn_parm_diff.
7577///
7578/// @return the string representing the current instance of
7579/// fn_parm_diff.
7580const string&
7582{
7583 if (diff::priv_->pretty_representation_.empty())
7584 {
7585 std::ostringstream o;
7586 o << "function_parameter_diff["
7587 << first_subject()->get_pretty_representation()
7588 << ", "
7589 << second_subject()->get_pretty_representation()
7590 << "]";
7591 diff::priv_->pretty_representation_ = o.str();
7592 }
7593 return diff::priv_->pretty_representation_;
7594}
7595
7596/// Return true iff the current diff node carries a change.
7597///
7598/// @return true iff the current diff node carries a change.
7599bool
7601{return *first_parameter() != *second_parameter();}
7602
7603/// Check if the current diff node carries a local change.
7604///
7605/// @return the kind of local change carried by the current diff node.
7606/// The value returned is zero if the current node carries no local
7607/// change.
7608enum change_kind
7610{
7611 ir::change_kind k = ir::NO_CHANGE_KIND;
7612 if (!equals(*first_parameter(), *second_parameter(), &k))
7613 return k & ir::ALL_LOCAL_CHANGES_MASK;
7614 return ir::NO_CHANGE_KIND;
7615}
7616
7617/// Emit a textual report about the current fn_parm_diff instance.
7618///
7619/// @param out the output stream to emit the textual report to.
7620///
7621/// @param indent the indentation string to use in the report.
7622void
7623fn_parm_diff::report(ostream& out, const string& indent) const
7624{
7625 context()->get_reporter()->report(*this, out, indent);
7626}
7627
7628/// Populate the vector of children nodes of the @ref diff base type
7629/// sub-object of this instance of @ref fn_parm_diff.
7630///
7631/// The children nodes can then later be retrieved using
7632/// diff::children_nodes()
7633void
7635{
7636 if (type_diff())
7638}
7639
7640/// Compute the difference between two function_decl::parameter_sptr;
7641/// that is, between two function parameters. Return a resulting
7642/// fn_parm_diff_sptr that represents the changes.
7643///
7644/// Note that the two decls must have been created in the same @ref
7645/// environment, otherwise, this function aborts.
7646///
7647/// @param first the first subject of the diff.
7648///
7649/// @param second the second subject of the diff.
7650///
7651/// @param ctxt the context of the diff.
7652///
7653/// @return fn_parm_diff_sptr the resulting diff node.
7656 const function_decl::parameter_sptr second,
7657 diff_context_sptr ctxt)
7658{
7659 if (!first || !second)
7660 return fn_parm_diff_sptr();
7661
7662 fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7663 ctxt->initialize_canonical_diff(result);
7664
7665 return result;
7666}
7667// </fn_parm_diff stuff>
7668
7669// <function_type_diff stuff>
7670
7671void
7672function_type_diff::ensure_lookup_tables_populated()
7673{
7674 priv_->return_type_diff_ =
7675 compute_diff(first_function_type()->get_return_type(),
7676 second_function_type()->get_return_type(),
7677 context());
7678
7679 string parm_name;
7681 for (vector<deletion>::const_iterator i =
7682 priv_->parm_changes_.deletions().begin();
7683 i != priv_->parm_changes_.deletions().end();
7684 ++i)
7685 {
7686 parm = *(first_function_type()->get_first_parm()
7687 + i->index());
7688 parm_name = parm->get_name_id();
7689 // If for a reason the type name is empty we want to know and
7690 // fix that.
7691 ABG_ASSERT(!parm_name.empty());
7692 priv_->deleted_parms_[parm_name] = parm;
7693 priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7694 }
7695
7696 for (vector<insertion>::const_iterator i =
7697 priv_->parm_changes_.insertions().begin();
7698 i != priv_->parm_changes_.insertions().end();
7699 ++i)
7700 {
7701 for (vector<unsigned>::const_iterator j =
7702 i->inserted_indexes().begin();
7703 j != i->inserted_indexes().end();
7704 ++j)
7705 {
7706 parm = *(second_function_type()->get_first_parm() + *j);
7707 parm_name = parm->get_name_id();
7708 // If for a reason the type name is empty we want to know and
7709 // fix that.
7710 ABG_ASSERT(!parm_name.empty());
7711 {
7712 string_parm_map::const_iterator k =
7713 priv_->deleted_parms_.find(parm_name);
7714 if (k != priv_->deleted_parms_.end())
7715 {
7716 if (*k->second != *parm)
7717 priv_->subtype_changed_parms_[parm_name] =
7718 compute_diff(k->second, parm, context());
7719 priv_->deleted_parms_.erase(parm_name);
7720 }
7721 else
7722 priv_->added_parms_[parm_name] = parm;
7723 }
7724 {
7725 unsigned_parm_map::const_iterator k =
7726 priv_->deleted_parms_by_id_.find(parm->get_index());
7727 if (k != priv_->deleted_parms_by_id_.end())
7728 {
7729 if (*k->second != *parm
7730 && (k->second->get_name_id() != parm_name))
7731 priv_->changed_parms_by_id_[parm->get_index()] =
7732 compute_diff(k->second, parm, context());
7733 priv_->added_parms_.erase(parm_name);
7734 priv_->deleted_parms_.erase(k->second->get_name_id());
7735 priv_->deleted_parms_by_id_.erase(parm->get_index());
7736 }
7737 else
7738 priv_->added_parms_by_id_[parm->get_index()] = parm;
7739 }
7740 }
7741 }
7742
7743 sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7744 priv_->sorted_subtype_changed_parms_);
7745 sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7746 priv_->sorted_changed_parms_by_id_);
7747 sort_string_parm_map(priv_->deleted_parms_,
7748 priv_->sorted_deleted_parms_);
7749
7750 sort_string_parm_map(priv_->added_parms_,
7751 priv_->sorted_added_parms_);
7752}
7753
7754/// In the vector of deleted parameters, get the one that is at a given
7755/// index.
7756///
7757/// @param i the index of the deleted parameter to get.
7758///
7759/// @return the parameter returned.
7761function_type_diff::deleted_parameter_at(int i) const
7762{return first_function_type()->get_parameters()[i];}
7763
7764/// Getter for the sorted vector of deleted parameters.
7765///
7766/// @return the sorted vector of deleted parameters.
7767const vector<function_decl::parameter_sptr>&
7769{return priv_->sorted_deleted_parms_;}
7770
7771/// Getter for the sorted vector of added parameters .
7772///
7773/// @return the sorted vector of added parameters.
7774const vector<function_decl::parameter_sptr>&
7776{return priv_->sorted_added_parms_;}
7777
7778/// In the vector of inserted parameters, get the one that is at a
7779/// given index.
7780///
7781/// @param i the index of the inserted parameter to get.
7782///
7783/// @return the parameter returned.
7785function_type_diff::inserted_parameter_at(int i) const
7786{return second_function_type()->get_parameters()[i];}
7787
7788/// Consutrctor of the @ref function_type type.
7789///
7790/// @param first the first @ref function_type subject of the diff to
7791/// create.
7792///
7793/// @param second the second @ref function_type subject of the diff to
7794/// create.
7795///
7796/// @param ctxt the diff context to be used by the newly created
7797/// instance of function_type_diff. Note that this context object
7798/// must stay alive at least during the life time of the current
7799/// instance of @ref function_type_diff. Otherwise memory corruption
7800/// issues occur.
7802 const function_type_sptr second,
7803 diff_context_sptr ctxt)
7804 : type_diff_base(first, second, ctxt),
7805 priv_(new priv)
7806{}
7807
7808/// Getter for the first subject of the diff.
7809///
7810/// @return the first function type involved in the diff.
7813{return dynamic_pointer_cast<function_type>(first_subject());}
7814
7815/// Getter for the second subject of the diff.
7816///
7817/// @return the second function type involved in the diff.
7820{return dynamic_pointer_cast<function_type>(second_subject());}
7821
7822/// Getter for the diff of the return types of the two function types
7823/// of the current diff.
7824///
7825/// @return the diff of the return types of the two function types of
7826/// the current diff.
7827const diff_sptr
7829{return priv_->return_type_diff_;}
7830
7831/// Getter for the map of function parameter changes of the current diff.
7832///
7833/// @return a map of function parameter changes of the current diff.
7836{return priv_->subtype_changed_parms_;}
7837
7838/// Getter for the map of parameters that got removed.
7839///
7840/// @return the map of parameters that got removed.
7841const string_parm_map&
7843{return priv_->deleted_parms_;}
7844
7845/// Getter for the map of parameters that got added.
7846///
7847/// @return the map of parameters that got added.
7848const string_parm_map&
7850{return priv_->added_parms_;}
7851
7852/// Build and return a copy of a pretty representation of the current
7853/// instance of @ref function_type_diff.
7854///
7855/// @return a copy of the pretty representation of the current
7856/// instance of @ref function_type_diff.
7857const string&
7859{
7860 if (diff::priv_->pretty_representation_.empty())
7861 {
7862 std::ostringstream o;
7863 o << "function_type_diff["
7865 << ", "
7867 << "]";
7868 diff::priv_->pretty_representation_ = o.str();
7869 }
7870 return diff::priv_->pretty_representation_;
7871}
7872
7873/// Test if the current diff node carries changes.
7874///
7875/// @return true iff the current diff node carries changes.
7876bool
7879
7880/// Test if the current diff node carries local changes.
7881///
7882/// A local change is a change that is carried by this diff node, not
7883/// by any of its children nodes.
7884///
7885/// @return the kind of local change carried by the current diff node.
7886/// The value returned is zero if the current node carries no local
7887/// change.
7888enum change_kind
7890{
7891 ir::change_kind k = ir::NO_CHANGE_KIND;
7893 return k & ir::ALL_LOCAL_CHANGES_MASK;
7894 return ir::NO_CHANGE_KIND;
7895}
7896
7897/// Build and emit a textual report about the current @ref
7898/// function_type_diff instance.
7899///
7900/// @param out the output stream.
7901///
7902/// @param indent the indentation string to use.
7903void
7904function_type_diff::report(ostream& out, const string& indent) const
7905{
7906 context()->get_reporter()->report(*this, out, indent);
7907}
7908
7909/// Populate the vector of children node of the @ref diff base type
7910/// sub-object of this instance of @ref function_type_diff.
7911///
7912/// The children node can then later be retrieved using
7913/// diff::children_node().
7914void
7916{
7917 if (diff_sptr d = return_type_diff())
7919
7920 for (vector<fn_parm_diff_sptr>::const_iterator i =
7921 priv_->sorted_subtype_changed_parms_.begin();
7922 i != priv_->sorted_subtype_changed_parms_.end();
7923 ++i)
7924 if (diff_sptr d = *i)
7926
7927 for (vector<fn_parm_diff_sptr>::const_iterator i =
7928 priv_->sorted_changed_parms_by_id_.begin();
7929 i != priv_->sorted_changed_parms_by_id_.end();
7930 ++i)
7931 if (diff_sptr d = *i)
7933}
7934
7935/// Compute the diff between two instances of @ref function_type.
7936///
7937/// Note that the two types must have been created in the same @ref
7938/// environment, otherwise, this function aborts.
7939///
7940/// @param first the first @ref function_type to consider for the diff.
7941///
7942/// @param second the second @ref function_type to consider for the diff.
7943///
7944/// @param ctxt the diff context to use.
7945///
7946/// @return the resulting diff between the two @ref function_type.
7949 const function_type_sptr second,
7950 diff_context_sptr ctxt)
7951{
7952 if (!first || !second)
7953 {
7954 // TODO: implement this for either first or second being NULL.
7955 return function_type_diff_sptr();
7956 }
7957
7958 function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7959
7960 diff_utils::compute_diff(first->get_first_parm(),
7961 first->get_parameters().end(),
7962 second->get_first_parm(),
7963 second->get_parameters().end(),
7964 result->priv_->parm_changes_);
7965
7966 result->ensure_lookup_tables_populated();
7967
7968 ctxt->initialize_canonical_diff(result);
7969
7970 return result;
7971}
7972// </function_type_diff stuff>
7973
7974// <function_decl_diff stuff>
7975
7976/// Build the lookup tables of the diff, if necessary.
7977void
7978function_decl_diff::ensure_lookup_tables_populated()
7979{
7980}
7981
7982/// Populate the vector of children node of the @ref diff base type
7983/// sub-object of this instance of @ref function_decl_diff.
7984///
7985/// The children node can then later be retrieved using
7986/// diff::children_node().
7987void
7989{
7990 if (diff_sptr d = type_diff())
7992}
7993
7994/// Constructor for function_decl_diff
7995///
7996/// @param first the first function considered by the diff.
7997///
7998/// @param second the second function considered by the diff.
7999///
8000/// @param ctxt the context of the diff. Note that this context
8001/// object must stay alive at least during the life time of the
8002/// current instance of @ref function_decl_diff. Otherwise memory
8003/// corruption issues occur.
8005 const function_decl_sptr second,
8006 diff_context_sptr ctxt)
8007 : decl_diff_base(first, second, ctxt),
8008 priv_(new priv)
8009{
8010}
8011
8012/// @return the first function considered by the diff.
8015{return dynamic_pointer_cast<function_decl>(first_subject());}
8016
8017/// @return the second function considered by the diff.
8020{return dynamic_pointer_cast<function_decl>(second_subject());}
8021
8023function_decl_diff::type_diff() const
8024{return priv_->type_diff_;}
8025
8026/// @return the pretty representation for the current instance of @ref
8027/// function_decl_diff.
8028const string&
8030{
8031 if (diff::priv_->pretty_representation_.empty())
8032 {
8033 std::ostringstream o;
8034 o << "function_diff["
8035 << first_subject()->get_pretty_representation()
8036 << ", "
8037 << second_subject()->get_pretty_representation()
8038 << "]";
8039 diff::priv_->pretty_representation_ = o.str();
8040 }
8041 return diff::priv_->pretty_representation_;
8042}
8043
8044/// Return true iff the current diff node carries a change.
8045///
8046/// @return true iff the current diff node carries a change.
8047bool
8050
8051/// @return the kind of local change carried by the current diff node.
8052/// The value returned is zero if the current node carries no local
8053/// change.
8054enum change_kind
8056{
8057 ir::change_kind k = ir::NO_CHANGE_KIND;
8059 return k & ir::ALL_LOCAL_CHANGES_MASK;
8060 return ir::NO_CHANGE_KIND;
8061}
8062
8063/// Serialize a report of the changes encapsulated in the current
8064/// instance of @ref function_decl_diff over to an output stream.
8065///
8066/// @param out the output stream to serialize the report to.
8067///
8068/// @param indent the string to use an an indentation prefix.
8069void
8070function_decl_diff::report(ostream& out, const string& indent) const
8071{
8072 context()->get_reporter()->report(*this, out, indent);
8073}
8074
8075/// Compute the diff between two function_decl.
8076///
8077/// Note that the two decls must have been created in the same @ref
8078/// environment, otherwise, this function aborts.
8079///
8080/// @param first the first function_decl to consider for the diff
8081///
8082/// @param second the second function_decl to consider for the diff
8083///
8084/// @param ctxt the diff context to use.
8085///
8086/// @return the computed diff
8089 const function_decl_sptr second,
8090 diff_context_sptr ctxt)
8091{
8092 if (!first || !second)
8093 {
8094 // TODO: implement this for either first or second being NULL.
8095 return function_decl_diff_sptr();
8096 }
8097
8098 function_type_diff_sptr type_diff = compute_diff(first->get_type(),
8099 second->get_type(),
8100 ctxt);
8101
8102 function_decl_diff_sptr result(new function_decl_diff(first, second,
8103 ctxt));
8104 result->priv_->type_diff_ = type_diff;
8105
8106 result->ensure_lookup_tables_populated();
8107
8108 ctxt->initialize_canonical_diff(result);
8109
8110 return result;
8111}
8112
8113// </function_decl_diff stuff>
8114
8115// <type_decl_diff stuff>
8116
8117/// Constructor for type_decl_diff.
8118///
8119/// @param first the first subject of the diff.
8120///
8121/// @param second the second subject of the diff.
8122///
8123/// @param ctxt the context of the diff. Note that this context
8124/// object must stay alive at least during the life time of the
8125/// current instance of @ref type_decl_diff. Otherwise memory
8126/// corruption issues occur.
8127type_decl_diff::type_decl_diff(const type_decl_sptr first,
8128 const type_decl_sptr second,
8129 diff_context_sptr ctxt)
8130 : type_diff_base(first, second, ctxt)
8131{}
8132
8133/// Getter for the first subject of the type_decl_diff.
8134///
8135/// @return the first type_decl involved in the diff.
8136const type_decl_sptr
8138{return dynamic_pointer_cast<type_decl>(first_subject());}
8139
8140/// Getter for the second subject of the type_decl_diff.
8141///
8142/// @return the second type_decl involved in the diff.
8143const type_decl_sptr
8145{return dynamic_pointer_cast<type_decl>(second_subject());}
8146
8147/// @return the pretty representation for the current instance of @ref
8148/// type_decl_diff.
8149const string&
8151{
8152 if (diff::priv_->pretty_representation_.empty())
8153 {
8154 std::ostringstream o;
8155 o << "type_decl_diff["
8156 << first_subject()->get_pretty_representation()
8157 << ", "
8158 << second_subject()->get_pretty_representation()
8159 << "]";
8160 diff::priv_->pretty_representation_ = o.str();
8161 }
8162 return diff::priv_->pretty_representation_;
8163}
8164/// Return true iff the current diff node carries a change.
8165///
8166/// @return true iff the current diff node carries a change.
8167bool
8169{return first_type_decl() != second_type_decl();}
8170
8171/// @return the kind of local change carried by the current diff node.
8172/// The value returned is zero if the current node carries no local
8173/// change.
8174enum change_kind
8176{
8177 ir::change_kind k = ir::NO_CHANGE_KIND;
8178 if (!equals(*first_type_decl(), *second_type_decl(), &k))
8179 return k & ir::ALL_LOCAL_CHANGES_MASK;
8180 return ir::NO_CHANGE_KIND;
8181}
8182/// Ouputs a report of the differences between of the two type_decl
8183/// involved in the type_decl_diff.
8184///
8185/// @param out the output stream to emit the report to.
8186///
8187/// @param indent the string to use for indentatino indent.
8188void
8189type_decl_diff::report(ostream& out, const string& indent) const
8190{
8191 context()->get_reporter()->report(*this, out, indent);
8192}
8193
8194/// Compute a diff between two type_decl.
8195///
8196/// Note that the two types must have been created in the same @ref
8197/// environment, otherwise, this function aborts.
8198///
8199/// This function doesn't actually compute a diff. As a type_decl is
8200/// very simple (unlike compound constructs like function_decl or
8201/// class_decl) it's easy to just compare the components of the
8202/// type_decl to know what has changed. Thus this function just
8203/// builds and return a type_decl_diff object. The
8204/// type_decl_diff::report function will just compare the components
8205/// of the the two type_decl and display where and how they differ.
8206///
8207/// @param first a pointer to the first type_decl to
8208/// consider.
8209///
8210/// @param second a pointer to the second type_decl to consider.
8211///
8212/// @param ctxt the diff context to use.
8213///
8214/// @return a pointer to the resulting type_decl_diff.
8217 const type_decl_sptr second,
8218 diff_context_sptr ctxt)
8219{
8220 type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
8221
8222 // We don't need to actually compute a diff here as a type_decl
8223 // doesn't have complicated sub-components. type_decl_diff::report
8224 // just walks the members of the type_decls and display information
8225 // about the ones that have changed. On a similar note,
8226 // type_decl_diff::length returns 0 if the two type_decls are equal,
8227 // and 1 otherwise.
8228
8229 ctxt->initialize_canonical_diff(result);
8230
8231 return result;
8232}
8233
8234// </type_decl_diff stuff>
8235
8236// <typedef_diff stuff>
8237
8238/// Populate the vector of children node of the @ref diff base type
8239/// sub-object of this instance of @ref typedef_diff.
8240///
8241/// The children node can then later be retrieved using
8242/// diff::children_node().
8243void
8246
8247/// Constructor for typedef_diff.
8248///
8249/// @param first the first subject of the diff.
8250///
8251/// @param second the second subject of the diff.
8252///
8253/// @param underlying the underlying diff of the @ref typedef_diff.
8254/// That is the diff between the underlying types of @p first and @p
8255/// second.
8256///
8257/// @param ctxt the context of the diff. Note that this context
8258/// object must stay alive at least during the life time of the
8259/// current instance of @ref typedef_diff. Otherwise memory
8260/// corruption issues occur.
8261typedef_diff::typedef_diff(const typedef_decl_sptr first,
8262 const typedef_decl_sptr second,
8263 const diff_sptr underlying,
8264 diff_context_sptr ctxt)
8265 : type_diff_base(first, second, ctxt),
8266 priv_(new priv(underlying))
8267{}
8268
8269/// Getter for the firt typedef_decl involved in the diff.
8270///
8271/// @return the first subject of the diff.
8274{return dynamic_pointer_cast<typedef_decl>(first_subject());}
8275
8276/// Getter for the second typedef_decl involved in the diff.
8277///
8278/// @return the second subject of the diff.
8281{return dynamic_pointer_cast<typedef_decl>(second_subject());}
8282
8283/// Getter for the diff between the two underlying types of the
8284/// typedefs.
8285///
8286/// @return the diff object reprensenting the difference between the
8287/// two underlying types of the typedefs.
8288const diff_sptr
8290{return priv_->underlying_type_diff_;}
8291
8292/// Setter for the diff between the two underlying types of the
8293/// typedefs.
8294///
8295/// @param d the new diff object reprensenting the difference between
8296/// the two underlying types of the typedefs.
8297void
8299{priv_->underlying_type_diff_ = d;}
8300
8301/// @return the pretty representation for the current instance of @ref
8302/// typedef_diff.
8303const string&
8305{
8306 if (diff::priv_->pretty_representation_.empty())
8307 {
8308 std::ostringstream o;
8309 o << "typedef_diff["
8310 << first_subject()->get_pretty_representation()
8311 << ", "
8312 << second_subject()->get_pretty_representation()
8313 << "]";
8314 diff::priv_->pretty_representation_ = o.str();
8315 }
8316 return diff::priv_->pretty_representation_;
8317}
8318
8319/// Return true iff the current diff node carries a change.
8320///
8321/// @return true iff the current diff node carries a change.
8322bool
8324{
8325 decl_base_sptr second = second_typedef_decl();
8326 return !(*first_typedef_decl() == *second);
8327}
8328
8329/// @return the kind of local change carried by the current diff node.
8330/// The value returned is zero if the current node carries no local
8331/// change.
8332enum change_kind
8334{
8335 ir::change_kind k = ir::NO_CHANGE_KIND;
8337 return k & ir::ALL_LOCAL_CHANGES_MASK;
8338 return ir::NO_CHANGE_KIND;
8339}
8340
8341/// Reports the difference between the two subjects of the diff in a
8342/// serialized form.
8343///
8344/// @param out the output stream to emit the report to.
8345///
8346/// @param indent the indentation string to use.
8347void
8348typedef_diff::report(ostream& out, const string& indent) const
8349{
8350 context()->get_reporter()->report(*this, out, indent);
8351}
8352
8353/// Compute a diff between two typedef_decl.
8354///
8355/// Note that the two types must have been created in the same @ref
8356/// environment, otherwise, this function aborts.
8357///
8358/// @param first a pointer to the first typedef_decl to consider.
8359///
8360/// @param second a pointer to the second typedef_decl to consider.
8361///
8362/// @param ctxt the diff context to use.
8363///
8364/// @return a pointer to the the resulting typedef_diff.
8367 const typedef_decl_sptr second,
8368 diff_context_sptr ctxt)
8369{
8370 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
8371 second->get_underlying_type(),
8372 ctxt);
8373 typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
8374
8375 ctxt->initialize_canonical_diff(result);
8376
8377 return result;
8378}
8379
8380/// Return the leaf underlying diff node of a @ref typedef_diff node.
8381///
8382/// If the underlying diff node of a @ref typedef_diff node is itself
8383/// a @ref typedef_diff node, then recursively look at the underlying
8384/// diff nodes to get the first one that is not a a @ref typedef_diff
8385/// node. This is what a leaf underlying diff node means.
8386///
8387/// Otherwise, if the underlying diff node of @ref typedef_diff is
8388/// *NOT* a @ref typedef_diff node, then just return the underlying
8389/// diff node.
8390///
8391/// And if the diff node considered is not a @ref typedef_diff node,
8392/// then just return it.
8393///
8394/// @return the leaf underlying diff node of a @p diff.
8395const diff*
8397{
8398 const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
8399 if (!d)
8400 return diff;
8401
8402 if (const typedef_diff* deef =
8403 dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
8405
8406 return d->underlying_type_diff().get();
8407}
8408
8409// </typedef_diff stuff>
8410
8411// <translation_unit_diff stuff>
8412
8413/// Constructor for translation_unit_diff.
8414///
8415/// @param first the first translation unit to consider for this diff.
8416///
8417/// @param second the second translation unit to consider for this diff.
8418///
8419/// @param ctxt the context of the diff. Note that this context
8420/// object must stay alive at least during the life time of the
8421/// current instance of @ref translation_unit_diff. Otherwise memory
8422/// corruption issues occur.
8424 translation_unit_sptr second,
8425 diff_context_sptr ctxt)
8426 : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
8427 priv_(new priv(first, second))
8428{
8429}
8430
8431/// Getter for the first translation unit of this diff.
8432///
8433/// @return the first translation unit of this diff.
8436{return priv_->first_;}
8437
8438/// Getter for the second translation unit of this diff.
8439///
8440/// @return the second translation unit of this diff.
8443{return priv_->second_;}
8444
8445/// Return true iff the current diff node carries a change.
8446///
8447/// @return true iff the current diff node carries a change.
8448bool
8450{return scope_diff::has_changes();}
8451
8452/// @return the kind of local change carried by the current diff node.
8453/// The value returned is zero if the current node carries no local
8454/// change.
8455enum change_kind
8457{return ir::NO_CHANGE_KIND;}
8458
8459/// Report the diff in a serialized form.
8460///
8461/// @param out the output stream to serialize the report to.
8462///
8463/// @param indent the prefix to use as indentation for the report.
8464void
8465translation_unit_diff::report(ostream& out, const string& indent) const
8466{scope_diff::report(out, indent);}
8467
8468/// Compute the diff between two translation_units.
8469///
8470/// Note that the two translation units must have been created in the
8471/// same @ref environment, otherwise, this function aborts.
8472///
8473/// @param first the first translation_unit to consider.
8474///
8475/// @param second the second translation_unit to consider.
8476///
8477/// @param ctxt the diff context to use. If null, this function will
8478/// create a new context and set to the diff object returned.
8479///
8480/// @return the newly created diff object.
8483 const translation_unit_sptr second,
8484 diff_context_sptr ctxt)
8485{
8486 ABG_ASSERT(first && second);
8487
8488 if (!ctxt)
8489 ctxt.reset(new diff_context);
8490
8491 // TODO: handle first or second having empty contents.
8492 translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
8493 ctxt));
8494 scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
8495
8496 compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
8497 static_pointer_cast<scope_decl>(second->get_global_scope()),
8498 sc_diff,
8499 ctxt);
8500
8501 ctxt->initialize_canonical_diff(tu_diff);
8502
8503 return tu_diff;
8504}
8505
8506// </translation_unit_diff stuff>
8507
8508// <diff_maps stuff>
8509
8510/// The private data of the @ref diff_maps type.
8511struct diff_maps::priv
8512{
8513 string_diff_ptr_map type_decl_diff_map_;
8514 string_diff_ptr_map enum_diff_map_;
8515 string_diff_ptr_map class_diff_map_;
8516 string_diff_ptr_map union_diff_map_;
8517 string_diff_ptr_map typedef_diff_map_;
8518 string_diff_ptr_map subrange_diff_map_;
8519 string_diff_ptr_map array_diff_map_;
8520 string_diff_ptr_map reference_diff_map_;
8521 string_diff_ptr_map function_type_diff_map_;
8522 string_diff_ptr_map function_decl_diff_map_;
8523 string_diff_ptr_map var_decl_diff_map_;
8524 string_diff_ptr_map distinct_diff_map_;
8525 string_diff_ptr_map fn_parm_diff_map_;
8526 diff_artifact_set_map_type impacted_artifacts_map_;
8527}; // end struct diff_maps::priv
8528
8529/// Default constructor of the @ref diff_maps type.
8531 : priv_(new diff_maps::priv())
8532{}
8533
8534diff_maps::~diff_maps() = default;
8535
8536/// Getter of the map that contains basic type diffs.
8537///
8538/// @return the map that contains basic type diffs.
8541{return priv_->type_decl_diff_map_;}
8542
8543/// Getter of the map that contains basic type diffs.
8544///
8545/// @return the map that contains basic type diffs.
8548{return priv_->type_decl_diff_map_;}
8549
8550/// Getter of the map that contains enum type diffs.
8551///
8552/// @return the map that contains enum type diffs.
8555{return priv_->enum_diff_map_;}
8556
8557/// Getter of the map that contains enum type diffs.
8558///
8559/// @return the map that contains enum type diffs.
8562{return priv_->enum_diff_map_;}
8563
8564/// Getter of the map that contains class type diffs.
8565///
8566/// @return the map that contains class type diffs.
8569{return priv_->class_diff_map_;}
8570
8571/// Getter of the map that contains class type diffs.
8572///
8573/// @return the map that contains class type diffs.
8576{return priv_->class_diff_map_;}
8577
8578/// Getter of the map that contains union type diffs.
8579///
8580/// @return the map that contains union type diffs.
8583{return priv_->union_diff_map_;}
8584
8585/// Getter of the map that contains union type diffs.
8586///
8587/// @return the map that contains union type diffs.
8590{return priv_->union_diff_map_;}
8591
8592/// Getter of the map that contains typedef type diffs.
8593///
8594/// @return the map that contains typedef type diffs.
8597{return priv_->typedef_diff_map_;}
8598
8599/// Getter of the map that contains typedef type diffs.
8600///
8601/// @return the map that contains typedef type diffs.
8604{return priv_->typedef_diff_map_;}
8605
8606/// Getter of the map that contains subrange type diffs.
8607///
8608/// @return the map that contains subrange type diffs.
8611{return priv_->subrange_diff_map_;}
8612
8613/// Getter of the map that contains subrange type diffs.
8614///
8615/// @return the map that contains subrange type diffs.
8618{return priv_->subrange_diff_map_;}
8619
8620/// Getter of the map that contains array type diffs.
8621///
8622/// @return the map that contains array type diffs.
8625{return priv_->array_diff_map_;}
8626
8627/// Getter of the map that contains array type diffs.
8628///
8629/// @return the map that contains array type diffs.
8632{return priv_->array_diff_map_;}
8633
8634/// Getter of the map that contains reference type diffs.
8635///
8636/// @return the map that contains reference type diffs.
8639{return priv_->reference_diff_map_;}
8640
8641/// Getter of the map that contains reference type diffs.
8642///
8643/// @return the map that contains reference type diffs.
8646{{return priv_->reference_diff_map_;}}
8647
8648/// Getter of the map that contains function parameter diffs.
8649///
8650/// @return the map that contains function parameter diffs.
8653{return priv_->fn_parm_diff_map_;}
8654
8655/// Getter of the map that contains function parameter diffs.
8656///
8657/// @return the map that contains function parameter diffs.
8660{return priv_->fn_parm_diff_map_;}
8661
8662/// Getter of the map that contains function type diffs.
8663///
8664/// @return the map that contains function type diffs.
8667{return priv_->function_type_diff_map_;}
8668
8669/// Getter of the map that contains function type diffs.
8670///
8671/// @return the map that contains function type diffs.
8674{return priv_->function_type_diff_map_;}
8675
8676/// Getter of the map that contains function decl diffs.
8677///
8678/// @return the map that contains function decl diffs.
8681{return priv_->function_decl_diff_map_;}
8682
8683/// Getter of the map that contains function decl diffs.
8684///
8685/// @return the map that contains function decl diffs.
8688{return priv_->function_decl_diff_map_;}
8689
8690/// Getter of the map that contains var decl diffs.
8691///
8692/// @return the map that contains var decl diffs.
8695{return priv_->var_decl_diff_map_;}
8696
8697/// Getter of the map that contains var decl diffs.
8698///
8699/// @return the map that contains var decl diffs.
8702{return priv_->var_decl_diff_map_;}
8703
8704/// Getter of the map that contains distinct diffs.
8705///
8706/// @return the map that contains distinct diffs.
8709{return priv_->distinct_diff_map_;}
8710
8711/// Getter of the map that contains distinct diffs.
8712///
8713/// @return the map that contains distinct diffs.
8716{return priv_->distinct_diff_map_;}
8717
8718/// Insert a new diff node into the current instance of @ref diff_maps.
8719///
8720/// @param dif the new diff node to insert into the @ref diff_maps.
8721///
8722/// @param impacted_iface the interface (global function or variable)
8723/// currently being analysed that led to analysing the diff node @p
8724/// dif. In other words, this is the interface impacted by the diff
8725/// node @p dif. Note that this can be nil in cases where we are
8726/// directly analysing changes to a type that is not reachable from
8727/// any global function or variable.
8728///
8729/// @return true iff the diff node could be added to the current
8730/// instance of @ref diff_maps.
8731bool
8733 const type_or_decl_base_sptr& impacted_iface)
8734{
8735 string n = get_pretty_representation(dif->first_subject(),
8736 /*internal=*/true);
8737 if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8738 get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8739 else if (const enum_diff *d = is_enum_diff(dif))
8740 get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8741 else if (const class_diff *d = is_class_diff(dif))
8742 get_class_diff_map()[n] = const_cast<class_diff*>(d);
8743 else if (const union_diff *d = is_union_diff(dif))
8744 get_union_diff_map()[n] = const_cast<union_diff*>(d);
8745 else if (const typedef_diff *d = is_typedef_diff(dif))
8746 get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8747 else if (const subrange_diff *d = is_subrange_diff(dif))
8748 get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8749 else if (const array_diff *d = is_array_diff(dif))
8750 get_array_diff_map()[n] = const_cast<array_diff*>(d);
8751 else if (const reference_diff *d = is_reference_diff(dif))
8752 get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8753 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8754 get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8755 else if (const function_type_diff *d = is_function_type_diff(dif))
8756 get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8757 else if (const var_diff *d = is_var_diff(dif))
8758 get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8759 else if (const function_decl_diff *d = is_function_decl_diff(dif))
8760 get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8761 else if (const distinct_diff *d = is_distinct_diff(dif))
8762 get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8763 else if (is_base_diff(dif))
8764 // we silently drop this case.
8765 return true;
8766 else
8768
8769 // Update the map that associates this diff node to the set of
8770 // interfaces it impacts.
8771
8772 if (impacted_iface)
8773 {
8774 diff_artifact_set_map_type::iterator i =
8775 priv_->impacted_artifacts_map_.find(dif);
8776
8777 if (i == priv_->impacted_artifacts_map_.end())
8778 {
8780 set.insert(impacted_iface);
8781 priv_->impacted_artifacts_map_[dif] = set;
8782 }
8783 else
8784 i->second.insert(impacted_iface);
8785 }
8786
8787 return true;
8788}
8789
8790/// Lookup the interfaces that are impacted by a given leaf diff node.
8791///
8792/// @param d the diff node to consider.
8793///
8794/// @return the set of artifacts impacted by @p d.
8797{
8798 diff_artifact_set_map_type::iterator i =
8799 priv_->impacted_artifacts_map_.find(d);
8800
8801 if (i == priv_->impacted_artifacts_map_.end())
8802 return 0;
8803
8804 return &i->second;
8805}
8806
8807//
8808// </diff_maps stuff>
8809
8810/// Constructor for the @ref diff_stat type.
8811///
8812/// @param ctxt the context of the corpus diff. Note that this
8813/// context object must stay alive at least during the life time of
8814/// the current instance of @ref corpus_diff::diff_stats. Otherwise
8815/// memory corruption issues occur.
8816corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8817 : priv_(new priv(ctxt))
8818{}
8819
8820/// Getter for the number of functions removed.
8821///
8822/// @return the number of functions removed.
8823size_t
8825{return priv_->num_func_removed;}
8826
8827/// Setter for the number of functions removed.
8828///
8829/// @param n the new number of functions removed.
8830void
8832{priv_->num_func_removed = n;}
8833
8834/// Getter for the number of removed functions that have been filtered
8835/// out.
8836///
8837/// @return the number of removed functions that have been filtered
8838/// out.
8839size_t
8841{
8842 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8843 return num_func_removed();
8844 return priv_->num_removed_func_filtered_out;
8845}
8846
8847/// Setter for the number of removed functions that have been filtered
8848/// out.
8849///
8850/// @param t the new value.
8851void
8853{priv_->num_removed_func_filtered_out = t;}
8854
8855/// Getter for the net number of function removed.
8856///
8857/// This is the difference between the number of functions removed and
8858/// the number of functons removed that have been filtered out.
8859///
8860/// @return the net number of function removed.
8861size_t
8863{
8864 ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8865 return num_func_removed() - num_removed_func_filtered_out();
8866}
8867
8868/// Getter for the number of functions added.
8869///
8870/// @return the number of functions added.
8871size_t
8873{return priv_->num_func_added;}
8874
8875/// Setter for the number of functions added.
8876///
8877/// @param n the new number of functions added.
8878void
8880{priv_->num_func_added = n;}
8881
8882/// Getter for the number of added function that have been filtered out.
8883///
8884/// @return the number of added function that have been filtered out.
8885size_t
8887{
8888 if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8889 return num_func_added();
8890 return priv_->num_added_func_filtered_out;
8891}
8892
8893/// Setter for the number of added function that have been filtered
8894/// out.
8895///
8896/// @param n the new value.
8897void
8899{priv_->num_added_func_filtered_out = n;}
8900
8901/// Getter for the net number of added functions.
8902///
8903/// The net number of added functions is the difference between the
8904/// number of added functions and the number of added functions that
8905/// have been filtered out.
8906///
8907/// @return the net number of added functions.
8908size_t
8910{
8911 ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8912 return num_func_added() - num_added_func_filtered_out();
8913}
8914
8915/// Getter for the number of functions that have a change in one of
8916/// their sub-types.
8917///
8918/// @return the number of functions that have a change in one of their
8919/// sub-types.
8920size_t
8922{return priv_->num_func_changed;}
8923
8924/// Setter for the number of functions that have a change in one of
8925/// their sub-types.
8926///
8927/// @@param n the new number of functions that have a change in one of
8928/// their sub-types.
8929void
8931{priv_->num_func_changed = n;}
8932
8933/// Getter for the number of functions that have a change in one of
8934/// their sub-types, and that have been filtered out.
8935///
8936/// @return the number of functions that have a change in one of their
8937/// sub-types, and that have been filtered out.
8938size_t
8940{return priv_->num_changed_func_filtered_out;}
8941
8942/// Setter for the number of functions that have a change in one of
8943/// their sub-types, and that have been filtered out.
8944///
8945/// @param n the new number of functions that have a change in one of their
8946/// sub-types, and that have been filtered out.
8947void
8949{priv_->num_changed_func_filtered_out = n;}
8950
8951/// Getter for the number of functions that carry virtual member
8952/// offset changes.
8953///
8954/// @return the number of functions that carry virtual member changes.
8955size_t
8957{return priv_->num_func_with_virt_offset_changes;}
8958
8959/// Setter for the number of functions that carry virtual member
8960/// offset changes.
8961///
8962/// @param n the new number of functions that carry virtual member
8963/// offset. changes.
8964void
8966{priv_->num_func_with_virt_offset_changes = n;}
8967
8968/// Getter for the number of functions with local harmful changes.
8969///
8970/// A local harmful change is a harmful change that is local to the
8971/// function itself or is local to a return or parameter type.
8972///
8973/// @return the number of functions with local harmful changes.
8974size_t
8976{return priv_->num_func_with_local_harmful_changes;}
8977
8978/// Setter for the number of functions with local harmful changes.
8979///
8980/// A local harmful change is a harmful change that is local to the
8981/// function itself or is local to a return or parameter type.
8982///
8983/// @param n the number of functions with local harmful changes.
8984void
8986{priv_->num_func_with_local_harmful_changes = n;}
8987
8988/// Getter for the number of variables with local harmful changes.
8989///
8990/// A local harmful change is a harmful change that is local to the
8991/// variable itself or is local to its type.
8992///
8993/// @return the number of variables with local harmful changes.
8994size_t
8996{return priv_->num_var_with_local_harmful_changes;}
8997
8998/// Setter for the number of variables with local harmful changes.
8999///
9000/// A local harmful change is a harmful change that is local to the
9001/// variable itself or is local to its type.
9002///
9003/// @param n the number of variables with local harmful changes.
9004void
9006{priv_->num_var_with_local_harmful_changes = n;}
9007
9008/// Getter for the number of functions with incompatible changes.
9009///
9010/// @return the number of functions with incompatible changes.
9011size_t
9013{return priv_->num_func_with_incompatible_changes;}
9014
9015/// Setter for the number of functions with incompatible changes.
9016///
9017/// @param n the number of functions with incompatible changes.
9018void
9020{priv_->num_func_with_incompatible_changes = n;}
9021
9022/// Getter for the number of variables with incompatible changes.
9023///
9024/// @return the number of variables with incompatible changes.
9025size_t
9027{return priv_->num_var_with_incompatible_changes;}
9028
9029/// Setter for the number of variables with incompatible changes.
9030///
9031/// @param n the number of variables with incompatible changes.
9032void
9034{priv_->num_var_with_incompatible_changes = n;}
9035
9036/// Getter for the number of functions that have a change in their
9037/// sub-types, minus the number of these functions that got filtered
9038/// out from the diff.
9039///
9040/// @return for the the number of functions that have a change in
9041/// their sub-types, minus the number of these functions that got
9042/// filtered out from the diff.
9043size_t
9045{return num_func_changed() - num_changed_func_filtered_out();}
9046
9047/// Getter of the net number of functions with changes that are not
9048/// incompatible.
9049///
9050/// @return net number of functions with changes that are not
9051/// incompatible.
9052size_t
9054{return net_num_func_changed() - num_func_with_incompatible_changes();}
9055
9056/// Getter for the number of variables removed.
9057///
9058/// @return the number of variables removed.
9059size_t
9061{return priv_->num_vars_removed;}
9062
9063/// Setter for the number of variables removed.
9064///
9065/// @param n the new number of variables removed.
9066void
9068{priv_->num_vars_removed = n;}
9069
9070/// Getter for the number removed variables that have been filtered
9071/// out.
9072///
9073/// @return the number removed variables that have been filtered out.
9074size_t
9076{
9077 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
9078 return num_vars_removed();
9079 return priv_->num_removed_vars_filtered_out;
9080}
9081
9082/// Setter for the number of removed variables that have been filtered
9083/// out.
9084///
9085/// @param n the new value.
9086void
9088{priv_->num_removed_vars_filtered_out = n;}
9089
9090/// Getter for the net number of removed variables.
9091///
9092/// The net number of removed variables is the difference between the
9093/// number of removed variables and the number of removed variables
9094/// that have been filtered out.
9095///
9096/// @return the net number of removed variables.
9097size_t
9099{
9100 ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
9101 return num_vars_removed() - num_removed_vars_filtered_out();
9102}
9103
9104/// Getter for the number of variables added.
9105///
9106/// @return the number of variables added.
9107size_t
9109{return priv_->num_vars_added;}
9110
9111/// Setter for the number of variables added.
9112///
9113/// @param n the new number of variables added.
9114void
9116{priv_->num_vars_added = n;}
9117
9118/// Getter for the number of added variables that have been filtered
9119/// out.
9120///
9121/// @return the number of added variables that have been filtered out.
9122size_t
9124{
9125 if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
9126 return num_vars_added();
9127 return priv_->num_added_vars_filtered_out;
9128}
9129
9130/// Setter for the number of added variables that have been filtered
9131/// out.
9132///
9133/// @param n the new value.
9134void
9136{priv_->num_added_vars_filtered_out = n;}
9137
9138/// Getter for the net number of added variables.
9139///
9140/// The net number of added variables is the difference between the
9141/// number of added variables and the number of added variables that
9142/// have been filetered out.
9143///
9144/// @return the net number of added variables.
9145size_t
9147{
9148 ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
9149 return num_vars_added() - num_added_vars_filtered_out();
9150}
9151
9152/// Getter for the number of variables that have a change in one of
9153/// their sub-types.
9154///
9155/// @return the number of variables that have a change in one of their
9156/// sub-types.
9157size_t
9159{return priv_->num_vars_changed;}
9160
9161/// Setter for the number of variables that have a change in one of
9162/// their sub-types.
9163///
9164/// @param n the new number of variables that have a change in one of
9165/// their sub-types.
9166void
9168{priv_->num_vars_changed = n;}
9169
9170/// Getter for the number of variables that have a change in one of
9171/// their sub-types, and that have been filtered out.
9172///
9173/// @return the number of functions that have a change in one of their
9174/// sub-types, and that have been filtered out.
9175size_t
9177{return priv_->num_changed_vars_filtered_out;}
9178
9179/// Setter for the number of variables that have a change in one of
9180/// their sub-types, and that have been filtered out.
9181///
9182/// @param n the new number of variables that have a change in one of their
9183/// sub-types, and that have been filtered out.
9184void
9186{priv_->num_changed_vars_filtered_out = n;}
9187
9188/// Getter for the number of variables that have a change in their
9189/// sub-types, minus the number of these variables that got filtered
9190/// out from the diff.
9191///
9192/// @return for the the number of variables that have a change in
9193/// their sub-types, minus the number of these variables that got
9194/// filtered out from the diff.
9195size_t
9197{return num_vars_changed() - num_changed_vars_filtered_out();}
9198
9199/// Getter of the net number of variables with changes that are not
9200/// incompatible.
9201///
9202/// @return net number of variables with changes that are not
9203/// incompatible.
9204size_t
9206{return net_num_vars_changed() - num_var_with_incompatible_changes();}
9207
9208/// Getter for the number of function symbols (not referenced by any
9209/// debug info) that got removed.
9210///
9211/// @return the number of function symbols (not referenced by any
9212/// debug info) that got removed.
9213size_t
9215{return priv_->num_func_syms_removed;}
9216
9217/// Setter for the number of function symbols (not referenced by any
9218/// debug info) that got removed.
9219///
9220/// @param n the number of function symbols (not referenced by any
9221/// debug info) that got removed.
9222void
9224{priv_->num_func_syms_removed = n;}
9225
9226/// Getter for the number of removed function symbols, not referenced
9227/// by debug info, that have been filtered out.
9228///
9229/// @return the number of removed function symbols, not referenced by
9230/// debug info, that have been filtered out.
9231size_t
9233{
9234 if (priv_->ctxt()
9235 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
9236 return num_func_syms_removed();
9237 return priv_->num_removed_func_syms_filtered_out;
9238}
9239
9240/// Setter for the number of removed function symbols, not referenced
9241/// by debug info, that have been filtered out.
9242///
9243/// @param n the new the number of removed function symbols, not
9244/// referenced by debug info, that have been filtered out.
9245void
9247{priv_->num_removed_func_syms_filtered_out = n;}
9248
9249/// Getter of the net number of removed function symbols that are not
9250/// referenced by any debug info.
9251///
9252/// This is the difference between the total number of removed
9253/// function symbols and the number of removed function symbols that
9254/// have been filteted out. Both numbers are for symbols not
9255/// referenced by debug info.
9256///
9257/// return the net number of removed function symbols that are not
9258/// referenced by any debug info.
9259size_t
9261{
9262 ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
9263 return num_func_syms_removed() - num_removed_func_syms_filtered_out();
9264}
9265
9266/// Getter for the number of function symbols (not referenced by any
9267/// debug info) that got added.
9268///
9269/// @return the number of function symbols (not referenced by any
9270/// debug info) that got added.
9271size_t
9273{return priv_->num_func_syms_added;}
9274
9275/// Setter for the number of function symbols (not referenced by any
9276/// debug info) that got added.
9277///
9278/// @param n the new number of function symbols (not referenced by any
9279/// debug info) that got added.
9280void
9282{priv_->num_func_syms_added = n;}
9283
9284/// Getter for the number of added function symbols, not referenced by
9285/// any debug info, that have been filtered out.
9286///
9287/// @return the number of added function symbols, not referenced by
9288/// any debug info, that have been filtered out.
9289size_t
9291{
9292 if (priv_->ctxt()
9293 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9294 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9295 return num_func_syms_added();
9296 return priv_->num_added_func_syms_filtered_out;
9297}
9298
9299/// Setter for the number of added function symbols, not referenced by
9300/// any debug info, that have been filtered out.
9301///
9302/// @param n the new number of added function symbols, not referenced
9303/// by any debug info, that have been filtered out.
9304void
9306{priv_->num_added_func_syms_filtered_out = n;}
9307
9308/// Getter of the net number of added function symbols that are not
9309/// referenced by any debug info.
9310///
9311/// This is the difference between the total number of added
9312/// function symbols and the number of added function symbols that
9313/// have been filteted out. Both numbers are for symbols not
9314/// referenced by debug info.
9315///
9316/// return the net number of added function symbols that are not
9317/// referenced by any debug info.
9318size_t
9320{
9321 ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
9322 return num_func_syms_added()- num_added_func_syms_filtered_out();
9323}
9324
9325/// Getter for the number of variable symbols (not referenced by any
9326/// debug info) that got removed.
9327///
9328/// @return the number of variable symbols (not referenced by any
9329/// debug info) that got removed.
9330size_t
9332{return priv_->num_var_syms_removed;}
9333
9334/// Setter for the number of variable symbols (not referenced by any
9335/// debug info) that got removed.
9336///
9337/// @param n the number of variable symbols (not referenced by any
9338/// debug info) that got removed.
9339void
9341{priv_->num_var_syms_removed = n;}
9342
9343/// Getter for the number of removed variable symbols, not referenced
9344/// by any debug info, that have been filtered out.
9345///
9346/// @return the number of removed variable symbols, not referenced
9347/// by any debug info, that have been filtered out.
9348size_t
9350{
9351 if (priv_->ctxt()
9352 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
9353 return num_var_syms_removed();
9354 return priv_->num_removed_var_syms_filtered_out;
9355}
9356
9357/// Setter for the number of removed variable symbols, not referenced
9358/// by any debug info, that have been filtered out.
9359///
9360/// @param n the number of removed variable symbols, not referenced by
9361/// any debug info, that have been filtered out.
9362void
9364{priv_->num_removed_var_syms_filtered_out = n;}
9365
9366/// Getter of the net number of removed variable symbols that are not
9367/// referenced by any debug info.
9368///
9369/// This is the difference between the total number of removed
9370/// variable symbols and the number of removed variable symbols that
9371/// have been filteted out. Both numbers are for symbols not
9372/// referenced by debug info.
9373///
9374/// return the net number of removed variable symbols that are not
9375/// referenced by any debug info.
9376size_t
9378{
9379 ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
9380 return num_var_syms_removed() - num_removed_var_syms_filtered_out();
9381}
9382
9383/// Getter for the number of variable symbols (not referenced by any
9384/// debug info) that got added.
9385///
9386/// @return the number of variable symbols (not referenced by any
9387/// debug info) that got added.
9388size_t
9390{return priv_->num_var_syms_added;}
9391
9392/// Setter for the number of variable symbols (not referenced by any
9393/// debug info) that got added.
9394///
9395/// @param n the new number of variable symbols (not referenced by any
9396/// debug info) that got added.
9397void
9399{priv_->num_var_syms_added = n;}
9400
9401/// Getter for the number of added variable symbols, not referenced by
9402/// any debug info, that have been filtered out.
9403///
9404/// @return the number of added variable symbols, not referenced by
9405/// any debug info, that have been filtered out.
9406size_t
9408{
9409 if (priv_->ctxt()
9410 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9411 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9412 return num_var_syms_added();
9413 return priv_->num_added_var_syms_filtered_out;
9414}
9415
9416/// Setter for the number of added variable symbols, not referenced by
9417/// any debug info, that have been filtered out.
9418///
9419/// @param n the new number of added variable symbols, not referenced
9420/// by any debug info, that have been filtered out.
9421void
9423{priv_->num_added_var_syms_filtered_out = n;}
9424
9425/// Getter of the net number of added variable symbols that are not
9426/// referenced by any debug info.
9427///
9428/// This is the difference between the total number of added
9429/// variable symbols and the number of added variable symbols that
9430/// have been filteted out. Both numbers are for symbols not
9431/// referenced by debug info.
9432///
9433/// return the net number of added variable symbols that are not
9434/// referenced by any debug info.
9435size_t
9437{
9438 ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
9439 return num_var_syms_added() - num_added_var_syms_filtered_out();
9440}
9441
9442/// Getter of the number of leaf type change diff nodes.
9443///
9444/// @return the number of leaf type change diff nodes.
9445size_t
9447{return priv_->num_leaf_changes;}
9448
9449/// Setter of the number of leaf type change diff nodes.
9450///
9451/// @param n the new number of leaf type change diff nodes.
9452void
9454{priv_->num_leaf_changes = n;}
9455
9456/// Getter of the number of leaf type change diff nodes that have been
9457/// filtered out.
9458///
9459/// @return the number of leaf type change diff nodes that have been
9460size_t
9462{return priv_->num_leaf_changes_filtered_out;}
9463
9464/// Setter of the number of leaf type change diff nodes that have been
9465/// filtered out.
9466///
9467/// @param n the new number of leaf type change diff nodes that have
9468/// been filtered out.
9469void
9471{priv_->num_leaf_changes_filtered_out = n;}
9472
9473/// Getter of the net number of leaf change diff nodes.
9474///
9475/// This is the difference between the total number of leaf change
9476/// diff nodes, and the number of the leaf change diff nodes that have
9477/// been filtered out.
9478///
9479/// A leaf change is either a type change, a function change or a
9480/// variable change.
9481size_t
9483{
9484 ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
9485 return num_leaf_changes() - num_leaf_changes_filtered_out();
9486}
9487
9488/// Getter for the number of leaf type change diff nodes.
9489///
9490/// @return the number of leaf type changes diff nodes.
9491size_t
9493{return priv_->num_leaf_type_changes;}
9494
9495/// Setter for the number of leaf type change diff nodes.
9496///
9497/// @param n the new number of leaf type change diff nodes.
9498void
9500{priv_->num_leaf_type_changes = n;}
9501
9502/// Getter for the number of filtered out leaf type change diff nodes.
9503///
9504/// @return the number of filtered out leaf type change diff nodes.
9505size_t
9507{return priv_->num_leaf_type_changes_filtered_out;}
9508
9509/// Setter for the number of filtered out leaf type change diff nodes.
9510/// @param n the new number of filtered out leaf type change diff nodes.
9511void
9513{priv_->num_leaf_type_changes_filtered_out = n;}
9514
9515/// Getter for the net number of leaf type change diff nodes.
9516///
9517/// This is the difference between the number of leaf type changes and
9518/// the number of filtered out leaf type changes.
9519///
9520/// @return the net number of leaf type change diff nodes.
9521size_t
9523{return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
9524
9525/// Getter for the number of leaf function change diff nodes.
9526///
9527/// @return the number of leaf function change diff nodes.
9528size_t
9530{return priv_->num_leaf_func_changes;}
9531
9532/// Setter for the number of leaf function change diff nodes.
9533///
9534/// @param n the new number of leaf function change diff nodes.
9535void
9537{priv_->num_leaf_func_changes = n;}
9538
9539/// Getter for the number of leaf function change diff nodes that were
9540/// filtered out.
9541///
9542/// @return the number of leaf function change diff nodes that were
9543/// filtered out.
9544size_t
9546{return priv_->num_leaf_func_changes_filtered_out;}
9547
9548/// Setter for the number of leaf function change diff nodes that were
9549/// filtered out.
9550///
9551/// @param n the new number of leaf function change diff nodes that
9552/// were filtered out.
9553void
9555{priv_->num_leaf_func_changes_filtered_out = n;}
9556
9557/// Getter for the net number of leaf function change diff nodes.
9558///
9559/// This is the difference between the number of leaf function change
9560/// diff nodes and the number of filtered out leaf function change
9561/// diff nodes.
9562///
9563/// @return the net number of leaf function change diff nodes.
9564size_t
9566{return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
9567
9568/// Getter for the number of leaf variable change diff nodes.
9569///
9570/// @return the number of leaf variable change diff nodes.
9571size_t
9573{return priv_->num_leaf_var_changes;}
9574
9575/// Setter for the number of leaf variable change diff nodes.
9576///
9577/// @param n the number of leaf variable change diff nodes.
9578void
9580{priv_->num_leaf_var_changes = n;}
9581
9582/// Getter of the number of added types that are unreachable from the
9583/// public interface of the ABI corpus.
9584///
9585/// Public interface means the set of defined and publicly exported
9586/// functions and variables of the ABI corpus.
9587///
9588/// @return the number of added types that are unreachable from the
9589/// public interface of the ABI corpus.
9590size_t
9592{return priv_->num_added_unreachable_types;}
9593
9594/// Setter of the number of added types that are unreachable from the
9595/// public interface (global functions or variables) of the ABI
9596/// corpus.
9597///
9598/// Public interface means the set of defined and publicly exported
9599/// functions and variables of the ABI corpus.
9600///
9601/// @param n the new number of added types that are unreachable from
9602/// the public interface of the ABI corpus.
9603void
9605{priv_->num_added_unreachable_types = n;}
9606
9607/// Getter of the number of added types that are unreachable from
9608/// public interfaces and that are filtered out by suppression
9609/// specifications.
9610///
9611/// @return the number of added types that are unreachable from public
9612/// interfaces and that are filtered out by suppression
9613/// specifications.
9614size_t
9616{return priv_->num_added_unreachable_types_filtered_out;}
9617
9618/// Setter of the number of added types that are unreachable from
9619/// public interfaces and that are filtered out by suppression
9620/// specifications.
9621///
9622/// @param n the new number of added types that are unreachable from
9623/// public interfaces and that are filtered out by suppression
9624/// specifications.
9625void
9627{priv_->num_added_unreachable_types_filtered_out = n;}
9628
9629/// Getter of the number of added types that are unreachable from
9630/// public interfaces and that are *NOT* filtered out by suppression
9631/// specifications.
9632///
9633/// @return the number of added types that are unreachable from public
9634/// interfaces and that are *NOT* filtered out by suppression
9635/// specifications.
9636size_t
9638{
9639 ABG_ASSERT(num_added_unreachable_types()
9640 >=
9641 num_added_unreachable_types_filtered_out());
9642
9643 return (num_added_unreachable_types()
9644 -
9645 num_added_unreachable_types_filtered_out());
9646}
9647
9648/// Getter of the number of removed types that are unreachable from
9649/// the public interface of the ABI corpus.
9650///
9651/// Public interface means the set of defined and publicly exported
9652/// functions and variables of the ABI corpus.
9653///
9654/// @return the number of removed types that are unreachable from
9655/// the public interface of the ABI corpus.
9656size_t
9658{return priv_->num_removed_unreachable_types;}
9659
9660/// Setter of the number of removed types that are unreachable from
9661/// the public interface of the ABI corpus.
9662///
9663/// Public interface means the set of defined and publicly exported
9664/// functions and variables of the ABI corpus.
9665///
9666///@param n the new number of removed types that are unreachable from
9667/// the public interface of the ABI corpus.
9668void
9670{priv_->num_removed_unreachable_types = n;}
9671
9672/// Getter of the number of removed types that are not reachable from
9673/// public interfaces and that have been filtered out by suppression
9674/// specifications.
9675///
9676/// @return the number of removed types that are not reachable from
9677/// public interfaces and that have been filtered out by suppression
9678/// specifications.
9679size_t
9681{return priv_->num_removed_unreachable_types_filtered_out;}
9682
9683/// Setter of the number of removed types that are not reachable from
9684/// public interfaces and that have been filtered out by suppression
9685/// specifications.
9686///
9687/// @param n the new number of removed types that are not reachable
9688/// from public interfaces and that have been filtered out by
9689/// suppression specifications.
9690void
9692{priv_->num_removed_unreachable_types_filtered_out = n;}
9693
9694/// Getter of the number of removed types that are not reachable from
9695/// public interfaces and that have *NOT* been filtered out by
9696/// suppression specifications.
9697///
9698/// @return the number of removed types that are not reachable from
9699/// public interfaces and that have *NOT* been filtered out by
9700/// suppression specifications.
9701size_t
9703{
9704 ABG_ASSERT(num_removed_unreachable_types()
9705 >=
9706 num_removed_unreachable_types_filtered_out());
9707
9708 return (num_removed_unreachable_types()
9709 -
9710 num_removed_unreachable_types_filtered_out());
9711}
9712
9713/// Getter of the number of changed types that are unreachable from
9714/// the public interface of the ABI corpus.
9715///
9716/// Public interface means the set of defined and publicly exported
9717/// functions and variables of the ABI corpus.
9718///
9719/// @return the number of changed types that are unreachable from the
9720/// public interface of the ABI corpus.
9721size_t
9723{return priv_->num_changed_unreachable_types;}
9724
9725/// Setter of the number of changed types that are unreachable from
9726/// the public interface of the ABI corpus.
9727///
9728/// Public interface means the set of defined and publicly exported
9729/// functions and variables of the ABI corpus.
9730///
9731///@param n the new number of changed types that are unreachable from
9732/// the public interface of the ABI corpus.
9733void
9735{priv_->num_changed_unreachable_types = n;}
9736
9737/// Getter of the number of changed types that are unreachable from
9738/// public interfaces and that have been filtered out by suppression
9739/// specifications.
9740///
9741/// @return the number of changed types that are unreachable from
9742/// public interfaces and that have been filtered out by suppression
9743/// specifications.
9744size_t
9746{return priv_->num_changed_unreachable_types_filtered_out;}
9747
9748/// Setter of the number of changed types that are unreachable from
9749/// public interfaces and that have been filtered out by suppression
9750/// specifications.
9751///
9752/// @param n the new number of changed types that are unreachable from
9753/// public interfaces and that have been filtered out by suppression
9754/// specifications.
9755void
9757{priv_->num_changed_unreachable_types_filtered_out = n;}
9758
9759/// Getter of the number of changed types that are unreachable from
9760/// public interfaces and that have *NOT* been filtered out by
9761/// suppression specifications.
9762///
9763/// @return the number of changed types that are unreachable from
9764/// public interfaces and that have *NOT* been filtered out by
9765/// suppression specifications.
9766size_t
9768{
9769 ABG_ASSERT(num_changed_unreachable_types()
9770 >=
9771 num_changed_unreachable_types_filtered_out());
9772
9773 return (num_changed_unreachable_types()
9774 -
9775 num_changed_unreachable_types_filtered_out());
9776}
9777
9778/// Getter for the number of leaf variable changes diff nodes that
9779/// have been filtered out.
9780///
9781/// @return the number of leaf variable changes diff nodes that have
9782/// been filtered out.
9783size_t
9785{return priv_->num_leaf_var_changes_filtered_out;}
9786
9787/// Setter for the number of leaf variable changes diff nodes that
9788/// have been filtered out.
9789///
9790/// @param n the number of leaf variable changes diff nodes that have
9791/// been filtered out.
9792void
9794{priv_->num_leaf_var_changes_filtered_out = n;}
9795
9796/// Getter for the net number of leaf variable change diff nodes.
9797///
9798/// This the difference between the number of leaf variable change
9799/// diff nodes and the number of filtered out leaf variable change
9800/// diff nodes.
9801///
9802/// @return the net number of leaf variable change diff nodes.
9803size_t
9805{return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9806
9807
9808// <corpus_diff stuff>
9809
9810/// Getter of the context associated with this corpus.
9811///
9812/// @return a smart pointer to the context associate with the corpus.
9815{return ctxt_.lock();}
9816
9817/// Tests if the lookup tables are empty.
9818///
9819/// @return true if the lookup tables are empty, false otherwise.
9820bool
9822{
9823 return (deleted_fns_.empty()
9824 && added_fns_.empty()
9825 && changed_fns_map_.empty()
9826 && deleted_vars_.empty()
9827 && added_vars_.empty()
9828 && changed_vars_map_.empty());
9829}
9830
9831/// Clear the lookup tables useful for reporting an enum_diff.
9832void
9834{
9835 deleted_fns_.clear();
9836 added_fns_.clear();
9837 changed_fns_map_.clear();
9838 deleted_vars_.clear();
9839 added_vars_.clear();
9840 changed_vars_map_.clear();
9841}
9842
9843/// If the lookup tables are not yet built, walk the differences and
9844/// fill the lookup tables.
9845void
9847{
9848 if (!lookup_tables_empty())
9849 return;
9850
9851 diff_context_sptr ctxt = get_context();
9852
9853 {
9854 edit_script& e = fns_edit_script_;
9855
9856 for (vector<deletion>::const_iterator it = e.deletions().begin();
9857 it != e.deletions().end();
9858 ++it)
9859 {
9860 unsigned i = it->index();
9861 ABG_ASSERT(i < first_->get_functions().size());
9862
9863 const function_decl* deleted_fn = first_->get_functions()[i];
9864 string n = get_function_id_or_pretty_representation(deleted_fn);
9865 ABG_ASSERT(!n.empty());
9866 // The below is commented out because there can be several
9867 // functions with the same ID in the corpus. So several
9868 // functions with the same ID can be deleted.
9869 // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9870 deleted_fns_[n] = deleted_fn;
9871 }
9872
9873 for (vector<insertion>::const_iterator it = e.insertions().begin();
9874 it != e.insertions().end();
9875 ++it)
9876 {
9877 for (vector<unsigned>::const_iterator iit =
9878 it->inserted_indexes().begin();
9879 iit != it->inserted_indexes().end();
9880 ++iit)
9881 {
9882 unsigned i = *iit;
9883 const function_decl* added_fn = second_->get_functions()[i];
9884 string n = get_function_id_or_pretty_representation(added_fn);
9885 ABG_ASSERT(!n.empty());
9886 // The below is commented out because there can be several
9887 // functions with the same ID in the corpus. So several
9888 // functions with the same ID can be added.
9889 // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9890 string_function_ptr_map::const_iterator j =
9891 deleted_fns_.find(n);
9892 if (j != deleted_fns_.end())
9893 {
9894 function_decl_sptr f(const_cast<function_decl*>(j->second),
9895 noop_deleter());
9896 function_decl_sptr s(const_cast<function_decl*>(added_fn),
9897 noop_deleter());
9898 function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9899 if (*j->second != *added_fn)
9900 changed_fns_map_[j->first] = d;
9901 deleted_fns_.erase(j);
9902 }
9903 else
9904 added_fns_[n] = added_fn;
9905 }
9906 }
9907 sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9908
9909 // Now walk the allegedly deleted functions; check if their
9910 // underlying symbols are deleted as well; otherwise, consider
9911 // that the function in question hasn't been deleted.
9912
9913 vector<string> to_delete;
9914 for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9915 i != deleted_fns_.end();
9916 ++i)
9917 if (second_->lookup_function_symbol(*i->second->get_symbol()))
9918 to_delete.push_back(i->first);
9919
9920 for (vector<string>::const_iterator i = to_delete.begin();
9921 i != to_delete.end();
9922 ++i)
9923 deleted_fns_.erase(*i);
9924
9925 // Do something similar for added functions.
9926
9927 to_delete.clear();
9928 for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9929 i != added_fns_.end();
9930 ++i)
9931 {
9932 if (first_->lookup_function_symbol(*i->second->get_symbol()))
9933 to_delete.push_back(i->first);
9934 else if (! i->second->get_symbol()->get_version().is_empty()
9935 && i->second->get_symbol()->get_version().is_default())
9936 // We are looking for a symbol that has a default version,
9937 // and which seems to be newly added. Let's see if the same
9938 // symbol with *no* version was already present in the
9939 // former corpus. If yes, then the symbol shouldn't be
9940 // considered as 'added'.
9941 {
9942 elf_symbol::version empty_version;
9943 if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
9944 empty_version))
9945 to_delete.push_back(i->first);
9946 }
9947 }
9948
9949 for (vector<string>::const_iterator i = to_delete.begin();
9950 i != to_delete.end();
9951 ++i)
9952 added_fns_.erase(*i);
9953 }
9954
9955 {
9956 edit_script& e = vars_edit_script_;
9957
9958 for (vector<deletion>::const_iterator it = e.deletions().begin();
9959 it != e.deletions().end();
9960 ++it)
9961 {
9962 unsigned i = it->index();
9963 ABG_ASSERT(i < first_->get_variables().size());
9964
9965 const var_decl_sptr deleted_var = first_->get_variables()[i];
9966 string n = deleted_var->get_id();
9967 ABG_ASSERT(!n.empty());
9968 ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
9969 deleted_vars_[n] = deleted_var;
9970 }
9971
9972 for (vector<insertion>::const_iterator it = e.insertions().begin();
9973 it != e.insertions().end();
9974 ++it)
9975 {
9976 for (vector<unsigned>::const_iterator iit =
9977 it->inserted_indexes().begin();
9978 iit != it->inserted_indexes().end();
9979 ++iit)
9980 {
9981 unsigned i = *iit;
9982 const var_decl_sptr added_var = second_->get_variables()[i];
9983 string n = added_var->get_id();
9984 ABG_ASSERT(!n.empty());
9985 {
9986 string_var_ptr_map::const_iterator k = added_vars_.find(n);
9987 if ( k != added_vars_.end())
9988 {
9989 ABG_ASSERT(is_member_decl(k->second)
9990 && get_member_is_static(k->second));
9991 continue;
9992 }
9993 }
9994 string_var_ptr_map::const_iterator j =
9995 deleted_vars_.find(n);
9996 if (j != deleted_vars_.end())
9997 {
9998 if (*j->second != *added_var)
9999 {
10000 var_decl_sptr f = j->second;
10001 var_decl_sptr s = added_var;
10002 changed_vars_map_[n] = compute_diff(f, s, ctxt);
10003 }
10004 deleted_vars_.erase(j);
10005 }
10006 else
10007 added_vars_[n] = added_var;
10008 }
10009 }
10010 sort_string_var_diff_sptr_map(changed_vars_map_,
10011 sorted_changed_vars_);
10012
10013 // Now walk the allegedly deleted variables; check if their
10014 // underlying symbols are deleted as well; otherwise consider
10015 // that the variable in question hasn't been deleted.
10016
10017 vector<string> to_delete;
10018 for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
10019 i != deleted_vars_.end();
10020 ++i)
10021 if (second_->lookup_variable_symbol(*i->second->get_symbol()))
10022 to_delete.push_back(i->first);
10023
10024 for (vector<string>::const_iterator i = to_delete.begin();
10025 i != to_delete.end();
10026 ++i)
10027 deleted_vars_.erase(*i);
10028
10029 // Do something similar for added variables.
10030
10031 to_delete.clear();
10032 for (string_var_ptr_map::const_iterator i = added_vars_.begin();
10033 i != added_vars_.end();
10034 ++i)
10035 if (first_->lookup_variable_symbol(*i->second->get_symbol()))
10036 to_delete.push_back(i->first);
10037 else if (! i->second->get_symbol()->get_version().is_empty()
10038 && i->second->get_symbol()->get_version().is_default())
10039 // We are looking for a symbol that has a default version,
10040 // and which seems to be newly added. Let's see if the same
10041 // symbol with *no* version was already present in the
10042 // former corpus. If yes, then the symbol shouldn't be
10043 // considered as 'added'.
10044 {
10045 elf_symbol::version empty_version;
10046 if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
10047 empty_version))
10048 to_delete.push_back(i->first);
10049 }
10050
10051 for (vector<string>::const_iterator i = to_delete.begin();
10052 i != to_delete.end();
10053 ++i)
10054 added_vars_.erase(*i);
10055 }
10056
10057 // Massage the edit script for added/removed function symbols that
10058 // were not referenced by any debug info and turn them into maps of
10059 // {symbol_name, symbol}.
10060 {
10061 edit_script& e = unrefed_fn_syms_edit_script_;
10062 for (vector<deletion>::const_iterator it = e.deletions().begin();
10063 it != e.deletions().end();
10064 ++it)
10065 {
10066 unsigned i = it->index();
10067 ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
10068 elf_symbol_sptr deleted_sym =
10069 first_->get_unreferenced_function_symbols()[i];
10070 if (!second_->lookup_function_symbol(*deleted_sym))
10071 deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
10072 }
10073
10074 for (vector<insertion>::const_iterator it = e.insertions().begin();
10075 it != e.insertions().end();
10076 ++it)
10077 {
10078 for (vector<unsigned>::const_iterator iit =
10079 it->inserted_indexes().begin();
10080 iit != it->inserted_indexes().end();
10081 ++iit)
10082 {
10083 unsigned i = *iit;
10084 ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
10085 elf_symbol_sptr added_sym =
10086 second_->get_unreferenced_function_symbols()[i];
10087 if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
10088 == deleted_unrefed_fn_syms_.end()))
10089 {
10090 if (!first_->lookup_function_symbol(*added_sym))
10091 {
10092 bool do_add = true;
10093 if (! added_sym->get_version().is_empty()
10094 && added_sym->get_version().is_default())
10095 {
10096 // So added_seem has a default version. If
10097 // the former corpus had a symbol with the
10098 // same name as added_sym but with *no*
10099 // version, then added_sym shouldn't be
10100 // considered as a newly added symbol.
10101 elf_symbol::version empty_version;
10102 if (first_->lookup_function_symbol(added_sym->get_name(),
10103 empty_version))
10104 do_add = false;
10105 }
10106
10107 if (do_add)
10108 added_unrefed_fn_syms_[added_sym->get_id_string()] =
10109 added_sym;
10110 }
10111 }
10112 else
10113 deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
10114 }
10115 }
10116 }
10117
10118 // Massage the edit script for added/removed variable symbols that
10119 // were not referenced by any debug info and turn them into maps of
10120 // {symbol_name, symbol}.
10121 {
10122 edit_script& e = unrefed_var_syms_edit_script_;
10123 for (vector<deletion>::const_iterator it = e.deletions().begin();
10124 it != e.deletions().end();
10125 ++it)
10126 {
10127 unsigned i = it->index();
10128 ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
10129 elf_symbol_sptr deleted_sym =
10130 first_->get_unreferenced_variable_symbols()[i];
10131 if (!second_->lookup_variable_symbol(*deleted_sym))
10132 deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
10133 }
10134
10135 for (vector<insertion>::const_iterator it = e.insertions().begin();
10136 it != e.insertions().end();
10137 ++it)
10138 {
10139 for (vector<unsigned>::const_iterator iit =
10140 it->inserted_indexes().begin();
10141 iit != it->inserted_indexes().end();
10142 ++iit)
10143 {
10144 unsigned i = *iit;
10145 ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
10146 elf_symbol_sptr added_sym =
10147 second_->get_unreferenced_variable_symbols()[i];
10148 if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
10149 == deleted_unrefed_var_syms_.end())
10150 {
10151 if (!first_->lookup_variable_symbol(*added_sym))
10152 {
10153 bool do_add = true;
10154 if (! added_sym->get_version().is_empty()
10155 && added_sym->get_version().is_default())
10156 {
10157 // So added_seem has a default version. If
10158 // the former corpus had a symbol with the
10159 // same name as added_sym but with *no*
10160 // version, then added_sym shouldn't be
10161 // considered as a newly added symbol.
10162 elf_symbol::version empty_version;
10163 if (first_->lookup_variable_symbol(added_sym->get_name(),
10164 empty_version))
10165 do_add = false;
10166 }
10167
10168 if (do_add)
10169 added_unrefed_var_syms_[added_sym->get_id_string()] =
10170 added_sym;
10171 }
10172 }
10173 else
10174 deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
10175 }
10176 }
10177 }
10178
10179 // Handle the unreachable_types_edit_script_
10180 {
10181 edit_script& e = unreachable_types_edit_script_;
10182
10183 // Populate the map of deleted unreachable types from the
10184 // deletions of the edit script.
10185 for (vector<deletion>::const_iterator it = e.deletions().begin();
10186 it != e.deletions().end();
10187 ++it)
10188 {
10189 unsigned i = it->index();
10190 type_base_sptr t
10191 (first_->get_types_not_reachable_from_public_interfaces()[i]);
10192
10193 if (!is_user_defined_type(t))
10194 continue;
10195
10196 string repr =
10197 abigail::ir::get_pretty_representation(t, /*internal=*/false);
10198 deleted_unreachable_types_[repr] = t;
10199 }
10200
10201 // Populate the map of added and change unreachable types from the
10202 // insertions of the edit script.
10203 for (vector<insertion>::const_iterator it = e.insertions().begin();
10204 it != e.insertions().end();
10205 ++it)
10206 {
10207 for (vector<unsigned>::const_iterator iit =
10208 it->inserted_indexes().begin();
10209 iit != it->inserted_indexes().end();
10210 ++iit)
10211 {
10212 unsigned i = *iit;
10213 type_base_sptr t
10214 (second_->get_types_not_reachable_from_public_interfaces()[i]);
10215
10216 if (!is_user_defined_type(t))
10217 continue;
10218
10219 string repr =
10220 abigail::ir::get_pretty_representation(t, /*internal=*/false);
10221
10222 // Let's see if the inserted type we are looking at was
10223 // reported as deleted as well.
10224 //
10225 // If it's been deleted and a different version of it has
10226 // now been added, it means it's been *changed*. In that
10227 // case we'll compute the diff of that change and store it
10228 // in the map of changed unreachable types.
10229 //
10230 // Otherwise, it means the type's been added so we'll add
10231 // it to the set of added unreachable types.
10232
10233 string_type_base_sptr_map::const_iterator j =
10234 deleted_unreachable_types_.find(repr);
10235 if (j != deleted_unreachable_types_.end())
10236 {
10237 // So there was another type of the same pretty
10238 // representation which was reported as deleted.
10239 // Let's see if they are different or not ...
10240 decl_base_sptr old_type = is_decl(j->second);
10241 decl_base_sptr new_type = is_decl(t);
10242 if (old_type != new_type)
10243 {
10244 // The previously added type is different from this
10245 // one that is added. That means the initial type
10246 // was changed. Let's compute its diff and store it
10247 // as a changed type.
10248 diff_sptr d = compute_diff(old_type, new_type, ctxt);
10249 ABG_ASSERT(d->has_changes());
10250 changed_unreachable_types_[repr]= d;
10251 }
10252
10253 // In any case, the type was both deleted and added,
10254 // so we cannot have it marked as being deleted. So
10255 // let's remove it from the deleted types.
10256 deleted_unreachable_types_.erase(j);
10257 }
10258 else
10259 // The type wasn't previously reported as deleted, so
10260 // it's really added.
10261 added_unreachable_types_[repr] = t;
10262 }
10263 }
10264
10265 // Handle anonymous enums that got changed. An anonymous enum is
10266 // designated by its flat textual representation. So a change to
10267 // any of its enumerators results in a different enum. That is
10268 // represented by a deletion of the previous anonymous enum, and
10269 // the addition of a new one. For the user however, it's the same
10270 // enum that changed. Let's massage this "added/removed" pattern
10271 // to show what the user expects, namely, a changed anonymous
10272 // enum.
10273 {
10274 std::set<type_base_sptr> deleted_anon_types;
10275 std::set<type_base_sptr> added_anon_types;
10276
10277 for (auto entry : deleted_unreachable_types_)
10278 {
10279 if ((is_enum_type(entry.second)
10280 && is_enum_type(entry.second)->get_is_anonymous())
10281 || (is_class_or_union_type(entry.second)
10282 && is_class_or_union_type(entry.second)->get_is_anonymous()))
10283 deleted_anon_types.insert(entry.second);
10284 }
10285
10286
10287 for (auto entry : added_unreachable_types_)
10288 if ((is_enum_type(entry.second)
10289 && is_enum_type(entry.second)->get_is_anonymous())
10290 || (is_class_or_union_type(entry.second)
10291 && is_class_or_union_type(entry.second)->get_is_anonymous()))
10292 added_anon_types.insert(entry.second);
10293
10294 string_type_base_sptr_map added_anon_types_to_erase;
10295 string_type_base_sptr_map removed_anon_types_to_erase;
10296 enum_type_decl_sptr deleted_enum;
10297 class_or_union_sptr deleted_class;
10298
10299 // Look for deleted anonymous types (enums, unions, structs &
10300 // classes) which have enumerators or data members present in an
10301 // added anonymous type ...
10302 for (auto deleted: deleted_anon_types)
10303 {
10304 deleted_enum = is_enum_type(deleted);
10305 deleted_class = is_class_or_union_type(deleted);
10306
10307 // For enums, look for any enumerator of 'deleted_enum' that
10308 // is also present in an added anonymous enum.
10309 if (deleted_enum)
10310 {
10311 for (auto enr : deleted_enum->get_enumerators())
10312 {
10313 bool this_enum_got_changed = false;
10314 for (auto t : added_anon_types)
10315 {
10316 if (enum_type_decl_sptr added_enum = is_enum_type(t))
10317 if (is_enumerator_present_in_enum(enr, *added_enum))
10318 {
10319 // So the enumerator 'enr' from the
10320 // 'deleted_enum' enum is also present in the
10321 // 'added_enum' enum so we assume that
10322 // 'deleted_enum' and 'added_enum' are the same
10323 // enum that got changed. Let's represent it
10324 // using a diff node.
10325 diff_sptr d = compute_diff(deleted_enum,
10326 added_enum, ctxt);
10327 ABG_ASSERT(d->has_changes());
10328 string repr =
10330 /*internal=*/false);
10331 changed_unreachable_types_[repr]= d;
10332 this_enum_got_changed = true;
10333 string r1 =
10335 /*internal=*/false);
10336 string r2 =
10338 /*internal=*/false);
10339 removed_anon_types_to_erase[r1] = deleted_enum;
10340 added_anon_types_to_erase[r2] = added_enum;
10341 break;
10342 }
10343 }
10344 if (this_enum_got_changed)
10345 break;
10346 }
10347 }
10348 else if (deleted_class)
10349 {
10350 // For unions, structs & classes, look for any data
10351 // member of 'deleted_class' that is also present in an
10352 // added anonymous class.
10353 for (auto dm : deleted_class->get_data_members())
10354 {
10355 bool this_class_got_changed = false;
10356 for (auto klass : added_anon_types)
10357 {
10358 if (class_or_union_sptr added_class =
10360 if (class_or_union_types_of_same_kind(deleted_class,
10361 added_class)
10362 && lookup_data_member(added_class, dm))
10363 {
10364 // So the data member 'dm' from the
10365 // 'deleted_class' class is also present in
10366 // the 'added_class' class so we assume that
10367 // 'deleted_class' and 'added_class' are the
10368 // same anonymous class that got changed.
10369 // Let's represent it using a diff node.
10370 diff_sptr d = compute_diff(is_type(deleted_class),
10371 is_type(added_class),
10372 ctxt);
10373 ABG_ASSERT(d->has_changes());
10374 string repr =
10376 /*internal=*/false);
10377 changed_unreachable_types_[repr]= d;
10378 this_class_got_changed = true;
10379 string r1 =
10381 /*internal=*/false);
10382 string r2 =
10384 /*internal=*/false);
10385 removed_anon_types_to_erase[r1] = deleted_class;
10386 added_anon_types_to_erase[r2] = added_class;
10387 break;
10388 }
10389 }
10390 if (this_class_got_changed)
10391 break;
10392 }
10393 }
10394 }
10395
10396 // Now remove the added/removed anonymous types from their maps,
10397 // as they are now represented as a changed type, not an added
10398 // and removed anonymous type.
10399 for (auto entry : added_anon_types_to_erase)
10400 added_unreachable_types_.erase(entry.first);
10401
10402 for (auto entry : removed_anon_types_to_erase)
10403 deleted_unreachable_types_.erase(entry.first);
10404 }
10405 }
10406}
10407
10408/// Test if a change reports about a given @ref function_decl that is
10409/// changed in a certain way is suppressed by a given suppression
10410/// specifiation
10411///
10412/// @param fn the @ref function_decl to consider.
10413///
10414/// @param suppr the suppression specification to consider.
10415///
10416/// @param k the kind of change that happened to @p fn.
10417///
10418/// @param ctxt the context of the current diff.
10419///
10420/// @return true iff the suppression specification @p suppr suppresses
10421/// change reports about function @p fn, if that function changes in
10422/// the way expressed by @p k.
10423static bool
10424function_is_suppressed(const function_decl* fn,
10425 const suppression_sptr suppr,
10427 const diff_context_sptr ctxt)
10428{
10430 if (!fn_suppr)
10431 return false;
10432 return fn_suppr->suppresses_function(fn, k, ctxt);
10433}
10434
10435/// Test if a change reports about a given @ref var_decl that is
10436/// changed in a certain way is suppressed by a given suppression
10437/// specifiation
10438///
10439/// @param fn the @ref var_decl to consider.
10440///
10441/// @param suppr the suppression specification to consider.
10442///
10443/// @param k the kind of change that happened to @p fn.
10444///
10445/// @param ctxt the context of the current diff.
10446///
10447/// @return true iff the suppression specification @p suppr suppresses
10448/// change reports about variable @p fn, if that variable changes in
10449/// the way expressed by @p k.
10450static bool
10451variable_is_suppressed(const var_decl_sptr& var,
10452 const suppression_sptr suppr,
10454 const diff_context_sptr ctxt)
10455{
10457 if (!var_suppr)
10458 return false;
10459 return var_suppr->suppresses_variable(var, k, ctxt);
10460}
10461
10462/// Apply suppression specifications for this corpus diff to the set
10463/// of added/removed functions/variables, as well as to types not
10464/// reachable from global functions/variables.
10465void
10467{
10468 diff_context_sptr ctxt = get_context();
10469
10470 const suppressions_type& suppressions = ctxt->suppressions();
10471 for (suppressions_type::const_iterator i = suppressions.begin();
10472 i != suppressions.end();
10473 ++i)
10474 {
10475 // Added/Deleted functions.
10477 {
10478 // Added functions
10479 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10480 e != added_fns_.end();
10481 ++e)
10482 if (function_is_suppressed(e->second, fn_suppr,
10484 ctxt))
10485 suppressed_added_fns_[e->first] = e->second;
10486
10487 // Deleted functions.
10488 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10489 e != deleted_fns_.end();
10490 ++e)
10491 if (function_is_suppressed(e->second, fn_suppr,
10493 ctxt))
10494 suppressed_deleted_fns_[e->first] = e->second;
10495
10496 // Added function symbols not referenced by any debug info
10497 for (string_elf_symbol_map::const_iterator e =
10498 added_unrefed_fn_syms_.begin();
10499 e != added_unrefed_fn_syms_.end();
10500 ++e)
10501 if (fn_suppr->suppresses_function_symbol(e->second,
10503 ctxt))
10504 suppressed_added_unrefed_fn_syms_[e->first] = e->second;
10505
10506 // Removed function symbols not referenced by any debug info
10507 for (string_elf_symbol_map::const_iterator e =
10508 deleted_unrefed_fn_syms_.begin();
10509 e != deleted_unrefed_fn_syms_.end();
10510 ++e)
10511 if (fn_suppr->suppresses_function_symbol(e->second,
10513 ctxt))
10514 suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
10515 }
10516 // Added/Delete virtual member functions changes that might be
10517 // suppressed by a type_suppression that matches the enclosing
10518 // class of the virtual member function.
10519 else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
10520 {
10521 // Added virtual functions
10522 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10523 e != added_fns_.end();
10524 ++e)
10525 if (is_member_function(e->second)
10526 && get_member_function_is_virtual(e->second))
10527 {
10528 const function_decl *f = e->second;
10529 class_decl_sptr c =
10530 is_class_type(is_method_type(f->get_type())->get_class_type());
10531 ABG_ASSERT(c);
10532 if (type_suppr->suppresses_type(c, ctxt))
10533 suppressed_added_fns_[e->first] = e->second;
10534 }
10535 // Deleted virtual functions
10536 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10537 e != deleted_fns_.end();
10538 ++e)
10539 if (is_member_function(e->second)
10540 && get_member_function_is_virtual(e->second))
10541 {
10542 const function_decl *f = e->second;
10543 class_decl_sptr c =
10544 is_class_type(is_method_type(f->get_type())->get_class_type());
10545 ABG_ASSERT(c);
10546 if (type_suppr->suppresses_type(c, ctxt))
10547 suppressed_deleted_fns_[e->first] = e->second;
10548 }
10549
10550 // Apply this type suppression to deleted types
10551 // non-reachable from a public interface.
10552 for (string_type_base_sptr_map::const_iterator e =
10553 deleted_unreachable_types_.begin();
10554 e != deleted_unreachable_types_.end();
10555 ++e)
10556 if (type_suppr->suppresses_type(e->second, ctxt))
10557 suppressed_deleted_unreachable_types_[e->first] = e->second;
10558
10559 // Apply this type suppression to added types
10560 // non-reachable from a public interface.
10561 for (string_type_base_sptr_map::const_iterator e =
10562 added_unreachable_types_.begin();
10563 e != added_unreachable_types_.end();
10564 ++e)
10565 if (type_suppr->suppresses_type(e->second, ctxt))
10566 suppressed_added_unreachable_types_[e->first] = e->second;
10567 }
10568 // Added/Deleted variables
10569 else if (variable_suppression_sptr var_suppr =
10571 {
10572 // Added variables
10573 for (string_var_ptr_map::const_iterator e = added_vars_.begin();
10574 e != added_vars_.end();
10575 ++e)
10576 if (variable_is_suppressed(e->second, var_suppr,
10578 ctxt))
10579 suppressed_added_vars_[e->first] = e->second;
10580
10581 //Deleted variables
10582 for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
10583 e != deleted_vars_.end();
10584 ++e)
10585 if (variable_is_suppressed(e->second, var_suppr,
10587 ctxt))
10588 suppressed_deleted_vars_[e->first] = e->second;
10589
10590 // Added variable symbols not referenced by any debug info
10591 for (string_elf_symbol_map::const_iterator e =
10592 added_unrefed_var_syms_.begin();
10593 e != added_unrefed_var_syms_.end();
10594 ++e)
10595 if (var_suppr->suppresses_variable_symbol(e->second,
10597 ctxt))
10598 suppressed_added_unrefed_var_syms_[e->first] = e->second;
10599
10600 // Removed variable symbols not referenced by any debug info
10601 for (string_elf_symbol_map::const_iterator e =
10602 deleted_unrefed_var_syms_.begin();
10603 e != deleted_unrefed_var_syms_.end();
10604 ++e)
10605 if (var_suppr->suppresses_variable_symbol(e->second,
10607 ctxt))
10608 suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
10609 }
10610 }
10611}
10612
10613/// Test if the change reports for a given deleted function have
10614/// been deleted.
10615///
10616/// @param fn the function to consider.
10617///
10618/// @return true iff the change reports for a give given deleted
10619/// function have been deleted.
10620bool
10622{
10623 if (!fn)
10624 return false;
10625
10626 string_function_ptr_map::const_iterator i =
10627 suppressed_deleted_fns_.find(fn->get_id());
10628
10629 return (i != suppressed_deleted_fns_.end());
10630}
10631
10632/// Test if an added type that is unreachable from public interface
10633/// has been suppressed by a suppression specification.
10634///
10635/// @param t the added unreachable type to be considered.
10636///
10637/// @return true iff @p t has been suppressed by a suppression
10638/// specification.
10639bool
10641{
10642 if (!t)
10643 return false;
10644
10645 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10646 string_type_base_sptr_map::const_iterator i =
10647 suppressed_added_unreachable_types_.find(repr);
10648 if (i == suppressed_added_unreachable_types_.end())
10649 return false;
10650
10651 return true;
10652}
10653
10654/// Test if a deleted type that is unreachable from public interface
10655/// has been suppressed by a suppression specification.
10656///
10657/// @param t the deleted unreachable type to be considered.
10658///
10659/// @return true iff @p t has been suppressed by a suppression
10660/// specification.
10661bool
10663{
10664 if (!t)
10665 return false;
10666
10667 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10668 string_type_base_sptr_map::const_iterator i =
10669 suppressed_deleted_unreachable_types_.find(repr);
10670 if (i == suppressed_deleted_unreachable_types_.end())
10671 return false;
10672
10673 return true;
10674}
10675
10676/// Test if the change reports for a give given added function has
10677/// been deleted.
10678///
10679/// @param fn the function to consider.
10680///
10681/// @return true iff the change reports for a give given added
10682/// function has been deleted.
10683bool
10685{
10686 if (!fn)
10687 return false;
10688
10689 string_function_ptr_map::const_iterator i =
10690 suppressed_added_fns_.find(fn->get_id());
10691
10692 return (i != suppressed_added_fns_.end());
10693}
10694
10695/// Test if the change reports for a give given deleted variable has
10696/// been deleted.
10697///
10698/// @param var the variable to consider.
10699///
10700/// @return true iff the change reports for a give given deleted
10701/// variable has been deleted.
10702bool
10704{
10705 if (!var)
10706 return false;
10707
10708 string_var_ptr_map::const_iterator i =
10709 suppressed_deleted_vars_.find(var->get_id());
10710
10711 return (i != suppressed_deleted_vars_.end());
10712}
10713
10714/// Test if the change reports for a given added variable have been
10715/// suppressed.
10716///
10717/// @param var the variable to consider.
10718///
10719/// @return true iff the change reports for a given deleted
10720/// variable has been deleted.
10721bool
10723{
10724 if (!var)
10725 return false;
10726
10727 string_var_ptr_map::const_iterator i =
10728 suppressed_added_vars_.find(var->get_id());
10729
10730 return (i != suppressed_added_vars_.end());
10731}
10732
10733/// Test if the change reports for a given deleted function symbol
10734/// (that is not referenced by any debug info) has been suppressed.
10735///
10736/// @param var the function to consider.
10737///
10738/// @return true iff the change reports for a given deleted function
10739/// symbol has been suppressed.
10740bool
10742{
10743 if (!s)
10744 return false;
10745
10746 string_elf_symbol_map::const_iterator i =
10747 suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10748
10749 return (i != suppressed_deleted_unrefed_fn_syms_.end());
10750}
10751
10752/// Test if the change reports for a given added function symbol
10753/// (that is not referenced by any debug info) has been suppressed.
10754///
10755/// @param var the function to consider.
10756///
10757/// @return true iff the change reports for a given added function
10758/// symbol has been suppressed.
10759bool
10761{
10762 if (!s)
10763 return false;
10764
10765 string_elf_symbol_map::const_iterator i =
10766 suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10767
10768 return (i != suppressed_added_unrefed_fn_syms_.end());
10769}
10770
10771/// Test if the change reports for a given deleted variable symbol
10772/// (that is not referenced by any debug info) has been suppressed.
10773///
10774/// @param var the variable to consider.
10775///
10776/// @return true iff the change reports for a given deleted variable
10777/// symbol has been suppressed.
10778bool
10780{
10781 if (!s)
10782 return false;
10783
10784 string_elf_symbol_map::const_iterator i =
10785 suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10786
10787 return (i != suppressed_deleted_unrefed_var_syms_.end());
10788}
10789
10790/// Test if the change reports for a given added variable symbol
10791/// (that is not referenced by any debug info) has been suppressed.
10792///
10793/// @param var the variable to consider.
10794///
10795/// @return true iff the change reports for a given added variable
10796/// symbol has been suppressed.
10797bool
10799{
10800 if (!s)
10801 return false;
10802
10803 string_elf_symbol_map::const_iterator i =
10804 suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10805
10806 return (i != suppressed_added_unrefed_var_syms_.end());
10807}
10808
10809#ifdef do_count_diff_map_changes
10810#undef do_count_diff_map_changes
10811#endif
10812#define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10813 { \
10814 string_diff_ptr_map::const_iterator i; \
10815 for (i = diff_map.begin(); \
10816 i != diff_map.end(); \
10817 ++i) \
10818 { \
10819 if (const var_diff* d = is_var_diff(i->second)) \
10820 if (is_data_member(d->first_var())) \
10821 continue; \
10822 \
10823 if (i->second->has_local_changes()) \
10824 ++n_changes; \
10825 if (!i->second->get_canonical_diff()->to_be_reported()) \
10826 ++n_filtered; \
10827 } \
10828 }
10829
10830/// Count the number of leaf changes as well as the number of the
10831/// changes that have been filtered out.
10832///
10833/// @param num_changes out parameter. This is set to the total number
10834/// of leaf changes.
10835///
10836/// @param num_filtered out parameter. This is set to the number of
10837/// leaf changes that have been filtered out.
10838void
10839corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10840{
10841 count_leaf_type_changes(num_changes, num_filtered);
10842
10843 // Now count the non-type changes.
10844 do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10845 num_changes, num_filtered);
10846 do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10847 num_changes, num_filtered);
10848}
10849
10850/// Count the number of leaf *type* changes as well as the number of
10851/// the leaf type changes that have been filtered out.
10852///
10853/// @param num_changes out parameter. This is set to the total number
10854/// of leaf type changes.
10855///
10856/// @param num_filtered out parameter. This is set to the number of
10857/// leaf type changes that have been filtered out.
10858void
10860 size_t &num_filtered)
10861{
10862 do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10863 num_changes, num_filtered);
10864 do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10865 num_changes, num_filtered);
10866 do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10867 num_changes, num_filtered);
10868 do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10869 num_changes, num_filtered);
10870 do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10871 num_changes, num_filtered);
10872 do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10873 num_changes, num_filtered);
10874 do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10875 num_changes, num_filtered);
10876 do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10877 num_changes, num_filtered);
10878 do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10879 num_changes, num_filtered);
10880}
10881
10882/// Count the number of types not reachable from the interface (i.e,
10883/// not reachable from global functions or variables).
10884///
10885/// @param num_added this is set to the number of added types not
10886/// reachable from the interface.
10887///
10888/// @param num_deleted this is set to the number of deleted types not
10889/// reachable from the interface.
10890///
10891/// @param num_changed this is set to the number of changed types not
10892/// reachable from the interface.
10893///
10894/// @param num_filtered_added this is set to the number of added types
10895/// not reachable from the interface and that have been filtered out
10896/// by suppression specifications.
10897///
10898/// @param num_filtered_deleted this is set to the number of deleted
10899/// types not reachable from the interface and that have been filtered
10900/// out by suppression specifications.
10901///
10902/// @param num_filtered_changed this is set to the number of changed
10903/// types not reachable from the interface and that have been filtered
10904/// out by suppression specifications.
10905void
10907 size_t &num_deleted,
10908 size_t &num_changed,
10909 size_t &num_filtered_added,
10910 size_t &num_filtered_deleted,
10911 size_t &num_filtered_changed)
10912{
10913 num_added = added_unreachable_types_.size();
10914 num_deleted = deleted_unreachable_types_.size();
10915 num_changed = changed_unreachable_types_.size();
10916 num_filtered_added = suppressed_added_unreachable_types_.size();
10917 num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10918
10919 for (vector<diff_sptr>::const_iterator i =
10922 ++i)
10923 if (!(*i)->to_be_reported())
10924 ++num_filtered_changed;
10925}
10926
10927/// Get the map of diff nodes representing changed unreachable types.
10928///
10929/// @return the map of diff nodes representing changed unreachable
10930/// types.
10933{return changed_unreachable_types_;}
10934
10935/// Get the sorted vector of diff nodes representing changed
10936/// unreachable types.
10937///
10938/// Upon the first invocation of this method, if the vector is empty,
10939/// this function gets the diff nodes representing changed
10940/// unreachable, sort them, and return the sorted vector.
10941///
10942/// @return the sorted vector of diff nodes representing changed
10943/// unreachable types.
10944const vector<diff_sptr>&
10946{
10947if (changed_unreachable_types_sorted_.empty())
10948 if (!changed_unreachable_types_.empty())
10949 sort_string_diff_sptr_map(changed_unreachable_types_,
10950 changed_unreachable_types_sorted_);
10951
10952 return changed_unreachable_types_sorted_;
10953}
10954
10955/// Compute the diff stats.
10956///
10957/// To know the number of functions that got filtered out, this
10958/// function applies the categorizing filters to the diff sub-trees of
10959/// each function changes diff, prior to calculating the stats.
10960///
10961/// @param num_removed the number of removed functions.
10962///
10963/// @param num_added the number of added functions.
10964///
10965/// @param num_changed the number of changed functions.
10966///
10967/// @param num_filtered_out the number of changed functions that are
10968/// got filtered out from the report
10969void
10971{
10972 stat.num_func_removed(deleted_fns_.size());
10973 stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
10974 stat.num_func_added(added_fns_.size());
10975 stat.num_added_func_filtered_out(suppressed_added_fns_.size());
10976 stat.num_func_changed(changed_fns_map_.size());
10977
10978 stat.num_vars_removed(deleted_vars_.size());
10979 stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
10980 stat.num_vars_added(added_vars_.size());
10981 stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
10982 stat.num_vars_changed(changed_vars_map_.size());
10983
10984 diff_context_sptr ctxt = get_context();
10985
10987 if (ctxt->perform_change_categorization())
10988 {
10989 if (get_context()->do_log())
10990 {
10991 std::cerr << "in apply_filters_and_compute_diff_stats:"
10992 << "applying filters to "
10993 << changed_fns_.size()
10994 << " changed fns ...\n";
10995 t.start();
10996 }
10997 // Walk the changed function diff nodes to apply the categorization
10998 // filters.
11000 for (function_decl_diff_sptrs_type::const_iterator i =
11001 changed_fns_.begin();
11002 i != changed_fns_.end();
11003 ++i)
11004 {
11005 diff_sptr diff = *i;
11006 ctxt->maybe_apply_filters(diff);
11007 }
11008
11009 if (get_context()->do_log())
11010 {
11011 t.stop();
11012 std::cerr << "in apply_filters_and_compute_diff_stats:"
11013 << "filters to changed fn applied!:" << t << "\n";
11014
11015 std::cerr << "in apply_filters_and_compute_diff_stats:"
11016 << "applying filters to "
11017 << sorted_changed_vars_.size()
11018 << " changed vars ...\n";
11019 t.start();
11020 }
11021
11022 // Walk the changed variable diff nodes to apply the categorization
11023 // filters.
11024 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11025 i != sorted_changed_vars_.end();
11026 ++i)
11027 {
11028 diff_sptr diff = *i;
11029 ctxt->maybe_apply_filters(diff);
11030 }
11031
11032 if (get_context()->do_log())
11033 {
11034 t.stop();
11035 std::cerr << "in apply_filters_and_compute_diff_stats:"
11036 << "filters to changed vars applied!:" << t << "\n";
11037
11038 std::cerr << "in apply_filters_and_compute_diff_stats:"
11039 << "applying filters to unreachable types ...\n";
11040 t.start();
11041 }
11042
11043 // walk the changed unreachable types to apply categorization
11044 // filters
11046 ctxt->maybe_apply_filters(diff);
11047
11048 for (auto& entry : changed_unreachable_types())
11049 ctxt->maybe_apply_filters(entry.second);
11050
11051 if (get_context()->do_log())
11052 {
11053 t.stop();
11054 std::cerr << "in apply_filters_and_compute_diff_stats:"
11055 << "filters to unreachable types applied!:" << t << "\n";
11056
11057 std::cerr << "in apply_filters_and_compute_diff_stats:"
11058 << "categorizing redundant changed sub nodes ...\n";
11059 t.start();
11060 }
11061
11062 categorize_redundant_changed_sub_nodes();
11063
11064 if (get_context()->do_log())
11065 {
11066 t.stop();
11067 std::cerr << "in apply_filters_and_compute_diff_stats:"
11068 << "redundant changed sub nodes categorized!:" << t << "\n";
11069
11070 std::cerr << "in apply_filters_and_compute_diff_stats:"
11071 << "count changed fns ...\n";
11072 t.start();
11073 }
11074 }
11075
11076 // Walk the changed function diff nodes to count the number of
11077 // filtered-out functions and the number of functions with virtual
11078 // offset changes.
11079 for (function_decl_diff_sptrs_type::const_iterator i =
11080 changed_fns_.begin();
11081 i != changed_fns_.end();
11082 ++i)
11083 {
11084 bool incompatible_change = false;
11085 if ((*i)->is_filtered_out())
11086 {
11088 (stat.num_changed_func_filtered_out() + 1);
11089
11090 if ((*i)->has_local_changes())
11093 }
11094
11095 // Now let's detect functions with incompatible changes.
11096 if (!(*i)->is_categorized_as_suppressed())
11097 {
11098 // Note that a filtered-out function diff (because of
11099 // redundancy) can still carry an incompatible change. In
11100 // that case, the diff will later be removed from the
11101 // account of filtered diff nodes.
11102 //
11103 // Also note that such a filtered-out function was *NOT*
11104 // suppressed by a user-provided suppression specification.
11105
11107 {
11110 incompatible_change = true;
11111 }
11112
11113 // Are any of the local changes of the function_diff harmful?
11114 // If yes, then set stat.num_func_with_local_harmful_changes()
11115 // and stat.num_var_with_local_harmful_changes().
11117 {
11120 incompatible_change = true;
11121 }
11122 }
11123
11124 if ((*i)->has_local_changes())
11126 (stat.num_leaf_func_changes() + 1);
11127
11128 if (incompatible_change)
11129 {
11130 incompatible_changed_fns_.push_back(*i);
11133
11134 if ((*i)->is_filtered_out())
11135 {
11136 // If the incompatible change was filtered-out (possibly
11137 // b/c of redundancy) consider it as not being filtered
11138 // out anymore.
11140 (stat.num_changed_func_filtered_out() - 1);
11141
11142 if ((*i)->has_local_changes())
11145 }
11146 }
11147 }
11148
11149 if (get_context()->do_log())
11150 {
11151 t.stop();
11152 std::cerr << "in apply_filters_and_compute_diff_stats:"
11153 << "changed fn counted!:" << t << "\n";
11154
11155 std::cerr << "in apply_filters_and_compute_diff_stats:"
11156 << "count changed vars ...\n";
11157 t.start();
11158 }
11159
11160 // Similarly to function diff nodes above, walk the changed
11161 // variables diff nodes to count the number of filtered-out,
11162 // suppressed and incompatible variable diff nodes.
11163 for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
11164 i != sorted_changed_vars_.end();
11165 ++i)
11166 {
11167 if ((*i)->is_filtered_out())
11168 {
11170 (stat.num_changed_vars_filtered_out() + 1);
11171
11172 if ((*i)->has_local_changes())
11175 }
11176
11177 if (!(*i)->is_categorized_as_suppressed())
11178 {
11180 {
11181 incompatible_changed_vars_.push_back(*i);
11186
11187 if ((*i)->is_filtered_out())
11188 {
11190 (stat.num_changed_vars_filtered_out() - 1);
11191
11192 if ((*i)->has_local_changes())
11195 }
11196 }
11197 }
11198
11199 if ((*i)->has_local_changes())
11201 (stat.num_leaf_var_changes() + 1);
11202 }
11203
11204 if (get_context()->do_log())
11205 {
11206 t.stop();
11207 std::cerr << "in apply_filters_and_compute_diff_stats:"
11208 << "changed vars counted!:" << t << "\n";
11209
11210 std::cerr << "in apply_filters_and_compute_diff_stats:"
11211 << "count leaf changed types ...\n";
11212 t.start();
11213 }
11214
11215 stat.num_func_syms_added(added_unrefed_fn_syms_.size());
11216 stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
11217 stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
11218 stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
11219 stat.num_var_syms_added(added_unrefed_var_syms_.size());
11220 stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
11221 stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
11222 stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
11223
11224 // Walk the general leaf type diff nodes to count them
11225 {
11226 size_t num_type_changes = 0, num_type_filtered = 0;
11227 count_leaf_type_changes(num_type_changes, num_type_filtered);
11228
11229 stat.num_leaf_type_changes(num_type_changes);
11230 stat.num_leaf_type_changes_filtered_out(num_type_filtered);
11231 }
11232
11233 if (get_context()->do_log())
11234 {
11235 t.stop();
11236 std::cerr << "in apply_filters_and_compute_diff_stats:"
11237 << "changed leaf types counted!:" << t << "\n";
11238
11239 std::cerr << "in apply_filters_and_compute_diff_stats:"
11240 << "count leaf changed artefacts ...\n";
11241 t.start();
11242 }
11243
11244 // Walk the general leaf artefacts diff nodes to count them
11245 {
11246 size_t num_changes = 0, num_filtered = 0;
11247 count_leaf_changes(num_changes, num_filtered);
11248
11249 stat.num_leaf_changes(num_changes);
11250 stat.num_leaf_changes_filtered_out(num_filtered);
11251 }
11252
11253 if (get_context()->do_log())
11254 {
11255 t.stop();
11256 std::cerr << "in apply_filters_and_compute_diff_stats:"
11257 << "changed leaf artefacts counted!:" << t << "\n";
11258
11259 std::cerr << "in apply_filters_and_compute_diff_stats:"
11260 << "count unreachable types ...\n";
11261 t.start();
11262 }
11263
11264 // Walk the unreachable types to count them
11265 {
11266 size_t num_added_unreachable_types = 0,
11267 num_changed_unreachable_types = 0,
11268 num_deleted_unreachable_types = 0,
11269 num_added_unreachable_types_filtered = 0,
11270 num_changed_unreachable_types_filtered = 0,
11271 num_deleted_unreachable_types_filtered = 0;
11272
11273 count_unreachable_types(num_added_unreachable_types,
11274 num_deleted_unreachable_types,
11275 num_changed_unreachable_types,
11276 num_added_unreachable_types_filtered,
11277 num_deleted_unreachable_types_filtered,
11278 num_changed_unreachable_types_filtered);
11279
11280 if (get_context()->do_log())
11281 {
11282 t.stop();
11283 std::cerr << "in apply_filters_and_compute_diff_stats:"
11284 << "unreachable types counted!:" << t << "\n";
11285 }
11286
11287 stat.num_added_unreachable_types(num_added_unreachable_types);
11288 stat.num_removed_unreachable_types(num_deleted_unreachable_types);
11289 stat.num_changed_unreachable_types(num_changed_unreachable_types);
11291 (num_added_unreachable_types_filtered);
11293 (num_deleted_unreachable_types_filtered);
11295 (num_changed_unreachable_types_filtered);
11296 }
11297}
11298
11299/// Emit the summary of the functions & variables that got
11300/// removed/changed/added.
11301///
11302/// TODO: This should be handled by the reporters, just like what is
11303/// done for reporter_base::diff_to_be_reported.
11304///
11305/// @param out the output stream to emit the stats to.
11306///
11307/// @param indent the indentation string to use in the summary.
11308void
11310 ostream& out,
11311 const string& indent)
11312{
11313 /// Report added/removed/changed functions.
11314 size_t net_num_leaf_changes =
11316 s.net_num_func_added() +
11319 s.net_num_vars_added() +
11326
11327 if (!sonames_equal_)
11328 out << indent << "ELF SONAME changed\n";
11329
11330 if (!architectures_equal_)
11331 out << indent << "ELF architecture changed\n";
11332
11333 diff_context_sptr ctxt = get_context();
11334
11335 if (ctxt->show_leaf_changes_only())
11336 {
11337 out << "Leaf changes summary: ";
11338 out << net_num_leaf_changes << " artifact";
11339 if (net_num_leaf_changes > 1)
11340 out << "s";
11341 out << " changed";
11342
11343 if (size_t num_filtered = s.num_leaf_changes_filtered_out())
11344 out << " (" << num_filtered << " filtered out)";
11345 out << "\n";
11346
11347 out << indent << "Changed leaf types summary: "
11350 out << " (" << s.num_leaf_type_changes_filtered_out()
11351 << " filtered out)";
11352 out << " leaf type";
11353 if (s.num_leaf_type_changes() > 1)
11354 out << "s";
11355 out << " changed\n";
11356
11357 // function changes summary
11358 out << indent << "Removed/Changed/Added functions summary: ";
11359 out << s.net_num_func_removed() << " Removed";
11361 out << " ("
11363 << " filtered out)";
11364 out << ", ";
11365
11366 out << s.net_num_leaf_func_changes() << " Changed";
11368 out << " ("
11370 << " filtered out)";
11371 out << ", ";
11372
11373 out << s.net_num_func_added()<< " Added ";
11374 if (s.net_num_func_added() <= 1)
11375 out << "function";
11376 else
11377 out << "functions";
11379 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11380 out << "\n";
11381
11382 // variables changes summary
11383 out << indent << "Removed/Changed/Added variables summary: ";
11384 out << s.net_num_vars_removed() << " Removed";
11386 out << " (" << s.num_removed_vars_filtered_out()
11387 << " filtered out)";
11388 out << ", ";
11389
11390 out << s.net_num_leaf_var_changes() << " Changed";
11392 out << " ("
11394 << " filtered out)";
11395 out << ", ";
11396
11397 out << s.net_num_vars_added() << " Added ";
11398 if (s.net_num_vars_added() <= 1)
11399 out << "variable";
11400 else
11401 out << "variables";
11403 out << " (" << s.num_added_vars_filtered_out()
11404 << " filtered out)";
11405 out << "\n";
11406 }
11407 else // if (ctxt->show_leaf_changes_only())
11408 {
11409 size_t total_nb_function_changes = s.num_func_removed()
11410 + s.num_func_changed() + s.num_func_added();
11411
11412 // function changes summary
11413 out << indent << "Functions changes summary: ";
11414 out << s.net_num_func_removed() << " Removed";
11416 out << " ("
11418 << " filtered out)";
11419 out << ", ";
11420
11421 out << s.net_num_func_changed() << " Changed";
11423 out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
11424 out << ", ";
11425
11426 out << s.net_num_func_added() << " Added";
11428 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11429 if (total_nb_function_changes <= 1)
11430 out << " function";
11431 else
11432 out << " functions";
11433 out << "\n";
11434
11435 // variables changes summary
11436 size_t total_nb_variable_changes = s.num_vars_removed()
11437 + s.num_vars_changed() + s.num_vars_added();
11438
11439 out << indent << "Variables changes summary: ";
11440 out << s.net_num_vars_removed() << " Removed";
11442 out << " (" << s.num_removed_vars_filtered_out()
11443 << " filtered out)";
11444 out << ", ";
11445
11446 out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
11448 out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
11449 out << ", ";
11450
11451 out << s.net_num_vars_added() << " Added";
11453 out << " (" << s.num_added_vars_filtered_out()
11454 << " filtered out)";
11455 if (total_nb_variable_changes <= 1)
11456 out << " variable";
11457 else
11458 out << " variables";
11459 out << "\n";
11460 }
11461
11462 // Show statistics about types not reachable from global
11463 // functions/variables.
11464 if (ctxt->show_unreachable_types())
11465 {
11466 size_t total_nb_unreachable_type_changes =
11470
11471 // Show summary of unreachable types
11472 out << indent << "Unreachable types summary: "
11474 << " removed";
11477 << " filtered out)";
11478 out << ", ";
11479
11481 << " changed";
11484 << " filtered out)";
11485 out << ", ";
11486
11488 << " added";
11491 << " filtered out)";
11492 if (total_nb_unreachable_type_changes <= 1)
11493 out << " type";
11494 else
11495 out << " types";
11496 out << "\n";
11497 }
11498
11499 if (ctxt->show_symbols_unreferenced_by_debug_info()
11500 && (s.num_func_syms_removed()
11501 || s.num_func_syms_added()
11503 || s.num_var_syms_added()))
11504 {
11505 // function symbols changes summary.
11506
11507 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11508 && s.num_func_syms_removed() == 0
11509 && s.num_func_syms_added() != 0)
11510 // If the only unreferenced function symbol change is function
11511 // syms that got added, but we were forbidden to show function
11512 // syms being added, do nothing.
11513 ;
11514 else
11515 {
11516 out << indent
11517 << "Function symbols changes summary: "
11518 << s.net_num_removed_func_syms() << " Removed";
11520 out << " (" << s.num_removed_func_syms_filtered_out()
11521 << " filtered out)";
11522 out << ", ";
11523 out << s.net_num_added_func_syms() << " Added";
11525 out << " (" << s.num_added_func_syms_filtered_out()
11526 << " filtered out)";
11527 out << " function symbol";
11529 out << "s";
11530 out << " not referenced by debug info\n";
11531 }
11532
11533 // variable symbol changes summary.
11534
11535 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11536 && s.num_var_syms_removed() == 0
11537 && s.num_var_syms_added() != 0)
11538 // If the only unreferenced variable symbol change is variable
11539 // syms that got added, but we were forbidden to show variable
11540 // syms being added, do nothing.
11541 ;
11542 else
11543 {
11544 out << indent
11545 << "Variable symbols changes summary: "
11546 << s.net_num_removed_var_syms() << " Removed";
11548 out << " (" << s.num_removed_var_syms_filtered_out()
11549 << " filtered out)";
11550 out << ", ";
11551 out << s.net_num_added_var_syms() << " Added";
11553 out << " (" << s.num_added_var_syms_filtered_out()
11554 << " filtered out)";
11555 out << " variable symbol";
11556 if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
11557 out << "s";
11558 out << " not referenced by debug info\n";
11559 }
11560 }
11561}
11562
11563/// Walk the changed functions and variables diff nodes to categorize
11564/// redundant nodes.
11565void
11567{
11569
11570 diff_context_sptr ctxt = get_context();
11571
11572 ctxt->forget_visited_diffs();
11573 for (function_decl_diff_sptrs_type::const_iterator i =
11574 changed_fns_.begin();
11575 i!= changed_fns_.end();
11576 ++i)
11577 {
11578 diff = *i;
11580 }
11581
11582 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11583 i!= sorted_changed_vars_.end();
11584 ++i)
11585 {
11586 diff_sptr diff = *i;
11588 }
11589
11590 for (diff_sptrs_type::const_iterator i =
11593 ++i)
11594 {
11595 diff_sptr diff = *i;
11597 }
11598}
11599
11600/// Walk the changed functions and variables diff nodes and clear the
11601/// redundancy categorization they might carry.
11602void
11604{
11606 for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
11607 i!= changed_fns_.end();
11608 ++i)
11609 {
11610 diff = *i;
11612 }
11613
11614 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11615 i!= sorted_changed_vars_.end();
11616 ++i)
11617 {
11618 diff = *i;
11620 }
11621}
11622
11623/// If the user asked to dump the diff tree node (for changed
11624/// variables and functions) on the error output stream, then just do
11625/// that.
11626///
11627/// This function is used for debugging purposes.
11628void
11630{
11631 diff_context_sptr ctxt = get_context();
11632
11633 if (!ctxt->dump_diff_tree()
11634 || ctxt->error_output_stream() == 0)
11635 return;
11636
11637 if (!changed_fns_.empty())
11638 {
11639 *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
11640 for (function_decl_diff_sptrs_type::const_iterator i =
11641 changed_fns_.begin();
11642 i != changed_fns_.end();
11643 ++i)
11644 {
11645 diff_sptr d = *i;
11646 print_diff_tree(d, *ctxt->error_output_stream());
11647 }
11648 }
11649
11650 if (!sorted_changed_vars_.empty())
11651 {
11652 *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
11653 for (var_diff_sptrs_type::const_iterator i =
11654 sorted_changed_vars_.begin();
11655 i != sorted_changed_vars_.end();
11656 ++i)
11657 {
11658 diff_sptr d = *i;
11659 print_diff_tree(d, *ctxt->error_output_stream());
11660 }
11661 }
11662
11663 if (!changed_unreachable_types_sorted().empty())
11664 {
11665 *ctxt->error_output_stream() << "\nchanged unreachable "
11666 "types diff tree: \n\n";
11667 for (vector<diff_sptr>::const_iterator i =
11670 ++i)
11671 {
11672 diff_sptr d = *i;
11673 print_diff_tree(d, *ctxt->error_output_stream());
11674 }
11675 }
11676}
11677
11678/// Populate the vector of children node of the @ref corpus_diff type.
11679///
11680/// The children node can then later be retrieved using
11681/// corpus_diff::children_node().
11682void
11684{
11685 for (function_decl_diff_sptrs_type::const_iterator i =
11686 changed_functions_sorted().begin();
11687 i != changed_functions_sorted().end();
11688 ++i)
11689 if (diff_sptr d = *i)
11691}
11692
11693/// Constructor for @ref corpus_diff.
11694///
11695/// @param first the first corpus of the diff.
11696///
11697/// @param second the second corpus of the diff.
11698///
11699/// @param ctxt the diff context to use. Note that this context
11700/// object must stay alive at least during the life time of the
11701/// current instance of @ref corpus_diff. Otherwise memory corruption
11702/// issues occur.
11704 corpus_sptr second,
11705 diff_context_sptr ctxt)
11706 : priv_(new priv(first, second, ctxt))
11707{}
11708
11709corpus_diff::~corpus_diff() = default;
11710
11711/// Finish building the current instance of @ref corpus_diff.
11712void
11714{
11715 if (priv_->finished_)
11716 return;
11718 priv_->finished_ = true;
11719}
11720
11721/// Test if logging was requested.
11722///
11723/// @return true iff logging was requested.
11724bool
11726{return context()->do_log();}
11727
11728/// Request logging, or not.
11729///
11730/// @param f true iff logging is requested.
11731void
11733{context()->do_log(f);}
11734
11735/// @return the first corpus of the diff.
11736corpus_sptr
11738{return priv_->first_;}
11739
11740/// @return the second corpus of the diff.
11741corpus_sptr
11743{return priv_->second_;}
11744
11745/// @return the children nodes of the current instance of corpus_diff.
11746const vector<diff*>&
11748{return priv_->children_;}
11749
11750/// Append a new child node to the vector of children nodes for the
11751/// current instance of @ref corpus_diff node.
11752///
11753/// Note that the vector of children nodes for the current instance of
11754/// @ref corpus_diff node must remain sorted, using
11755/// diff_less_than_functor.
11756///
11757/// @param d the new child node. Note that the life time of the
11758/// object held by @p d will thus equal the life time of the current
11759/// instance of @ref corpus_diff.
11760void
11762{
11763 ABG_ASSERT(d);
11764
11766 bool inserted = false;
11767 for (vector<diff*>::iterator i = priv_->children_.begin();
11768 i != priv_->children_.end();
11769 ++i)
11770 // Look for the point where to insert the diff child node.
11771 if (!is_less_than(d.get(), *i))
11772 {
11773 context()->keep_diff_alive(d);
11774 priv_->children_.insert(i, d.get());
11775 // As we have just inserted 'd' into the vector, the iterator
11776 // 'i' is invalidated. We must *NOT* use it anymore.
11777 inserted = true;
11778 break;
11779 }
11780
11781 if (!inserted)
11782 {
11783 context()->keep_diff_alive(d);
11784 // We didn't insert anything to the vector, presumably b/c it was
11785 // empty or had one element that was "less than" 'd'. We can thus
11786 // just append 'd' to the end of the vector.
11787 priv_->children_.push_back(d.get());
11788 }
11789}
11790
11791/// @return the bare edit script of the functions changed as recorded
11792/// by the diff.
11795{return priv_->fns_edit_script_;}
11796
11797/// @return the bare edit script of the variables changed as recorded
11798/// by the diff.
11801{return priv_->vars_edit_script_;}
11802
11803/// Test if the soname of the underlying corpus has changed.
11804///
11805/// @return true iff the soname has changed.
11806bool
11808{return !priv_->sonames_equal_;}
11809
11810/// Test if the architecture of the underlying corpus has changed.
11811///
11812/// @return true iff the architecture has changed.
11813bool
11815{return !priv_->architectures_equal_;}
11816
11817/// Getter for the deleted functions of the diff.
11818///
11819/// @return the the deleted functions of the diff.
11822{return priv_->deleted_fns_;}
11823
11824/// Getter for the added functions of the diff.
11825///
11826/// @return the added functions of the diff.
11829{return priv_->added_fns_;}
11830
11831/// Getter for the functions which signature didn't change, but which
11832/// do have some indirect changes in their parms.
11833///
11834/// @return a non-sorted map of functions which signature didn't
11835/// change, but which do have some indirect changes in their parms.
11836/// The key of the map is a unique identifier for the function; it's
11837/// usually made of the name and version of the underlying ELF symbol
11838/// of the function for corpora that were built from ELF files.
11841{return priv_->changed_fns_map_;}
11842
11843/// Getter for a sorted vector of functions which signature didn't
11844/// change, but which do have some indirect changes in their parms.
11845///
11846/// @return a sorted vector of functions which signature didn't
11847/// change, but which do have some indirect changes in their parms.
11850{return priv_->changed_fns_;}
11851
11852/// Getter of the set of diff nodes representing incompatibly changed
11853/// functions
11854///
11855/// @return the set of diff nodes representing incompatibly changed
11856/// functions
11859{return priv_->incompatible_changed_fns_;}
11860
11861/// Getter of the set of diff nodes representing incompatibly changed
11862/// functions
11863///
11864/// @return the set of diff nodes representing incompatibly changed
11865/// functions
11868{return priv_->incompatible_changed_fns_;}
11869
11870/// Getter for the variables that got deleted from the first subject
11871/// of the diff.
11872///
11873/// @return the map of deleted variable.
11874const string_var_ptr_map&
11876{return priv_->deleted_vars_;}
11877
11878/// Getter for the added variables of the diff.
11879///
11880/// @return the map of added variable.
11881const string_var_ptr_map&
11883{return priv_->added_vars_;}
11884
11885/// Getter for the non-sorted map of variables which signature didn't
11886/// change but which do have some indirect changes in some sub-types.
11887///
11888/// @return the non-sorted map of changed variables.
11891{return priv_->changed_vars_map_;}
11892
11893/// Getter for the sorted vector of variables which signature didn't
11894/// change but which do have some indirect changes in some sub-types.
11895///
11896/// @return a sorted vector of changed variables.
11899{return priv_->sorted_changed_vars_;}
11900
11901/// Getter of the set of diff nodes representing incompatibly changed
11902/// global variables.
11903///
11904/// @return the set of diff nodes representing incompatibly changed
11905/// global variables.
11908{return priv_->incompatible_changed_vars_;}
11909
11910/// Getter of the set of diff nodes representing incompatibly changed
11911/// global variables.
11912///
11913/// @return the set of diff nodes representing incompatibly changed
11914/// global variables.
11917{return priv_->incompatible_changed_vars_;}
11918
11919/// Getter for function symbols not referenced by any debug info and
11920/// that got deleted.
11921///
11922/// @return a map of elf function symbols not referenced by any debug
11923/// info and that got deleted.
11926{return priv_->deleted_unrefed_fn_syms_;}
11927
11928/// Getter for function symbols not referenced by any debug info and
11929/// that got added.
11930///
11931/// @return a map of elf function symbols not referenced by any debug
11932/// info and that got added.
11935{return priv_->added_unrefed_fn_syms_;}
11936
11937/// Getter for variable symbols not referenced by any debug info and
11938/// that got deleted.
11939///
11940/// @return a map of elf variable symbols not referenced by any debug
11941/// info and that got deleted.
11944{return priv_->deleted_unrefed_var_syms_;}
11945
11946/// Getter for variable symbols not referenced by any debug info and
11947/// that got added.
11948///
11949/// @return a map of elf variable symbols not referenced by any debug
11950/// info and that got added.
11953{return priv_->added_unrefed_var_syms_;}
11954
11955/// Getter for a map of deleted types that are not reachable from
11956/// global functions/variables.
11957///
11958/// @return a map that associates pretty representation of deleted
11959/// unreachable types and said types.
11962{return priv_->deleted_unreachable_types_;}
11963
11964/// Getter of a sorted vector of deleted types that are not reachable
11965/// from global functions/variables.
11966///
11967/// @return a sorted vector of deleted types that are not reachable
11968/// from global functions/variables. The types are lexicographically
11969/// sorted by considering their pretty representation.
11970const vector<type_base_sptr>&
11972{
11973 if (priv_->deleted_unreachable_types_sorted_.empty())
11974 if (!priv_->deleted_unreachable_types_.empty())
11975 sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
11976 priv_->deleted_unreachable_types_sorted_);
11977
11978 return priv_->deleted_unreachable_types_sorted_;
11979}
11980
11981/// Getter for a map of added types that are not reachable from global
11982/// functions/variables.
11983///
11984/// @return a map that associates pretty representation of added
11985/// unreachable types and said types.
11988{return priv_->added_unreachable_types_;}
11989
11990/// Getter of a sorted vector of added types that are not reachable
11991/// from global functions/variables.
11992///
11993/// @return a sorted vector of added types that are not reachable from
11994/// global functions/variables. The types are lexicographically
11995/// sorted by considering their pretty representation.
11996const vector<type_base_sptr>&
11998{
11999 if (priv_->added_unreachable_types_sorted_.empty())
12000 if (!priv_->added_unreachable_types_.empty())
12001 sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
12002 priv_->added_unreachable_types_sorted_);
12003
12004 return priv_->added_unreachable_types_sorted_;
12005}
12006
12007/// Getter for a map of changed types that are not reachable from
12008/// global functions/variables.
12009///
12010/// @return a map that associates pretty representation of changed
12011/// unreachable types and said types.
12014{return priv_->changed_unreachable_types_;}
12015
12016/// Getter of a sorted vector of changed types that are not reachable
12017/// from global functions/variables.
12018///
12019/// @return a sorted vector of changed types that are not reachable
12020/// from global functions/variables. The diffs are lexicographically
12021/// sorted by considering their pretty representation.
12022const vector<diff_sptr>&
12024{return priv_->changed_unreachable_types_sorted();}
12025
12026/// Getter of the diff context of this diff
12027///
12028/// @return the diff context for this diff.
12031{return priv_->get_context();}
12032
12033/// @return the pretty representation for the current instance of @ref
12034/// corpus_diff
12035const string&
12037{
12038 if (priv_->pretty_representation_.empty())
12039 {
12040 std::ostringstream o;
12041 o << "corpus_diff["
12042 << first_corpus()->get_path()
12043 << ", "
12044 << second_corpus()->get_path()
12045 << "]";
12046 priv_->pretty_representation_ = o.str();
12047 }
12048 return priv_->pretty_representation_;
12049}
12050/// Return true iff the current @ref corpus_diff node carries a
12051/// change.
12052///
12053/// @return true iff the current diff node carries a change.
12054bool
12056{
12057 return (soname_changed()
12059 || !(priv_->deleted_fns_.empty()
12060 && priv_->added_fns_.empty()
12061 && priv_->changed_fns_map_.empty()
12062 && priv_->deleted_vars_.empty()
12063 && priv_->added_vars_.empty()
12064 && priv_->changed_vars_map_.empty()
12065 && priv_->added_unrefed_fn_syms_.empty()
12066 && priv_->deleted_unrefed_fn_syms_.empty()
12067 && priv_->added_unrefed_var_syms_.empty()
12068 && priv_->deleted_unrefed_var_syms_.empty()
12069 && priv_->deleted_unreachable_types_.empty()
12070 && priv_->added_unreachable_types_.empty()
12071 && priv_->changed_unreachable_types_.empty()));
12072}
12073
12074/// Test if the current instance of @ref corpus_diff carries changes
12075/// that we are sure are incompatible. By incompatible change we mean
12076/// a change that "breaks" the ABI of the corpus we are looking at.
12077///
12078/// In concrete terms, this function considers the following changes
12079/// as being ABI incompatible for sure:
12080///
12081/// - a soname change
12082/// - if exported functions or variables got removed
12083///
12084/// Note that subtype changes *can* represent changes that break ABI
12085/// too. But they also can be changes that are OK, ABI-wise.
12086///
12087/// It's up to the user to provide suppression specifications to say
12088/// explicitely which subtype change is OK. The remaining sub-type
12089/// changes are then considered to be ABI incompatible. But to test
12090/// if such ABI incompatible subtype changes are present you need to
12091/// use the function @ref corpus_diff::has_net_subtype_changes()
12092///
12093/// @return true iff the current instance of @ref corpus_diff carries
12094/// changes that we are sure are ABI incompatible.
12095bool
12097{
12098 const diff_stats& stats = const_cast<corpus_diff*>(this)->
12100
12104 || stats.net_num_func_removed() != 0
12106 // If all reports about functions changes have been
12107 // suppressed, then even those about incompatible changes
12108 // don't matter anymore because the user willingly requested
12109 // to shut them down.
12110 && stats.net_num_func_changed() != 0)
12111 || stats.net_num_vars_removed() != 0
12113 && stats.net_num_vars_changed() != 0)
12114 || stats.net_num_removed_func_syms() != 0
12115 || stats.net_num_removed_var_syms() != 0
12116 || stats.net_num_removed_unreachable_types() != 0);
12117
12118 // If stats.net_num_changed_unreachable_types() != 0 then walk the
12119 // corpus_diff::priv::changed_unreachable_types_, and see if there
12120 // is one that is harmful by bitwise and-ing their category with
12121 // abigail::comparison::get_default_harmful_categories_bitmap().
12124 {
12125 // The changed unreachable types can carry harmful changes.
12126 // Let's figure if they actually do.
12127
12128 diff_context_sptr ctxt = context();
12129 for (auto &entry : priv_->changed_unreachable_types())
12130 {
12131 diff_sptr dif = entry.second;
12132
12133 // Let's see if any of the categories of this diff node
12134 // belong to the "harmful" ones.
12135 if (dif->get_category() & get_default_harmful_categories_bitmap())
12136 {
12138 break;
12139 }
12140 }
12141 }
12142
12144}
12145
12146/// Test if the current instance of @ref corpus_diff carries subtype
12147/// changes whose reports are not suppressed by any suppression
12148/// specification. In effect, these are deemed incompatible ABI
12149/// changes.
12150///
12151/// @return true iff the the current instance of @ref corpus_diff
12152/// carries subtype changes that are deemed incompatible ABI changes.
12153bool
12155{
12156 const diff_stats& stats = const_cast<corpus_diff*>(this)->
12158
12159 return (stats.net_num_func_changed() != 0
12160 || stats.net_num_vars_changed() != 0
12161 || stats.net_num_removed_unreachable_types() != 0
12162 || stats.net_num_changed_unreachable_types() != 0);
12163}
12164
12165/// Test if the current instance of @ref corpus_diff carries changes
12166/// whose reports are not suppressed by any suppression specification.
12167/// In effect, these are deemed incompatible ABI changes.
12168///
12169/// @return true iff the the current instance of @ref corpus_diff
12170/// carries subtype changes that are deemed incompatible ABI changes.
12171bool
12173{return context()->get_reporter()->diff_has_net_changes(this);}
12174
12175/// Apply the different filters that are registered to be applied to
12176/// the diff tree; that includes the categorization filters. Also,
12177/// apply the suppression interpretation filters.
12178///
12179/// After the filters are applied, this function calculates some
12180/// statistics about the changes carried by the current instance of
12181/// @ref corpus_diff. These statistics are represented by an instance
12182/// of @ref corpus_diff::diff_stats.
12183///
12184/// This member function is called by the reporting function
12185/// corpus_diff::report().
12186///
12187/// Note that for a given instance of corpus_diff, this function
12188/// applies the filters and suppressions only the first time it is
12189/// invoked. Subsequent invocations just return the instance of
12190/// corpus_diff::diff_stats that was cached after the first
12191/// invocation.
12192///
12193/// @return a reference to the statistics about the changes carried by
12194/// the current instance of @ref corpus_diff.
12197{
12198 if (priv_->diff_stats_)
12199 return *priv_->diff_stats_;
12200
12202 if (do_log())
12203 {
12204 std::cerr << "Applying suppressions ...\n";
12205 t.start();
12206 }
12207
12208 apply_suppressions(this);
12209
12210 if (do_log())
12211 {
12212 t.stop();
12213 std::cerr << "suppressions applied!:" << t << "\n";
12214 }
12215
12216 priv_->diff_stats_.reset(new diff_stats(context()));
12217
12218 if (do_log())
12219 {
12220 std::cerr << "Marking leaf nodes ...\n";
12221 t.start();
12222 }
12223
12225
12226 if (do_log())
12227 {
12228 t.stop();
12229 std::cerr << "leaf nodes marked!:" << t << "\n";
12230 std::cerr << "Applying filters and computing diff stats ...\n";
12231 t.start();
12232 }
12233
12234 priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
12235
12236 if (do_log())
12237 {
12238 t.stop();
12239 std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
12240 }
12241
12242 return *priv_->diff_stats_;
12243}
12244
12245/// A visitor that marks leaf diff nodes by storing them in the
12246/// instance of @ref diff_maps returned by
12247/// corpus_diff::get_leaf_diffs() invoked on the current instance of
12248/// corpus_diff.
12249struct leaf_diff_node_marker_visitor : public diff_node_visitor
12250{
12251 /// This is called when the visitor visits a diff node.
12252 ///
12253 /// It basically tests if the diff node being visited is a leaf diff
12254 /// node - that is, it contains local changes. If it does, then the
12255 /// node is added to the set of maps that hold leaf diffs in the
12256 /// current corpus_diff.
12257 ///
12258 /// Note that only leaf nodes that are reachable from public
12259 /// interfaces (global functions or variables) are collected by this
12260 /// visitor.
12261 ///
12262 /// @param d the diff node being visited.
12263 virtual void
12264 visit_begin(diff *d)
12265 {
12266 if (d->has_local_changes()
12267 // A leaf basic (or class/union) type name change makes no
12268 // sense when showing just leaf changes. It only makes sense
12269 // when it can explain the details about a non-leaf change.
12270 // In other words, it doesn't make sense to say that an "int"
12271 // became "unsigned int". But it does make sense to say that
12272 // a typedef changed because its underlying type was 'int' and
12273 // is now an "unsigned int".
12275 // Similarly, a *local* change describing a type that changed
12276 // its nature doesn't make sense.
12277 && !is_distinct_diff(d)
12278 // Similarly, a pointer (or reference or array), a typedef or
12279 // qualified type change in itself doesn't make sense. It
12280 // would rather make sense to show that pointer change as part
12281 // of the variable change whose pointer type changed, for
12282 // instance.
12283 && !is_pointer_diff(d)
12284 && !is_reference_diff(d)
12286 && !is_typedef_diff(d)
12287 && !is_array_diff(d)
12288 // Similarly a parameter change in itself doesn't make sense.
12289 // It should have already been reported as part of the change
12290 // of the function it belongs to.
12291 && !is_fn_parm_diff(d)
12292 // An anonymous class or union diff doesn't make sense on its
12293 // own. It must have been described already by the diff of
12294 // the enclosing struct or union if 'd' is from an anonymous
12295 // data member, or from a typedef change if 'd' is from a
12296 // typedef change which underlying type is an anonymous
12297 // struct/union.
12299 // An anonymous subrange doesn't make sense either.
12301 // Don't show decl-only-ness changes either.
12303 // Sometime, we can encounter artifacts of bogus DWARF that
12304 // yield a diff node for a decl-only class (and empty class
12305 // with the is_declaration flag set) that carries a non-zero
12306 // size! And of course at some point that non-zero size
12307 // changes. We need to be able to detect that.
12309 {
12310 diff_context_sptr ctxt = d->context();
12311 const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
12312 ABG_ASSERT(corpus_diff_node);
12313
12314 if (diff *iface_diff = get_current_topmost_iface_diff())
12315 {
12316 type_or_decl_base_sptr iface = iface_diff->first_subject();
12317 // So, this diff node that is reachable from a global
12318 // function or variable carries a leaf change. Let's add
12319 // it to the set of of leaf diffs of corpus_diff_node.
12320 const_cast<corpus_diff*>(corpus_diff_node)->
12321 get_leaf_diffs().insert_diff_node(d, iface);
12322 }
12323 }
12324 }
12325}; // end struct leaf_diff_node_marker_visitor
12326
12327/// Walks the diff nodes associated to the current corpus diff and
12328/// mark those that carry local changes. They are said to be leaf
12329/// diff nodes.
12330///
12331/// The marked nodes are available from the
12332/// corpus_diff::get_leaf_diffs() function.
12333void
12335{
12336 if (!has_changes())
12337 return;
12338
12339 if (!context()->show_leaf_changes_only())
12340 return;
12341
12342 leaf_diff_node_marker_visitor v;
12343 context()->forget_visited_diffs();
12344 bool s = context()->visiting_a_node_twice_is_forbidden();
12345 context()->forbid_visiting_a_node_twice(true);
12346 if (context()->show_impacted_interfaces())
12347 context()->forbid_visiting_a_node_twice_per_interface(true);
12348 traverse(v);
12349 context()->forbid_visiting_a_node_twice(s);
12350 context()->forbid_visiting_a_node_twice_per_interface(false);
12351}
12352
12353/// Get the set of maps that contain leaf nodes. A leaf node being a
12354/// node with a local change.
12355///
12356/// @return the set of maps that contain leaf nodes. A leaf node
12357/// being a node with a local change.
12358diff_maps&
12360{return priv_->leaf_diffs_;}
12361
12362/// Get the set of maps that contain leaf nodes. A leaf node being a
12363/// node with a local change.
12364///
12365/// @return the set of maps that contain leaf nodes. A leaf node
12366/// being a node with a local change.
12367const diff_maps&
12369{return priv_->leaf_diffs_;}
12370
12371/// Report the diff in a serialized form.
12372///
12373/// @param out the stream to serialize the diff to.
12374///
12375/// @param indent the prefix to use for the indentation of this
12376/// serialization.
12377void
12378corpus_diff::report(ostream& out, const string& indent) const
12379{
12380 context()->get_reporter()->report(*this, out, indent);
12381}
12382
12383/// Traverse the diff sub-tree under the current instance corpus_diff.
12384///
12385/// @param v the visitor to invoke on each diff node of the sub-tree.
12386///
12387/// @return true if the traversing has to keep going on, false otherwise.
12388bool
12390{
12392
12393 v.visit_begin(this);
12394
12395 if (!v.visit(this, true))
12396 {
12397 v.visit_end(this);
12398 return false;
12399 }
12400
12401 for (function_decl_diff_sptrs_type::const_iterator i =
12402 changed_functions_sorted().begin();
12403 i != changed_functions_sorted().end();
12404 ++i)
12405 {
12406 if (diff_sptr d = *i)
12407 {
12408 const diff_context_sptr &ctxt = context();
12409 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12410 ctxt->forget_visited_diffs();
12411
12413
12414 if (!d->traverse(v))
12415 {
12416 v.visit_end(this);
12418 return false;
12419 }
12420 }
12421 }
12422
12423 for (var_diff_sptrs_type::const_iterator i =
12424 changed_variables_sorted().begin();
12425 i != changed_variables_sorted().end();
12426 ++i)
12427 {
12428 if (diff_sptr d = *i)
12429 {
12430 const diff_context_sptr &ctxt = context();
12431 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12432 ctxt->forget_visited_diffs();
12433
12435
12436 if (!d->traverse(v))
12437 {
12438 v.visit_end(this);
12440 return false;
12441 }
12442 }
12443 }
12444
12446
12447 // Traverse the changed unreachable type diffs. These diffs are on
12448 // types that are not reachable from global functions or variables.
12449 for (vector<diff_sptr>::const_iterator i =
12452 ++i)
12453 {
12454 if (diff_sptr d = *i)
12455 {
12456 const diff_context_sptr &ctxt = context();
12457 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12458 ctxt->forget_visited_diffs();
12459
12460 if (!d->traverse(v))
12461 {
12462 v.visit_end(this);
12463 return false;
12464 }
12465 }
12466 }
12467
12468 v.visit_end(this);
12469 return true;
12470}
12471
12472/// Compute the diff between two instances of @ref corpus.
12473///
12474/// Note that the two corpora must have been created in the same @ref
12475/// environment, otherwise, this function aborts.
12476///
12477/// @param f the first @ref corpus to consider for the diff.
12478///
12479/// @param s the second @ref corpus to consider for the diff.
12480///
12481/// @param ctxt the diff context to use.
12482///
12483/// @return the resulting diff between the two @ref corpus.
12485compute_diff(const corpus_sptr f,
12486 const corpus_sptr s,
12487 diff_context_sptr ctxt)
12488{
12489 typedef corpus::functions::const_iterator fns_it_type;
12490 typedef corpus::variables::const_iterator vars_it_type;
12491 typedef elf_symbols::const_iterator symbols_it_type;
12492 typedef diff_utils::deep_ptr_eq_functor eq_type;
12493 typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
12494
12495 ABG_ASSERT(f && s);
12496
12497 if (!ctxt)
12498 ctxt.reset(new diff_context);
12499
12500 corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
12501
12502 ctxt->set_corpus_diff(r);
12503
12504 if(ctxt->show_soname_change())
12505 r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
12506 else
12507 r->priv_->sonames_equal_ = true;
12508
12509 r->priv_->architectures_equal_ =
12510 f->get_architecture_name() == s->get_architecture_name();
12511
12512 // Compute the diff of publicly defined and exported functions
12513 diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
12514 f->get_functions().end(),
12515 s->get_functions().begin(),
12516 s->get_functions().end(),
12517 r->priv_->fns_edit_script_);
12518
12519 // Compute the diff of publicly defined and exported variables.
12520 diff_utils::compute_diff<vars_it_type, eq_type>
12521 (f->get_variables().begin(), f->get_variables().end(),
12522 s->get_variables().begin(), s->get_variables().end(),
12523 r->priv_->vars_edit_script_);
12524
12525 // Compute the diff of function elf symbols not referenced by debug
12526 // info.
12527 diff_utils::compute_diff<symbols_it_type, eq_type>
12528 (f->get_unreferenced_function_symbols().begin(),
12529 f->get_unreferenced_function_symbols().end(),
12530 s->get_unreferenced_function_symbols().begin(),
12531 s->get_unreferenced_function_symbols().end(),
12532 r->priv_->unrefed_fn_syms_edit_script_);
12533
12534 // Compute the diff of variable elf symbols not referenced by debug
12535 // info.
12536 diff_utils::compute_diff<symbols_it_type, eq_type>
12537 (f->get_unreferenced_variable_symbols().begin(),
12538 f->get_unreferenced_variable_symbols().end(),
12539 s->get_unreferenced_variable_symbols().begin(),
12540 s->get_unreferenced_variable_symbols().end(),
12541 r->priv_->unrefed_var_syms_edit_script_);
12542
12543 if (ctxt->show_unreachable_types())
12544 // Compute the diff of types not reachable from public functions
12545 // or global variables that are exported.
12546 diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
12547 (f->get_types_not_reachable_from_public_interfaces().begin(),
12548 f->get_types_not_reachable_from_public_interfaces().end(),
12549 s->get_types_not_reachable_from_public_interfaces().begin(),
12550 s->get_types_not_reachable_from_public_interfaces().end(),
12551 r->priv_->unreachable_types_edit_script_);
12552
12553 r->priv_->ensure_lookup_tables_populated();
12554
12555 return r;
12556}
12557
12558// </corpus stuff>
12559
12560/// Compute the diff between two instances of @ref corpus_group.
12561///
12562/// Note that the two corpus_diff must have been created in the same
12563/// @ref environment, otherwise, this function aborts.
12564///
12565/// @param f the first @ref corpus_group to consider for the diff.
12566///
12567/// @param s the second @ref corpus_group to consider for the diff.
12568///
12569/// @param ctxt the diff context to use.
12570///
12571/// @return the resulting diff between the two @ref corpus_group.
12573compute_diff(const corpus_group_sptr& f,
12574 const corpus_group_sptr& s,
12575 diff_context_sptr ctxt)
12576{
12577
12578 corpus_sptr c1 = f;
12579 corpus_sptr c2 = s;
12580
12581 return compute_diff(c1, c2, ctxt);
12582}
12583
12584// <corpus_group stuff>
12585
12586// </corpus_group stuff>
12587// <diff_node_visitor stuff>
12588
12589/// The private data of the @diff_node_visitor type.
12590struct diff_node_visitor::priv
12591{
12592 diff* topmost_interface_diff;
12593 visiting_kind kind;
12594
12595 priv()
12596 : topmost_interface_diff(),
12597 kind()
12598 {}
12599
12600 priv(visiting_kind k)
12601 : topmost_interface_diff(),
12602 kind(k)
12603 {}
12604}; // end struct diff_node_visitor
12605
12606/// Default constructor of the @ref diff_node_visitor type.
12608 : priv_(new priv)
12609{}
12610
12611diff_node_visitor::~diff_node_visitor() = default;
12612
12613/// Constructor of the @ref diff_node_visitor type.
12614///
12615/// @param k how the visiting has to be performed.
12617 : priv_(new priv(k))
12618{}
12619
12620/// Getter for the visiting policy of the traversing code while
12621/// invoking this visitor.
12622///
12623/// @return the visiting policy used by the traversing code when
12624/// invoking this visitor.
12627{return priv_->kind;}
12628
12629/// Setter for the visiting policy of the traversing code while
12630/// invoking this visitor.
12631///
12632/// @param v a bit map representing the new visiting policy used by
12633/// the traversing code when invoking this visitor.
12634void
12636{priv_->kind = v;}
12637
12638/// Setter for the visiting policy of the traversing code while
12639/// invoking this visitor. This one makes a logical or between the
12640/// current policy and the bitmap given in argument and assigns the
12641/// current policy to the result.
12642///
12643/// @param v a bitmap representing the visiting policy to or with
12644/// the current policy.
12645void
12647{priv_->kind = priv_->kind | v;}
12648
12649/// Setter of the diff current topmost interface which is impacted by
12650/// the current diff node being visited.
12651///
12652/// @param d the current topmost interface diff impacted.
12653void
12655{priv_->topmost_interface_diff = d;}
12656
12657/// Getter of the diff current topmost interface which is impacted by
12658/// the current diff node being visited.
12659///
12660/// @return the current topmost interface diff impacted.
12661diff*
12663{return priv_->topmost_interface_diff;}
12664
12665/// This is called by the traversing code on a @ref diff node just
12666/// before visiting it. That is, before visiting it and its children
12667/// node.
12668///
12669/// @param d the diff node to visit.
12670void
12672{}
12673
12674/// This is called by the traversing code on a @ref diff node just
12675/// after visiting it. That is after visiting it and its children
12676/// nodes.
12677///
12678/// @param d the diff node that got visited.
12679void
12681{}
12682
12683/// This is called by the traversing code on a @ref corpus_diff node
12684/// just before visiting it. That is, before visiting it and its
12685/// children node.
12686///
12687/// @param p the corpus_diff node to visit.
12688///
12689void
12691{}
12692
12693/// This is called by the traversing code on a @ref corpus_diff node
12694/// just after visiting it. That is after visiting it and its children
12695/// nodes.
12696///
12697/// @param d the diff node that got visited.
12698void
12700{}
12701
12702/// Default visitor implementation
12703///
12704/// @return true
12705bool
12707{return true;}
12708
12709/// Default visitor implementation.
12710///
12711/// @return true
12712bool
12714{
12715 diff* d = dif;
12716 visit(d, pre);
12717
12718 return true;
12719}
12720
12721/// Default visitor implementation.
12722///
12723/// @return true
12724bool
12726{
12727 diff* d = dif;
12728 visit(d, pre);
12729
12730 return true;
12731}
12732
12733/// Default visitor implementation.
12734///
12735/// @return true
12736bool
12738{
12739 diff* d = dif;
12740 visit(d, pre);
12741
12742 return true;
12743}
12744
12745/// Default visitor implementation.
12746///
12747/// @return true
12748bool
12750{
12751 diff* d = dif;
12752 visit(d, pre);
12753
12754 return true;
12755}
12756
12757/// Default visitor implementation.
12758///
12759/// @return true
12760bool
12762{
12763 diff* d = dif;
12764 visit(d, pre);
12765
12766 return true;
12767}
12768
12769/// Default visitor implementation.
12770///
12771/// @return true
12772bool
12774{
12775 diff* d = dif;
12776 visit(d, pre);
12777
12778 return true;
12779}
12780
12781/// Default visitor implementation.
12782///
12783/// @return true
12784bool
12786{
12787 diff* d = dif;
12788 visit(d, pre);
12789
12790 return true;
12791}
12792
12793/// Default visitor implementation.
12794///
12795/// @return true
12796bool
12798{
12799 diff* d = dif;
12800 visit(d, pre);
12801
12802 return true;
12803}
12804
12805/// Default visitor implementation.
12806///
12807/// @return true
12808bool
12810{
12811 diff* d = dif;
12812 visit(d, pre);
12813
12814 return true;
12815}
12816
12817/// Default visitor implementation.
12818///
12819/// @return true
12820bool
12822{
12823 diff* d = dif;
12824 visit(d, pre);
12825
12826 return true;
12827}
12828
12829/// Default visitor implementation.
12830///
12831/// @return true
12832bool
12834{
12835 diff* d = dif;
12836 visit(d, pre);
12837
12838 return true;
12839}
12840
12841/// Default visitor implementation.
12842///
12843/// @return true
12844bool
12846{
12847 diff* d = dif;
12848 visit(d, pre);
12849
12850 return true;
12851}
12852
12853/// Default visitor implementation.
12854///
12855/// @return true
12856bool
12858{
12859 diff* d = dif;
12860 visit(d, pre);
12861
12862 return true;
12863}
12864
12865/// Default visitor implementation.
12866///
12867/// @return true
12868bool
12870{return true;}
12871
12872// </diff_node_visitor stuff>
12873
12874// <redundant diff node marking>
12875
12876// </redundant diff node marking>
12877
12878// <diff tree category propagation>
12879
12880/// A visitor to propagate the category of a node up to its parent
12881/// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
12882/// SUPPRESSED_CATEGORY because those are propagated using other
12883/// specific visitors.
12884struct category_propagation_visitor : public diff_node_visitor
12885{
12886 virtual void
12887 visit_end(diff* d)
12888 {
12889 // Has this diff node 'd' been already visited ?
12890 bool already_visited = d->context()->diff_has_been_visited(d);
12891
12892 // The canonical diff node of the class of equivalence of the diff
12893 // node 'd'.
12894 diff* canonical = d->get_canonical_diff();
12895
12896 // If this class of equivalence of diff node is being visited for
12897 // the first time, then update its canonical node's category too.
12898 bool update_canonical = !already_visited && canonical;
12899
12900 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12901 i != d->children_nodes().end();
12902 ++i)
12903 {
12904 // If we are visiting the class of equivalence of 'd' for the
12905 // first time, then let's look at the children of 'd' and
12906 // propagate their categories to 'd'.
12907 //
12908 // If the class of equivalence of 'd' has already been
12909 // visited, then let's look at the canonical diff nodes of the
12910 // children of 'd' and propagate their categories to 'd'.
12911 diff* diff = already_visited
12912 ? (*i)->get_canonical_diff()
12913 : *i;
12914
12916
12918 // Do not propagate redundant and suppressed categories. Those
12919 // are propagated in a specific pass elsewhere.
12920 c &= ~(REDUNDANT_CATEGORY
12926 // Also, if a (class) type has got a harmful name change, do not
12927 // propagate harmless name changes coming from its sub-types
12928 // (i.e, data members) to the class itself.
12931
12932 d->add_to_category(c);
12933 if (!already_visited && canonical)
12934 if (update_canonical)
12935 canonical->add_to_category(c);
12936 }
12937
12940 {
12941 // The current diff node has either:
12942 //
12943 // 1/ a harmless "void pointer to pointer" change
12944 //
12945 // or:
12946 //
12947 // 2/ a harmless "enum to int" change.
12948 //
12949 // The change 1/ was most likely flagged locally as a
12950 // non-compatible distinct change, aka, a non-compatible
12951 // change between two types of different kinds. At a higher
12952 // level however, as we see that it's just a void pointer to
12953 // pointer change, we should unset the
12954 // NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY categorization.
12955 //
12956 // The change 2/ was most likely flagged locally (in the
12957 // children nodes of the current diff node) as a
12958 // non-compatible name change. At a higher level however, as
12959 // we see that it's just a harmless "enum to int" change,
12960 // let's unset the NON_COMPATIBLE_NAME_CHANGE_CATEGORY
12961 // categorization as well.
12962 diff_category c = d->get_category();
12963 c &= (~NON_COMPATIBLE_NAME_CHANGE_CATEGORY
12964 & ~NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY);
12965 d->set_category(c);
12967 {
12968 // For pointers and references, changes to
12969 // pointed-to-types are considered local. So, if some
12970 // pointed-to-types have non-compatible name or distinct
12971 // change, then the local category of the
12972 // pointer/reference will reflect that. Let's thus clear
12973 // those NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY and
12974 // NON_COMPATIBLE_NAME_CHANGE_CATEGORY bits from the local
12975 // category as well.
12976 c = d->get_local_category();
12977 c &= (~NON_COMPATIBLE_NAME_CHANGE_CATEGORY
12978 & ~NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY);
12979 d->set_local_category(c);
12980 }
12981 }
12982
12984 {
12985 diff_category c = d->get_category();
12986 c &= ~NON_COMPATIBLE_NAME_CHANGE_CATEGORY;
12987 d->set_category(c);
12988 }
12989 }
12990};// end struct category_propagation_visitor
12991
12992/// Visit all the nodes of a given sub-tree. For each node that has a
12993/// particular category set, propagate that category set up to its
12994/// parent nodes.
12995///
12996/// @param diff_tree the diff sub-tree to walk for categorization
12997/// purpose;
12998void
13000{
13001 category_propagation_visitor v;
13002 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13003 diff_tree->context()->forbid_visiting_a_node_twice(true);
13004 diff_tree->context()->forget_visited_diffs();
13005 diff_tree->traverse(v);
13006 diff_tree->context()->forbid_visiting_a_node_twice(s);
13007}
13008
13009/// Visit all the nodes of a given sub-tree. For each node that has a
13010/// particular category set, propagate that category set up to its
13011/// parent nodes.
13012///
13013/// @param diff_tree the diff sub-tree to walk for categorization
13014/// purpose;
13015void
13017{propagate_categories(diff_tree.get());}
13018
13019/// Visit all the nodes of a given corpus tree. For each node that
13020/// has a particular category set, propagate that category set up to
13021/// its parent nodes.
13022///
13023/// @param diff_tree the corpus_diff tree to walk for categorization
13024/// purpose;
13025void
13027{
13028 category_propagation_visitor v;
13029 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13030 diff_tree->context()->forbid_visiting_a_node_twice(false);
13031 diff_tree->traverse(v);
13032 diff_tree->context()->forbid_visiting_a_node_twice(s);
13033}
13034
13035/// Visit all the nodes of a given corpus tree. For each node that
13036/// has a particular category set, propagate that category set up to
13037/// its parent nodes.
13038///
13039/// @param diff_tree the corpus_diff tree to walk for categorization
13040/// purpose;
13041void
13043{propagate_categories(diff_tree.get());}
13044
13045/// A tree node visitor that knows how to categorizes a given diff
13046/// node in the SUPPRESSED_CATEGORY category and how to propagate that
13047/// categorization.
13048struct suppression_categorization_visitor : public diff_node_visitor
13049{
13050
13051 /// Before visiting the children of the diff node, check if the node
13052 /// is suppressed by a suppression specification. If it is, mark
13053 /// the node as belonging to the SUPPRESSED_CATEGORY category.
13054 ///
13055 /// @param p the diff node to visit.
13056 virtual void
13057 visit_begin(diff* d)
13058 {
13059 bool is_private_type = false;
13060 if (d->is_suppressed(is_private_type))
13061 {
13062 diff_category c = is_private_type
13066
13067 // If a node was suppressed, all the other nodes of its class
13068 // of equivalence are suppressed too.
13069 diff *canonical_diff = d->get_canonical_diff();
13070 if (canonical_diff != d)
13071 canonical_diff->add_to_category(c);
13072 }
13074 {
13075 // This diff node is specifically allowed by a
13076 // negated_suppression, then mark it as being in the
13077 // HAS_ALLOWED_CHANGE_CATEGORY.
13080 diff *canonical_diff = d->get_canonical_diff();
13081 canonical_diff->add_to_category(c);
13082
13083 // Note that some complementary code later down below does
13084 // categorize the descendants and parents nodes of this node
13085 // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
13086 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
13087 }
13088
13089 // If a parent node has been allowed by a negated suppression
13090 // specification, then categorize the current node as
13091 // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
13092 if (d->parent_node())
13093 {
13098 else
13099 {
13100 c = d->parent_node()->get_category();
13104 }
13105 }
13106
13107 }
13108
13109 /// After visiting the children nodes of a given diff node,
13110 /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
13111 /// diff node, if need be.
13112 ///
13113 /// That is, if all children nodes carry a suppressed change the
13114 /// current node should be marked as suppressed as well.
13115 ///
13116 /// In practice, this might be too strong of a condition. If the
13117 /// current node carries a local change (i.e, a change not carried
13118 /// by any of its children node) and if that change is not
13119 /// suppressed, then the current node should *NOT* be suppressed.
13120 ///
13121 /// But right now, the IR doesn't let us know about local vs
13122 /// children-carried changes. So we cannot be that precise yet.
13123 virtual void
13124 visit_end(diff* d)
13125 {
13126 bool has_non_suppressed_child = false;
13127 bool has_non_empty_child = false;
13128 bool has_suppressed_child = false;
13129 bool has_non_private_child = false;
13130 bool has_private_child = false;
13131 bool has_descendant_with_allowed_change = false;
13132
13133 if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
13134 // (or the PRIVATE_TYPE_CATEGORY for the same matter)
13135 // category from its children is a node which:
13136 //
13137 // 1/ hasn't been suppressed already
13138 //
13139 // 2/ and has no local change (unless it's a pointer,
13140 // reference or qualified diff node).
13141 //
13142 // Note that qualified type and typedef diff nodes are a bit
13143 // special. The local changes of the underlying type are
13144 // considered local for the qualified/typedef type, just like
13145 // for pointer/reference types. But then the qualified or
13146 // typedef type itself can have local changes of its own, and
13147 // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
13148 // So a qualified type which have local changes that are
13149 // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
13150 // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
13151 // or SUPPRESSED_CATEGORY can see these categories be
13152 // propagated.
13153 //
13154 // Note that all pointer/reference diff node changes are
13155 // potentially considered local, i.e, local changes of the
13156 // pointed-to-type are considered local to the pointer itself.
13157 //
13158 // Similarly, changes local to the type of function parameters,
13159 // variables (and data members) and classes (that are not of
13160 // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
13161 // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
13162 // those kinds of diff node.
13163 !(d->get_category() & SUPPRESSED_CATEGORY)
13164 && (!d->has_local_changes()
13165 || is_pointer_diff(d)
13166 || is_reference_diff(d)
13168 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13169 || (is_typedef_diff(d)
13170 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13172 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13173 || (is_fn_parm_diff(d)
13174 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13176 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13177 || (is_var_diff(d)
13178 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
13179 || (is_class_diff(d)
13180 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
13181 {
13182 // Note that we handle private diff nodes differently from
13183 // generally suppressed diff nodes. E.g, it's not because a
13184 // type is private (and suppressed because of that; i.e, in
13185 // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
13186 // type should also be private and so suppressed. Private
13187 // diff nodes thus have different propagation rules than
13188 // generally suppressed rules.
13189 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
13190 i != d->children_nodes().end();
13191 ++i)
13192 {
13193 diff* child = *i;
13194 if (child->has_changes())
13195 {
13196 has_non_empty_child = true;
13197 if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
13198 has_suppressed_child = true;
13199 else if (child->get_class_of_equiv_category()
13201 // Propagation of the PRIVATE_TYPE_CATEGORY is going
13202 // to be handled later below.
13203 ;
13204 else
13205 has_non_suppressed_child = true;
13206
13207 if (child->get_class_of_equiv_category()
13209 has_private_child = true;
13210 else if (child->get_class_of_equiv_category()
13212 // Propagation of the SUPPRESSED_CATEGORY has been
13213 // handled above already.
13214 ;
13215 else
13216 has_non_private_child = true;
13217 }
13218 }
13219
13220 if (has_non_empty_child
13221 && has_suppressed_child
13222 && !has_non_suppressed_child)
13223 {
13225 // If a node was suppressed, all the other nodes of its class
13226 // of equivalence are suppressed too.
13227 diff *canonical_diff = d->get_canonical_diff();
13228 if (canonical_diff != d)
13229 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
13230 }
13231
13232 // Note that the private-ness of a an underlying type won't be
13233 // propagated to its parent typedef, by virtue of the big "if"
13234 // clause at the beginning of this function. So we don't have
13235 // to handle that case here. So the idiom of defining
13236 // typedefs of private (opaque) types will be respected;
13237 // meaning that changes to opaque underlying type will be
13238 // flagged as private and the typedef will be flagged private
13239 // as well, unless the typedef itself has local non-type
13240 // changes. In the later case, changes to the typedef will be
13241 // emitted because the typedef won't inherit the privateness
13242 // of its underlying type. So in practise, the typedef
13243 // remains public for the purpose of change reporting.
13244 if (has_non_empty_child
13245 && has_private_child
13246 && !has_non_private_child)
13247 {
13248 d->add_to_category(PRIVATE_TYPE_CATEGORY);
13249 // If a node was suppressed, all the other nodes of its class
13250 // of equivalence are suppressed too.
13251 diff *canonical_diff = d->get_canonical_diff();
13252 if (canonical_diff != d)
13253 canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
13254 }
13255
13256 // If the underlying type of a typedef is private and carries
13257 // changes (that are implicitely suppressed because it's
13258 // private) then the typedef must be suppressed too, so that
13259 // those changes to the underlying type are not seen.
13260 if (is_typedef_diff(d)
13261 && !d->has_local_changes()
13262 && has_private_child
13263 && has_non_empty_child)
13264 {
13265 d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
13266 // If a node was suppressed, all the other nodes of its class
13267 // of equivalence are suppressed too.
13268 diff *canonical_diff = d->get_canonical_diff();
13269 if (canonical_diff != d)
13270 canonical_diff->add_to_category
13272 }
13273
13274 if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
13275 if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
13276 {
13277 // d is a function diff that carries a local *type*
13278 // change (that means it's a change to the function
13279 // type). Let's see if the child function type diff
13280 // node is suppressed. That would mean that we are
13281 // instructed to show details of a diff that is deemed
13282 // suppressed; this means the suppression conflicts with
13283 // a local type change. In that case, let's follow what
13284 // the user asked and suppress the function altogether,
13285 if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
13286 if (fn_type_diff->is_suppressed())
13287 {
13288 d->add_to_category(SUPPRESSED_CATEGORY);
13289 // If a node was suppressed, all the other nodes
13290 // of its class of equivalence are suppressed too.
13291 diff *canonical_diff = d->get_canonical_diff();
13292 if (canonical_diff != d)
13293 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
13294 }
13295 }
13296 }
13297
13298 // If any descendant node was selected by a negated suppression
13299 // specification then categorize the current one as
13300 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
13301 for (auto child_node : d->children_nodes())
13302 {
13303 diff *canonical_diff = child_node->get_canonical_diff();
13304 diff_category c = canonical_diff->get_category();
13307 has_descendant_with_allowed_change = true;
13308 }
13309 if (has_descendant_with_allowed_change)
13310 {
13312 d->add_to_category(c);
13313 d->get_canonical_diff()->add_to_category(c);
13314 }
13315 }
13316}; //end struct suppression_categorization_visitor
13317
13318/// Walk a given diff-sub tree and appply the suppressions carried by
13319/// the context. If the suppression applies to a given node than
13320/// categorize the node into the SUPPRESSED_CATEGORY category and
13321/// propagate that categorization.
13322///
13323/// @param diff_tree the diff-sub tree to apply the suppressions to.
13324void
13326{
13327 if (diff_tree && !diff_tree->context()->suppressions().empty())
13328 {
13329 // Apply suppressions to functions and variables that have
13330 // changed sub-types.
13331 suppression_categorization_visitor v;
13332 diff_tree->context()->forget_visited_diffs();
13333 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13334 diff_tree->context()->forbid_visiting_a_node_twice(true);
13335 diff_tree->traverse(v);
13336 diff_tree->context()->forbid_visiting_a_node_twice(s);
13337 }
13338}
13339
13340/// Walk a given diff-sub tree and appply the suppressions carried by
13341/// the context. If the suppression applies to a given node than
13342/// categorize the node into the SUPPRESSED_CATEGORY category and
13343/// propagate that categorization.
13344///
13345/// @param diff_tree the diff-sub tree to apply the suppressions to.
13346void
13348{apply_suppressions(diff_tree.get());}
13349
13350/// Walk a @ref corpus_diff tree and appply the suppressions carried
13351/// by the context. If the suppression applies to a given node then
13352/// categorize the node into the SUPPRESSED_CATEGORY category and
13353/// propagate that categorization.
13354///
13355/// @param diff_tree the diff tree to apply the suppressions to.
13356void
13358{
13359 if (diff_tree && !diff_tree->context()->suppressions().empty())
13360 {
13361 // First, visit the children trees of changed constructs:
13362 // changed functions, variables, as well as sub-types of these,
13363 // and apply suppression specifications to these ...
13364 suppression_categorization_visitor v;
13365 diff_tree->context()->forget_visited_diffs();
13366 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13367 diff_tree->context()->forbid_visiting_a_node_twice(true);
13368 const_cast<corpus_diff*>(diff_tree)->traverse(v);
13369 diff_tree->context()->forbid_visiting_a_node_twice(s);
13370
13371 // ... then also visit the set of added and removed functions,
13372 // variables, symbols, and types not reachable from global
13373 // functions and variables.
13374 diff_tree->priv_->
13375 apply_supprs_to_added_removed_fns_vars_unreachable_types();
13376 }
13377}
13378
13379/// Walk a diff tree and appply the suppressions carried by the
13380/// context. If the suppression applies to a given node than
13381/// categorize the node into the SUPPRESSED_CATEGORY category and
13382/// propagate that categorization.
13383///
13384/// @param diff_tree the diff tree to apply the suppressions to.
13385void
13387{apply_suppressions(diff_tree.get());}
13388
13389// </diff tree category propagation>
13390
13391// <diff tree printing stuff>
13392
13393/// A visitor to print (to an output stream) a pretty representation
13394/// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
13395struct diff_node_printer : public diff_node_visitor
13396{
13397 ostream& out_;
13398 unsigned level_;
13399
13400 /// Emit a certain number of spaces to the output stream associated
13401 /// to this diff_node_printer.
13402 ///
13403 /// @param level half of the numver of spaces to emit.
13404 void
13405 do_indent(unsigned level)
13406 {
13407 for (unsigned i = 0; i < level; ++i)
13408 out_ << " ";
13409 }
13410
13411 diff_node_printer(ostream& out)
13412 : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
13413 out_(out),
13414 level_(0)
13415 {}
13416
13417 virtual void
13418 visit_begin(diff*)
13419 {
13420 ++level_;
13421 }
13422
13423 virtual void
13424 visit_end(diff*)
13425 {
13426 --level_;
13427 }
13428
13429 virtual void
13430 visit_begin(corpus_diff*)
13431 {
13432 ++level_;
13433 }
13434
13435 virtual void
13436 visit_end(corpus_diff*)
13437 {
13438 --level_;
13439 }
13440
13441 virtual bool
13442 visit(diff* d, bool pre)
13443 {
13444 if (!pre)
13445 // We are post-visiting the diff node D. Which means, we have
13446 // printed a pretty representation for it already. So do
13447 // nothing now.
13448 return true;
13449
13450 do_indent(level_);
13451 out_ << d->get_pretty_representation();
13452 out_ << "\n";
13453 do_indent(level_);
13454 out_ << "{\n";
13455 do_indent(level_ + 1);
13456 out_ << "category: "<< d->get_category() << "\n";
13457 do_indent(level_ + 1);
13458 out_ << "@: " << std::hex << d << std::dec << "\n";
13459 do_indent(level_ + 1);
13460 out_ << "@-canonical: " << std::hex
13461 << d->get_canonical_diff()
13462 << std::dec << "\n";
13463 do_indent(level_);
13464 out_ << "}\n";
13465
13466 return true;
13467 }
13468
13469 virtual bool
13470 visit(corpus_diff* d, bool pre)
13471 {
13472 if (!pre)
13473 // We are post-visiting the diff node D. Which means, we have
13474 // printed a pretty representation for it already. So do
13475 // nothing now.
13476 return true;
13477
13478 // indent
13479 for (unsigned i = 0; i < level_; ++i)
13480 out_ << ' ';
13481 out_ << d->get_pretty_representation();
13482 out_ << '\n';
13483 return true;
13484 }
13485}; // end struct diff_printer_visitor
13486
13487// </ diff tree printing stuff>
13488
13489/// Emit a textual representation of a @ref diff sub-tree to an
13490/// output stream.
13491///
13492/// @param diff_tree the sub-tree to emit the textual representation
13493/// for.
13494///
13495/// @param out the output stream to emit the textual representation
13496/// for @p diff_tree to.
13497void
13498print_diff_tree(diff* diff_tree, ostream& out)
13499{
13500 diff_node_printer p(out);
13501 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13502 diff_tree->context()->forbid_visiting_a_node_twice(false);
13503 diff_tree->traverse(p);
13504 diff_tree->context()->forbid_visiting_a_node_twice(s);
13505}
13506
13507/// Emit a textual representation of a @ref corpus_diff tree to an
13508/// output stream.
13509///
13510/// @param diff_tree the @ref corpus_diff tree to emit the textual
13511/// representation for.
13512///
13513/// @param out the output stream to emit the textual representation
13514/// for @p diff_tree to.
13515void
13516print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
13517{
13518 diff_node_printer p(out);
13519 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13520 diff_tree->context()->forbid_visiting_a_node_twice(false);
13521 diff_tree->traverse(p);
13522 diff_tree->context()->forbid_visiting_a_node_twice(s);
13523}
13524
13525/// Emit a textual representation of a @ref diff sub-tree to an
13526/// output stream.
13527///
13528/// @param diff_tree the sub-tree to emit the textual representation
13529/// for.
13530///
13531/// @param out the output stream to emit the textual representation
13532/// for @p diff_tree to.
13533void
13535 std::ostream& o)
13536{print_diff_tree(diff_tree.get(), o);}
13537
13538/// Emit a textual representation of a @ref corpus_diff tree to an
13539/// output stream.
13540///
13541/// @param diff_tree the @ref corpus_diff tree to emit the textual
13542/// representation for.
13543///
13544/// @param out the output stream to emit the textual representation
13545/// for @p diff_tree to.
13546void
13548 std::ostream& o)
13549{print_diff_tree(diff_tree.get(), o);}
13550
13551/// Print a given category out to stdout for debuging purposes
13552///
13553/// @param c the category to print to stdout.
13554void
13556{
13557 std::cout << c << std::endl;
13558}
13559
13560// <redundancy_marking_visitor>
13561
13562/// A tree visitor to categorize nodes with respect to the
13563/// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
13564/// present on several spots of the tree) and mark such nodes
13565/// appropriatly. This visitor also takes care of propagating the
13566/// REDUNDANT_CATEGORY of a given node to its parent nodes as
13567/// appropriate.
13568struct redundancy_marking_visitor : public diff_node_visitor
13569{
13570 bool skip_children_nodes_;
13571
13572 redundancy_marking_visitor()
13573 : skip_children_nodes_()
13574 {}
13575
13576 virtual void
13577 visit_begin(diff* d)
13578 {
13579 if (d->to_be_reported())
13580 {
13581 // A diff node that carries a change and that has been already
13582 // traversed elsewhere is considered redundant. So let's mark
13583 // it as such and let's not traverse it; that is, let's not
13584 // visit its children.
13585 if ((d->context()->diff_has_been_visited(d)
13586 || d->get_canonical_diff()->is_traversing())
13587 && d->has_changes())
13588 {
13589 // But if two diff nodes are redundant sibbling that carry
13590 // changes of base types, do not mark them as being
13591 // redundant. This is to avoid marking nodes as redundant
13592 // in this case:
13593 //
13594 // int foo(int a, int b);
13595 // compared with:
13596 // float foo(float a, float b); (in C).
13597 //
13598 // In this case, we want to report all the occurences of
13599 // the int->float change because logically, they are at
13600 // the same level in the diff tree.
13601
13602 bool redundant_with_sibling_node = false;
13603 const diff* p = d->parent_node();
13604
13605 // If this is a child node of a fn_parm_diff, look through
13606 // the fn_parm_diff node to get the function diff node.
13607 if (p && dynamic_cast<const fn_parm_diff*>(p))
13608 p = p->parent_node();
13609
13610 if (p)
13611 for (vector<diff*>::const_iterator s =
13612 p->children_nodes().begin();
13613 s != p->children_nodes().end();
13614 ++s)
13615 {
13616 if (*s == d)
13617 continue;
13618 diff* sib = *s;
13619 // If this is a fn_parm_diff, look through the
13620 // fn_parm_diff node to get at the real type node.
13621 if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
13622 sib = f->type_diff().get();
13623 if (sib == d)
13624 continue;
13625 if (sib->get_canonical_diff() == d->get_canonical_diff()
13626 // Sibbling diff nodes that carry base type
13627 // changes are to be marked as redundant.
13628 && (is_base_diff(sib) || is_distinct_diff(sib)))
13629 {
13630 redundant_with_sibling_node = true;
13631 break;
13632 }
13633 }
13634 if (!redundant_with_sibling_node
13635 // Changes to basic types should never be considered
13636 // redundant. For instance, if a member of integer
13637 // type is changed into a char type in both a struct A
13638 // and a struct B, we want to see both changes.
13640 // The same goes for distinct type changes
13642 // Functions with similar *local* changes are never marked
13643 // redundant because otherwise one could miss important
13644 // similar local changes that are applied to different
13645 // functions.
13647 // Changes involving variadic parameters of functions
13648 // should never be marked redundant because we want to see
13649 // them all.
13652 // If the canonical diff itself has been filtered out,
13653 // then this one is not marked redundant, unless the
13654 // canonical diff was already redundant.
13655 && (!d->get_canonical_diff()->is_filtered_out()
13656 || (d->get_canonical_diff()->get_category()
13658 // If the *same* diff node (not one that is merely
13659 // equivalent to this one) has already been visited
13660 // the do not mark it as beind redundant. It's only
13661 // the other nodes that are equivalent to this one
13662 // that must be marked redundant.
13663 && d->context()->diff_has_been_visited(d) != d
13664 // If the diff node is a function parameter and is not
13665 // a reference/pointer (to a non basic or a non
13666 // distinct type diff) then do not mark it as
13667 // redundant.
13668 //
13669 // Children nodes of base class diff nodes are never
13670 // redundant either, we want to see them all.
13674 {
13676 // As we said in preamble, as this node is marked as
13677 // being redundant, let's not visit its children.
13678 // This is not an optimization; it's needed for
13679 // correctness. In the case of a diff node involving
13680 // a class type that refers to himself, visiting the
13681 // children nodes might cause them to be wrongly
13682 // marked as redundant.
13685 skip_children_nodes_ = true;
13686 }
13687 }
13688 }
13689 else
13690 {
13691 // If the node is not to be reported, do not look at it children.
13693 skip_children_nodes_ = true;
13694 }
13695 }
13696
13697 virtual void
13698 visit_begin(corpus_diff*)
13699 {
13700 }
13701
13702 virtual void
13703 visit_end(diff* d)
13704 {
13705 if (skip_children_nodes_)
13706 // When visiting this node, we decided to skip its children
13707 // node. Now that we are done visiting the node, lets stop
13708 // avoiding the children nodes visiting for the other tree
13709 // nodes.
13710 {
13712 skip_children_nodes_ = false;
13713 }
13714 else
13715 {
13716 // Propagate the redundancy categorization of the children
13717 // nodes to this node. But if this node has local harmful
13718 // changes then it doesn't inherit redundancy from its
13719 // children nodes.
13720 if (!(d->get_category() & REDUNDANT_CATEGORY)
13721 && ((!d->has_local_changes_to_be_reported()
13722 || !is_harmful_category(d->get_local_category()))
13723 // By default, pointer, reference, array and qualified
13724 // types consider that a local changes to their
13725 // underlying type is always a local change for
13726 // themselves.
13727 //
13728 // This is as if those types don't have local changes
13729 // in the same sense as other types. So we always
13730 // propagate redundancy to them, regardless of if they
13731 // have local changes or not.
13732 //
13733 // We also propagate redundancy to typedef types if
13734 // these /only/ carry changes to their underlying
13735 // type.
13736 //
13737 // Note that changes to the underlying type of a
13738 // typedef is considered local of
13739 // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
13740 // typedef itself are considered local of
13741 // LOCAL_NON_TYPE_CHANGE_KIND kind.
13742 || is_pointer_diff(d)
13743 || is_array_diff(d)
13745 // A typedef with local non-type changes should not
13746 // see redundancy propagation from its underlying
13747 // type, otherwise, the non-type change might be
13748 // "suppressed" away.
13749 || (is_typedef_diff(d)
13750 && (!(d->has_local_changes()
13752 // A (member) variable with non-type local changes
13753 // should not see redundacy propagation from its type.
13754 // If redundant local-type changes are carried by its
13755 // type however, then that redundancy is propagated to
13756 // the variable. This is key to keep the redundancy
13757 // consistency in the system; otherwise, a type change
13758 // would be rightfully considered redundant at some
13759 // places but not at others.
13760 || (is_var_diff(d)
13761 && (!(d->has_local_changes()
13763 // A function parameter with non-type local changes
13764 // should not see redundancy propagation either. But
13765 // a function parameter with local type changes can
13766 // definitely be redundant.
13767 || (is_fn_parm_diff(d)
13768 && (!(d->has_local_changes()
13770 ))
13771 {
13772 bool has_non_redundant_child = false;
13773 bool has_non_empty_child = false;
13774 bool is_array_diff_node = is_array_diff(d);
13775 for (vector<diff*>::const_iterator i =
13776 d->children_nodes().begin();
13777 i != d->children_nodes().end();
13778 ++i)
13779 {
13780 if ((*i)->has_changes())
13781 {
13782 // If we are looking at a child node of an array,
13783 // do not take a subrange diff node change into
13784 // account when considering redundancy. In other
13785 // words, a subrange diff node that carries a
13786 // change should not be considered as a non-empty
13787 // child node. This is because we want to report
13788 // all subrange diff node changes and not consider
13789 // them as redundant.
13790 if (!is_array_diff_node || !is_subrange_diff(*i))
13791 has_non_empty_child = true;
13792 // Let's see if the current child node '*i' is
13793 // "non-redundant".
13794 //
13795 // A non-redundant node would be a node that
13796 // carries a change to be reported and has not
13797 // been marked as being redundant.
13798 if ((*i)->to_be_reported()
13799 && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
13800 has_non_redundant_child = true;
13801 }
13802 if (has_non_redundant_child)
13803 break;
13804 }
13805
13806 // A diff node for which at least a child node carries a
13807 // change, and for which all the children are redundant is
13808 // deemed redundant too, unless it has local changes.
13809 if (has_non_empty_child
13810 && !has_non_redundant_child)
13811 d->add_to_category(REDUNDANT_CATEGORY);
13812 }
13813 }
13814 }
13815
13816 virtual void
13817 visit_end(corpus_diff*)
13818 {
13819 }
13820
13821 virtual bool
13822 visit(diff*, bool)
13823 {return true;}
13824
13825 virtual bool
13826 visit(corpus_diff*, bool)
13827 {
13828 return true;
13829 }
13830};// end struct redundancy_marking_visitor
13831
13832/// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13833/// category out of the nodes.
13834struct redundancy_clearing_visitor : public diff_node_visitor
13835{
13836 bool
13837 visit(corpus_diff*, bool)
13838 {return true;}
13839
13840 bool
13841 visit(diff* d, bool)
13842 {
13843 // clear the REDUNDANT_CATEGORY out of the current node.
13844 diff_category c = d->get_category();
13845 c &= ~REDUNDANT_CATEGORY;
13846 d->set_category(c);
13847 return true;
13848 }
13849}; // end struct redundancy_clearing_visitor
13850
13851/// Walk a given @ref diff sub-tree to categorize each of the nodes
13852/// with respect to the REDUNDANT_CATEGORY.
13853///
13854/// @param diff_tree the @ref diff sub-tree to walk.
13855void
13857{
13858 if (diff_tree->context()->show_redundant_changes())
13859 return;
13860 redundancy_marking_visitor v;
13861 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13862 diff_tree->context()->forbid_visiting_a_node_twice(false);
13863 diff_tree->traverse(v);
13864 diff_tree->context()->forbid_visiting_a_node_twice(s);
13865}
13866
13867/// Walk a given @ref diff sub-tree to categorize each of the nodes
13868/// with respect to the REDUNDANT_CATEGORY.
13869///
13870/// @param diff_tree the @ref diff sub-tree to walk.
13871void
13873{categorize_redundancy(diff_tree.get());}
13874
13875/// Walk a given @ref corpus_diff tree to categorize each of the nodes
13876/// with respect to the REDUNDANT_CATEGORY.
13877///
13878/// @param diff_tree the @ref corpus_diff tree to walk.
13879void
13881{
13882 redundancy_marking_visitor v;
13883 diff_tree->context()->forget_visited_diffs();
13884 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13885 diff_tree->context()->forbid_visiting_a_node_twice(false);
13886 diff_tree->traverse(v);
13887 diff_tree->context()->forbid_visiting_a_node_twice(s);
13888}
13889
13890/// Walk a given @ref corpus_diff tree to categorize each of the nodes
13891/// with respect to the REDUNDANT_CATEGORY.
13892///
13893/// @param diff_tree the @ref corpus_diff tree to walk.
13894void
13896{categorize_redundancy(diff_tree.get());}
13897
13898// </redundancy_marking_visitor>
13899
13900/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13901/// out of the category of the nodes.
13902///
13903/// @param diff_tree the @ref diff sub-tree to walk.
13904void
13906{
13907 redundancy_clearing_visitor v;
13908 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13909 diff_tree->context()->forbid_visiting_a_node_twice(false);
13910 diff_tree->traverse(v);
13911 diff_tree->context()->forbid_visiting_a_node_twice(s);
13912 diff_tree->context()->forget_visited_diffs();
13913}
13914
13915/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13916/// out of the category of the nodes.
13917///
13918/// @param diff_tree the @ref diff sub-tree to walk.
13919void
13921{clear_redundancy_categorization(diff_tree.get());}
13922
13923/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13924/// out of the category of the nodes.
13925///
13926/// @param diff_tree the @ref corpus_diff tree to walk.
13927void
13929{
13930 redundancy_clearing_visitor v;
13931 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13932 diff_tree->context()->forbid_visiting_a_node_twice(false);
13933 diff_tree->traverse(v);
13934 diff_tree->context()->forbid_visiting_a_node_twice(s);
13935 diff_tree->context()->forget_visited_diffs();
13936}
13937
13938/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13939/// out of the category of the nodes.
13940///
13941/// @param diff_tree the @ref corpus_diff tree to walk.
13942void
13944{clear_redundancy_categorization(diff_tree.get());}
13945
13946/// Apply the @ref diff tree filters that have been associated to the
13947/// context of the a given @ref corpus_diff tree. As a result, the
13948/// nodes of the @diff tree are going to be categorized into one of
13949/// several of the categories of @ref diff_category.
13950///
13951/// @param diff_tree the @ref corpus_diff instance which @ref diff are
13952/// to be categorized.
13953void
13955{
13956 diff_tree->context()->maybe_apply_filters(diff_tree);
13957 propagate_categories(diff_tree);
13958}
13959
13960/// Test if a diff node represents the difference between a variadic
13961/// parameter type and something else.
13962///
13963/// @param d the diff node to consider.
13964///
13965/// @return true iff @p d is a diff node that represents the
13966/// difference between a variadic parameter type and something else.
13967bool
13969{
13970 if (!d)
13971 return false;
13972
13973 type_base_sptr t = is_type(d->first_subject());
13974 if (t && t->get_environment().is_variadic_parameter_type(t))
13975 return true;
13976
13977 t = is_type(d->second_subject());
13978 if (t && t->get_environment().is_variadic_parameter_type(t))
13979 return true;
13980
13981 return false;
13982}
13983
13984/// Test if a diff node represents the difference between a variadic
13985/// parameter type and something else.
13986///
13987/// @param d the diff node to consider.
13988///
13989/// @return true iff @p d is a diff node that represents the
13990/// difference between a variadic parameter type and something else.
13991bool
13993{return is_diff_of_variadic_parameter_type(d.get());}
13994
13995/// Test if a diff node represents the difference between a variadic
13996/// parameter and something else.
13997///
13998/// @param d the diff node to consider.
13999///
14000/// @return true iff @p d is a diff node that represents the
14001/// difference between a variadic parameter and something else.
14002bool
14004{
14006 dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
14007 return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
14008}
14009
14010/// Test if a diff node represents the difference between a variadic
14011/// parameter and something else.
14012///
14013/// @param d the diff node to consider.
14014///
14015/// @return true iff @p d is a diff node that represents the
14016/// difference between a variadic parameter and something else.
14017bool
14019{return is_diff_of_variadic_parameter(d.get());}
14020
14021/// Test if a diff node represents a diff between two basic types.
14022///
14023/// @param d the diff node to consider.
14024///
14025/// @return true iff @p d is a diff between two basic types.
14026const type_decl_diff*
14028{return dynamic_cast<const type_decl_diff*>(d);}
14029
14030/// Test if a diff node represents a diff between two basic types, or
14031/// between pointers, references or qualified type to basic types.
14032///
14033/// @param diff the diff node to consider.
14034///
14035/// @param allow_indirect_type if true, then this function looks into
14036/// pointer, reference or qualified diff types to see if they "point
14037/// to" basic types.
14038///
14039/// @return true iff @p d is a diff between two basic types.
14040const type_decl_diff*
14041is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
14042{
14043 if (allow_indirect_type)
14046}
14047
14048/// If a diff node is about changes between two typedef types, get the
14049/// diff node about changes between the underlying types.
14050///
14051/// Note that this function walks the tree of underlying diff nodes
14052/// returns the first diff node about types that are not typedefs.
14053///
14054/// @param dif the dif node to consider.
14055///
14056/// @return the underlying diff node of @p dif, or just return @p dif
14057/// if it's not a typedef diff node.
14058const diff*
14060{
14061 const typedef_diff *d = 0;
14062 while ((d = is_typedef_diff(dif)))
14063 dif = d->underlying_type_diff().get();
14064 return dif;
14065}
14066
14067/// If a diff node is about changes between two pointer types, get the
14068/// diff node about changes between the underlying (pointed-to) types.
14069///
14070/// Note that this function walks the tree of underlying diff nodes
14071/// returns the first diff node about types that are not pointers.
14072///
14073/// @param dif the dif node to consider.
14074///
14075/// @return the underlying diff node of @p dif, or just return @p dif
14076/// if it's not a pointer diff node.
14077const diff*
14079{
14080 const pointer_diff *d = 0;
14081 while ((d = is_pointer_diff(dif)))
14082 dif = d->underlying_type_diff().get();
14083 return dif;
14084}
14085
14086/// If a diff node is about changes between two reference types, get
14087/// the diff node about changes between the underlying (pointed-to)
14088/// types.
14089///
14090/// Note that this function walks the tree of underlying diff nodes
14091/// returns the first diff node about types that are not references.
14092///
14093/// @param dif the dif node to consider.
14094///
14095/// @return the underlying diff node of @p dif, or just return @p dif
14096/// if it's not a reference diff node.
14097const diff*
14099{
14100 const reference_diff *d = 0;
14101 while ((d = is_reference_diff(dif)))
14102 dif = d->underlying_type_diff().get();
14103 return dif;
14104}
14105
14106/// If a diff node is about changes between two qualified types, get
14107/// the diff node about changes between the underlying (non-qualified)
14108/// types.
14109///
14110/// Note that this function walks the tree of underlying diff nodes
14111/// returns the first diff node about types that are not qualified.
14112///
14113/// @param dif the dif node to consider.
14114///
14115/// @return the underlying diff node of @p dif, or just return @p dif
14116/// if it's not a qualified diff node.
14117const diff*
14119{
14120 const qualified_type_diff *d = 0;
14121 while ((d = is_qualified_type_diff(dif)))
14122 dif = d->underlying_type_diff().get();
14123 return dif;
14124}
14125
14126/// If a diff node is about changes between two function parameters
14127/// get the diff node about changes between the types of the parameters.
14128///
14129/// @param dif the dif node to consider.
14130///
14131/// @return the diff of the types of the parameters.
14132const diff*
14134{
14135 const fn_parm_diff *d = 0;
14136 while ((d = is_fn_parm_diff(dif)))
14137 dif = d->type_diff().get();
14138 return dif;
14139}
14140
14141/// If a diff node is about changes between two pointer, reference or
14142/// qualified types, get the diff node about changes between the
14143/// underlying types.
14144///
14145/// Note that this function walks the tree of underlying diff nodes
14146/// returns the first diff node about types that are not pointer,
14147/// reference or qualified.
14148///
14149/// @param dif the dif node to consider.
14150///
14151/// @return the underlying diff node of @p dif, or just return @p dif
14152/// if it's not a pointer, reference or qualified diff node.
14153const diff*
14155{
14156 while (true)
14157 {
14158 if (const pointer_diff *d = is_pointer_diff(dif))
14159 dif = peel_pointer_diff(d);
14160 else if (const reference_diff *d = is_reference_diff(dif))
14161 dif = peel_reference_diff(d);
14162 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14163 dif = peel_qualified_diff(d);
14164 else
14165 break;
14166 }
14167 return dif;
14168}
14169
14170/// If a diff node is about changes between two typedefs or qualified
14171/// types, get the diff node about changes between the underlying
14172/// types.
14173///
14174/// Note that this function walks the tree of underlying diff nodes
14175/// returns the first diff node about types that are not typedef or
14176/// qualified types.
14177///
14178/// @param dif the dif node to consider.
14179///
14180/// @return the underlying diff node of @p dif, or just return @p dif
14181/// if it's not typedef or qualified diff node.
14182const diff*
14184{
14185 while (true)
14186 {
14187 if (const typedef_diff *d = is_typedef_diff(dif))
14188 dif = peel_typedef_diff(d);
14189 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14190 dif = peel_qualified_diff(d);
14191 else
14192 break;
14193 }
14194 return dif;
14195}
14196
14197/// If a diff node is about changes between two typedefs or qualified
14198/// types, get the diff node about changes between the underlying
14199/// types.
14200///
14201/// Note that this function walks the tree of underlying diff nodes
14202/// returns the first diff node about types that are neither typedef,
14203/// qualified type nor parameters.
14204///
14205/// @param dif the dif node to consider.
14206///
14207/// @return the diff node about changes between the underlying types.
14208const diff*
14210{
14211 while (true)
14212 {
14213 if (const typedef_diff *d = is_typedef_diff(dif))
14214 dif = peel_typedef_diff(d);
14215 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
14216 dif = peel_qualified_diff(d);
14217 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
14218 dif = peel_fn_parm_diff(d);
14219 else
14220 break;
14221 }
14222 return dif;
14223}
14224
14225/// Test if a diff node represents a diff between two class or union
14226/// types.
14227///
14228/// @param d the diff node to consider.
14229///
14230/// @return iff @p is a diff between two class or union types then
14231/// return the instance of @ref class_or_union_diff that @p derives
14232/// from. Otherwise, return nil.
14235{return dynamic_cast<const class_or_union_diff*>(d);}
14236
14237/// Test if a given diff node carries *only* a local type change.
14238///
14239/// @param d the diff node to consider.
14240///
14241/// @return true iff @p has a change and that change is a local type
14242/// change.
14243static bool
14244has_local_type_change_only(const diff *d)
14245{
14246 if (enum change_kind k = d->has_local_changes())
14247 if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
14248 && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
14249 return true;
14250
14251 return false;
14252}
14253
14254/// Test if a diff node is a decl diff that only carries a basic type
14255/// change on its type diff sub-node.
14256///
14257///Note that that pointers/references/qualified types diffs to basic
14258/// type diffs are considered as having basic type change only.
14259///
14260/// @param d the diff node to consider.
14261///
14262/// @return true iff @p d is a decl diff that only carries a basic
14263/// type change on its type diff sub-node.
14264bool
14266{
14268
14269 if (is_diff_of_basic_type(d, true) && d->has_changes())
14270 return true;
14271 else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
14272 return (has_local_type_change_only(v)
14273 && is_diff_of_basic_type(v->type_diff().get(), true));
14274 else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
14275 return (has_local_type_change_only(p)
14276 && is_diff_of_basic_type(p->type_diff().get(), true));
14277 else if (const function_decl_diff* f =
14278 dynamic_cast<const function_decl_diff*>(d))
14279 return (has_local_type_change_only(f)
14280 && f->type_diff()
14281 && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
14282 true));
14283 return false;
14284}
14285}// end namespace comparison
14286} // 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:1737
#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_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 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 num_func_changed() const
Getter for the number of functions that have a change in one of their sub-types.
size_t num_removed_func_filtered_out() const
Getter for the number of removed functions that have been filtered out.
size_t net_num_vars_added() const
Getter for the net number of added variables.
size_t num_leaf_changes() const
Getter of the number of leaf type change diff nodes.
size_t num_leaf_func_changes_filtered_out() const
Getter for the number of leaf function change diff nodes that were filtered out.
size_t num_added_func_syms_filtered_out() const
Getter for the number of added function symbols, not referenced by any debug info,...
size_t num_leaf_type_changes_filtered_out() const
Getter for the number of filtered out leaf type change diff nodes.
size_t num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from the public interface of the ABI corpu...
size_t net_num_leaf_func_changes() const
Getter for the net number of leaf function change diff nodes.
size_t num_leaf_func_changes() const
Getter for the number of leaf function change diff nodes.
size_t net_num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from public interfaces and that have *NOT*...
size_t num_func_syms_removed() const
Getter for the number of function symbols (not referenced by any debug info) that got removed.
size_t num_leaf_changes_filtered_out() const
Getter of the number of leaf type change diff nodes that have been filtered out.
size_t num_vars_removed() const
Getter for the number of variables removed.
size_t num_var_syms_removed() const
Getter for the number of variable symbols (not referenced by any debug info) that got removed.
size_t 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:22892
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:23228
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.
void apply_filters(corpus_diff_sptr diff_tree)
Apply the diff tree filters that have been associated to the context of the a given corpus_diff tree....
shared_ptr< distinct_diff > distinct_diff_sptr
Convenience typedef for a shared pointer to distinct_types_diff.
shared_ptr< corpus_diff > corpus_diff_sptr
A convenience typedef for a shared pointer to corpus_diff.
std::pair< var_decl_sptr, var_decl_sptr > changed_var_sptr
Convenience typedef for a pair of var_decl_sptr representing a var_decl change. The first member of t...
shared_ptr< typedef_diff > typedef_diff_sptr
Convenience typedef for a shared pointer on a typedef_diff type.
const diff * peel_typedef_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
void sort_enumerators(const string_enumerator_map &enumerators_map, enum_type_decl::enumerators &sorted)
Sort a map of enumerators by their value.
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:10765
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:12141
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:11091
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:11322
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:11041
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:10608
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:20474
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:11985
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition: abg-ir.cc:10705
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition: abg-fwd.h:175
type_base_sptr strip_typedef(const type_base_sptr type)
Recursively returns the the underlying type of a typedef. The return type should not be a typedef of ...
Definition: abg-ir.cc:6780
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:11844
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition: abg-ir.cc:11371
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:28954
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:28524
function_decl * is_function_decl(const type_or_decl_base *d)
Test whether a declaration is a function_decl.
Definition: abg-ir.cc:10653
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:11814
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:11343
bool is_at_global_scope(const decl_base &decl)
Tests whether a given declaration is at global scope.
Definition: abg-ir.cc:10538
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:1681
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:1678
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.