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