libabigail
abg-comparison.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2// -*- Mode: C++ -*-
3//
4// Copyright (C) 2013-2024 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/// Compare two @ref function_decl_diff for the purpose of sorting.
172///
173/// @param first the first @ref function_decl_diff to consider.
174///
175/// @param second the second @ref function_decl_diff to consider.
176///
177/// @return true iff @p first compares less than @p second.
178bool
180{
182 s = second.first_function_decl();
183
184 string fr = f->get_qualified_name(), sr = s->get_qualified_name();
185
186 if (fr != sr)
187 return fr < sr;
188
189 if (!f->get_linkage_name().empty()
190 && !s->get_linkage_name().empty())
191 {
192 fr = f->get_linkage_name();
193 sr = s->get_linkage_name();
194 if (fr != sr)
195 return fr < sr;
196 }
197
198 if (f->get_symbol() && s->get_symbol())
199 {
200 fr = f->get_symbol()->get_id_string();
201 sr = s->get_symbol()->get_id_string();
202 if (fr != sr)
203 return fr < sr;
204 }
205
206 fr = f->get_pretty_representation(true, true);
207 sr = s->get_pretty_representation(true, true);
208
209 return fr < sr;
210}
211
212/// Sort an instance of @ref string_function_ptr_map map and stuff a
213/// resulting sorted vector of pointers to function_decl.
214///
215/// @param map the map to sort.
216///
217/// @param sorted the resulting sorted vector.
218void
220 vector<const function_decl*>& sorted)
221{
222 sorted.reserve(map.size());
223 for (string_function_ptr_map::const_iterator i = map.begin();
224 i != map.end();
225 ++i)
226 sorted.push_back(i->second);
227
228 function_comp comp;
229 std::sort(sorted.begin(), sorted.end(), comp);
230}
231
232/// Sort a map that's an instance of @ref
233/// string_member_function_sptr_map and fill a vector of member
234/// functions with the sorted result.
235///
236/// @param map the map to sort.
237///
238/// @param sorted the resulting sorted vector.
239void
242{
243 sorted.reserve(map.size());
244 for (string_member_function_sptr_map::const_iterator i = map.begin();
245 i != map.end();
246 ++i)
247 sorted.push_back(i->second);
248
249 function_comp comp;
250 std::sort(sorted.begin(), sorted.end(), comp);
251}
252
253/// Sort the values of a @ref string_function_decl_diff_sptr_map map
254/// and store the result in a vector of @ref function_decl_diff_sptr
255/// objects.
256///
257/// @param map the map whose values to store.
258///
259/// @param sorted the vector of function_decl_diff_sptr to store the
260/// result of the sort into.
261void
265{
266 sorted.reserve(map.size());
267 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
268 i != map.end();
269 ++i)
270 sorted.push_back(i->second);
272 std::sort(sorted.begin(), sorted.end(), comp);
273}
274
275/// Sort of an instance of @ref string_var_diff_sptr_map map.
276///
277/// @param map the input map to sort.
278///
279/// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
280/// It's populated with the sorted content.
281void
283 var_diff_sptrs_type& sorted)
284{
285 sorted.reserve(map.size());
286 for (string_var_diff_sptr_map::const_iterator i = map.begin();
287 i != map.end();
288 ++i)
289 sorted.push_back(i->second);
290
292 std::sort(sorted.begin(), sorted.end(), comp);
293}
294
295/// Sort a map of string -> pointer to @ref elf_symbol.
296///
297/// The result is a vector of @ref elf_symbol_sptr sorted by the
298/// name of the symbol.
299///
300/// @param map the map to sort.
301///
302/// @param sorted out parameter; the sorted vector of @ref
303/// elf_symbol_sptr.
304void
306 vector<elf_symbol_sptr>& sorted)
307{
308 for (string_elf_symbol_map::const_iterator i = map.begin();
309 i!= map.end();
310 ++i)
311 sorted.push_back(i->second);
312
313 elf_symbol_comp comp;
314 std::sort(sorted.begin(), sorted.end(), comp);
315}
316
317/// Sort a map of string -> pointer to @ref var_decl.
318///
319/// The result is a vector of var_decl* sorted by the qualified name
320/// of the variables.
321///
322/// @param map the map to sort.
323///
324/// @param sorted out parameter; the sorted vector of @ref var_decl.
325void
327 vector<const var_decl*>& sorted)
328{
329 for (string_var_ptr_map::const_iterator i = map.begin();
330 i != map.end();
331 ++i)
332 sorted.push_back(i->second);
333
334 var_comp comp;
335 std::sort(sorted.begin(), sorted.end(), comp);
336}
337
338/// Sort the values of a string_var_diff_sptr_map and store the result
339/// in a vector of var_diff_sptr.
340///
341/// @param map the map of changed data members to sort.
342///
343/// @param sorted the resulting vector of var_diff_sptr.
344void
346 var_diff_sptrs_type& sorted)
347{
348 sorted.reserve(map.size());
349 for (string_var_diff_sptr_map::const_iterator i = map.begin();
350 i != map.end();
351 ++i)
352 sorted.push_back(i->second);
354 std::sort(sorted.begin(), sorted.end(), comp);
355}
356
357/// Sort the values of a unsigned_var_diff_sptr_map map and store the
358/// result into a vector of var_diff_sptr.
359///
360/// @param map the map of changed data members to sort.
361///
362/// @param sorted the resulting vector of sorted var_diff_sptr.
363void
365 var_diff_sptrs_type& sorted)
366{
367 sorted.reserve(map.size());
368 for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
369 i != map.end();
370 ++i)
371 sorted.push_back(i->second);
373 std::sort(sorted.begin(), sorted.end(), comp);
374}
375
376/// Sort an map of string -> virtual member function into a vector of
377/// virtual member functions. The virtual member functions are sorted
378/// by increasing order of their virtual index.
379///
380/// @param map the input map.
381///
382/// @param sorted the resulting sorted vector of virtual function
383/// member.
384void
388{
389 sorted.reserve(map.size());
390 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
391 i != map.end();
392 ++i)
393 sorted.push_back(i->second);
394
396 sort(sorted.begin(), sorted.end(), comp);
397}
398
399/// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
400/// diff_sptr. The diff_sptr are sorted lexicographically wrt
401/// qualified names of their first subjects.
402///
403/// @param map the map to sort.
404///
405/// @param sorted the resulting sorted vector.
406void
408 diff_sptrs_type& sorted)
409{
410 sorted.reserve(map.size());
411 for (string_diff_sptr_map::const_iterator i = map.begin();
412 i != map.end();
413 ++i)
414 sorted.push_back(i->second);
415
416 diff_comp comp;
417 sort(sorted.begin(), sorted.end(), comp);
418}
419
420/// Sort a map ofg string -> @ref diff* into a vector of @ref
421/// diff_ptr. The diff_ptr are sorted lexicographically wrt
422/// qualified names of their first subjects.
423///
424/// @param map the map to sort.
425///
426/// @param sorted the resulting sorted vector.
427void
429 diff_ptrs_type& sorted)
430{
431 sorted.reserve(map.size());
432 for (string_diff_ptr_map::const_iterator i = map.begin();
433 i != map.end();
434 ++i)
435 sorted.push_back(i->second);
436
437 diff_comp comp;
438 sort(sorted.begin(), sorted.end(), comp);
439}
440
441/// Sort a map of string -> base_diff_sptr into a sorted vector of
442/// base_diff_sptr. The base_diff_sptr are sorted by increasing value
443/// of their offset in their containing type.
444///
445/// @param map the input map to sort.
446///
447/// @param sorted the resulting sorted vector.
448void
450 base_diff_sptrs_type& sorted)
451{
452 for (string_base_diff_sptr_map::const_iterator i = map.begin();
453 i != map.end();
454 ++i)
455 sorted.push_back(i->second);
456 base_diff_comp comp;
457 sort(sorted.begin(), sorted.end(), comp);
458}
459
460/// Lexicographically sort base specifications found
461/// in instances of string_base_sptr_map.
462void
465{
466 for (string_base_sptr_map::const_iterator i = m.begin();
467 i != m.end();
468 ++i)
469 sorted.push_back(i->second);
470
471 base_spec_comp comp;
472 std::sort(sorted.begin(), sorted.end(), comp);
473}
474
475/// Sort a map of @ref fn_parm_diff by the indexes of the function
476/// parameters.
477///
478/// @param map the map to sort.
479///
480/// @param sorted the resulting sorted vector of changed function
481/// parms.
482void
484 vector<fn_parm_diff_sptr>& sorted)
485{
486 sorted.reserve(map.size());
487 for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
488 i != map.end();
489 ++i)
490 sorted.push_back(i->second);
491
493 std::sort(sorted.begin(), sorted.end(), comp);
494}
495
496/// Sort a map of changed function parameters by the indexes of the
497/// function parameters.
498///
499/// @param map the map to sort.
500///
501/// @param sorted the resulting sorted vector of instances of @ref
502/// fn_parm_diff_sptr
503void
505 vector<fn_parm_diff_sptr>& sorted)
506{
507 sorted.reserve(map.size());
508 for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
509 i != map.end();
510 ++i)
511 sorted.push_back(i->second);
512
514 std::sort(sorted.begin(), sorted.end(), comp);
515}
516
517/// Sort a map of string -> function parameters.
518///
519/// @param map the map to sort.
520///
521/// @param sorted the resulting sorted vector of
522/// @ref vector<function_decl::parameter_sptr>
523void
525 vector<function_decl::parameter_sptr>& sorted)
526{
527 for (string_parm_map::const_iterator i = map.begin();
528 i != map.end();
529 ++i)
530 sorted.push_back(i->second);
531
532 parm_comp comp;
533 std::sort(sorted.begin(), sorted.end(), comp);
534}
535
536/// Sort the set of ABI artifacts contained in a @ref
537/// artifact_sptr_set_type.
538///
539/// @param set the set of ABI artifacts to sort.
540///
541/// @param output parameter the vector containing the sorted ABI
542/// artifacts.
543void
545 vector<type_or_decl_base_sptr>& sorted)
546{
547
548 for (artifact_sptr_set_type::const_iterator it = set.begin();
549 it != set.end();
550 ++it)
551 sorted.push_back(*it);
552
554 std::sort(sorted.begin(), sorted.end(), comp);
555}
556
557/// Sort a map of string to type_base_sptr entities.
558///
559/// The entries are sorted based on the lexicographic order of the
560/// pretty representation of the type_sptr_sptr. The sorted result is
561/// put in a vector of type_base_sptr.
562///
563/// @param map the map to sort.
564///
565/// @param sorted the resulting vector of type_base_sptr
566/// lexicographically sorted using their pretty representation.
567void
569 vector<type_base_sptr>& sorted)
570{
571 for (string_type_base_sptr_map::const_iterator i = map.begin();
572 i != map.end();
573 ++i)
574 sorted.push_back(i->second);
575
577 std::sort(sorted.begin(), sorted.end(), comp);
578}
579
580/// Return the first underlying type that is not a qualified type.
581/// @param t the qualified type to consider.
582///
583/// @return the first underlying type that is not a qualified type, or
584/// NULL if t is NULL.
585type_base_sptr
586get_leaf_type(qualified_type_def_sptr t)
587{
588 if (!t)
589 return type_base_sptr();
590
591 type_base_sptr ut = t->get_underlying_type();
592 qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
593
594 if (!qut)
595 return ut;
596 return get_leaf_type(qut);
597}
598
599/// Tests if a given diff node is to represent the changes between two
600/// gobal decls.
601///
602/// @param d the diff node to consider.
603///
604/// @return true iff @p d represents the changes between two global
605/// decls.
606bool
608{
609 ABG_ASSERT(d != 0);
610
611 if (d == 0)
612 return false;
613
615 ABG_ASSERT(first);
616
618 ABG_ASSERT(second);
619
620 if (decl_base_sptr decl = is_decl(first))
621 if (is_at_global_scope(decl))
622 if ((decl = is_decl(second)))
623 if (is_at_global_scope(decl))
624 return true;
625
626 return false;
627}
628
629// -----------------------------------------
630// </private functions re-usable elsewhere>
631// -----------------------------------------
632
633/// The overloaded or operator for @ref visiting_kind.
636{return static_cast<visiting_kind>(static_cast<unsigned>(l)
637 | static_cast<unsigned>(r));}
638
639/// The overloaded and operator for @ref visiting_kind.
642{
643 return static_cast<visiting_kind>(static_cast<unsigned>(l)
644 & static_cast<unsigned>(r));
645}
646
647/// The overloaded 'bit inversion' operator for @ref visiting_kind.
650{return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
651
652/// Test if a diff node is about differences between types.
653///
654/// @param diff the diff node to test.
655///
656/// @return a pointer to the actual type_diff_base* that @p diff
657/// extends, iff it is about differences between types.
658const type_diff_base*
660{return dynamic_cast<const type_diff_base*>(diff);}
661
662/// Test if a diff node is about differences between declarations.
663///
664/// @param diff the diff node to test.
665///
666/// @return a pointer to the actual decl_diff_base @p diff extends,
667/// iff it is about differences between declarations.
668const decl_diff_base*
670{return dynamic_cast<const decl_diff_base*>(diff);}
671
672/// Test if a diff node is a @ref class_diff node.
673///
674/// @param diff the diff node to consider.
675///
676/// @return a non-nil pointer to a @ref class_diff iff @p diff is a
677/// @ref class_diff node.
678const class_diff*
680{return dynamic_cast<const class_diff*>(diff);}
681
682/// Test if a diff node is a @ref enum_diff node.
683///
684/// @param diff the diff node to consider.
685///
686/// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
687/// a @ref enum_diff node.
688const enum_diff*
690{return dynamic_cast<const enum_diff*>(diff);}
691
692/// Test if a diff node is a @ref union_diff node.
693///
694/// @param diff the diff node to consider.
695///
696/// @return a non-nil pointer to a @ref union_diff iff @p diff is a
697/// @ref union_diff node.
698const union_diff*
700{return dynamic_cast<const union_diff*>(diff);}
701
702/// Test if a diff node is a @ref class_or_union_diff node.
703///
704/// @param d the diff node to consider.
705///
706/// @return a non-nil pointer to the @ref class_or_union_diff denoted
707/// by @p d iff @p d is a @ref class_or_union_diff.
710{return dynamic_cast<const class_or_union_diff*>(d);}
711
712/// Test if a diff node is a @ref class_or_union_diff between two
713/// anonymous classes or unions.
714///
715/// @param d the diff node to consider.
716///
717/// @return a non-nil pointer to the @ref class_or_union_diff iff @p
718/// denoted by @p d iff @p is pointer to an anonymous class or union
719/// diff.
722{
724 if (dif->first_class_or_union()->get_is_anonymous())
725 return dif;
726 return 0;
727}
728
729/// Test if a diff node is a @ref typedef_diff node.
730///
731/// @param diff the diff node to consider.
732///
733/// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
734/// @ref typedef_diff node.
735const typedef_diff*
737{return dynamic_cast<const typedef_diff*>(diff);}
738
739/// Test if a diff node is a @ref subrange_diff node.
740///
741/// @param diff the diff node to consider.
742///
743/// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
744/// @ref subrange_diff node.
745const subrange_diff*
747{return dynamic_cast<const subrange_diff*>(diff);}
748
749/// Test if a diff node is a @ref array_diff node.
750///
751/// @param diff the diff node to consider.
752///
753/// @return a non-nil pointer to a @ref array_diff iff @p diff is a
754/// @ref array_diff node.
755const array_diff*
757{return dynamic_cast<const array_diff*>(diff);}
758
759/// Test if a diff node is a @ref function_type_diff node.
760///
761/// @param diff the diff node to consider.
762///
763/// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
764/// @ref function_type_diff node.
767{return dynamic_cast<const function_type_diff*>(diff);}
768
769/// Test if a given diff node carries a function type change with
770/// local changes.
771///
772/// @param diff the diff node to consider.
773///
774/// @return a non-nil pointer to a @ref function_type_diff iff @p diff
775/// is a function_type_diff node that carries a local change.
778{
780 if (d->has_local_changes())
781 return d;
782
783 return 0;
784}
785
786/// Test if a diff node is about differences between variables.
787///
788/// @param diff the diff node to test.
789///
790/// @return a pointer to the actual var_diff that @p diff is a type
791/// of, iff it is about differences between variables.
792const var_diff*
794{
795 const var_diff* d = dynamic_cast<const var_diff*>(diff);
796 if (d)
798 return d;
799}
800
801/// Test if a diff node is about differences between functions.
802///
803/// @param diff the diff node to test.
804///
805/// @return a pointer to the actual var_diff that @p diff is a type
806/// of, iff it is about differences between variables.
809{
810 const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
811 if (d)
813 return d;
814}
815
816/// Test if a diff node is about differences between two pointers.
817///
818/// @param diff the diff node to consider.
819///
820/// @return the @p diff converted into an instance of @ref
821/// pointer_diff iff @p diff is about differences between two
822/// pointers.
823const pointer_diff*
825{return dynamic_cast<const pointer_diff*>(diff);}
826
827/// Test if a diff node is about differences between two references.
828///
829/// @param diff the diff node to consider.
830///
831/// @return the @p diff converted into an instance of @ref
832/// reference_diff iff @p diff is about differences between two
833/// references.
834const reference_diff*
836{return dynamic_cast<const reference_diff*>(diff);}
837
838/// Test if a diff node is about differences between two qualified
839/// types.
840///
841/// @param diff the diff node to consider.
842///
843/// @return @p diff converted into an instance of @ref
844/// qualified_type_diff iff @p diff is about differences between two
845/// qualified types.
848{return dynamic_cast<const qualified_type_diff*>(diff);}
849
850/// Test if a diff node is a reference or pointer diff node to a
851/// change that is neither basic type change nor distinct type change.
852///
853/// Note that this function also works on diffs of typedefs of
854/// reference or pointer.
855///
856/// @param diff the diff node to consider.
857///
858/// @return true iff @p diff is a eference or pointer diff node to a
859/// change that is neither basic type change nor distinct type change.
860bool
862{
864 if (const reference_diff* d = is_reference_diff(diff))
865 {
868 return false;
869 return true;
870 }
871 else if (const pointer_diff *d = is_pointer_diff(diff))
872 {
875 return false;
876 return true;
877 }
878
879 return false;
880}
881
882/// Test if a diff node is about differences between two function
883/// parameters.
884///
885/// @param diff the diff node to consider.
886///
887/// @return the @p diff converted into an instance of @ref
888/// reference_diff iff @p diff is about differences between two
889/// function parameters.
890const fn_parm_diff*
892{return dynamic_cast<const fn_parm_diff*>(diff);}
893
894/// Test if a diff node is about differences between two base class
895/// specifiers.
896///
897/// @param diff the diff node to consider.
898///
899/// @return the @p diff converted into an instance of @ref base_diff
900/// iff @p diff is about differences between two base class
901/// specifiers.
902const base_diff*
904{return dynamic_cast<const base_diff*>(diff);}
905
906/// Test if a diff node is about differences between two diff nodes of
907/// different kinds.
908///
909/// @param diff the diff node to consider.
910///
911/// @return the @p diff converted into an instance of @ref
912/// distintc_diff iff @p diff is about differences between two diff
913/// nodes of different kinds.
914const distinct_diff*
916{return dynamic_cast<const distinct_diff*>(diff);}
917
918/// Test if a diff node is a @ref corpus_diff node.
919///
920/// @param diff the diff node to consider.
921///
922/// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
923/// @ref corpus_diff node.
924const corpus_diff*
926{return dynamic_cast<const corpus_diff*>(diff);}
927
928/// Test if a diff node is a child node of a function parameter diff node.
929///
930/// @param diff the diff node to test.
931///
932/// @return true iff @p diff is a child node of a function parameter
933/// diff node.
934bool
936{return diff && is_fn_parm_diff(diff->parent_node());}
937
938/// Test if a diff node is a child node of a base diff node.
939///
940/// @param diff the diff node to test.
941///
942/// @return true iff @p diff is a child node of a base diff node.
943bool
945{return diff && is_base_diff(diff->parent_node());}
946
947/// The default traverse function.
948///
949/// @return true.
950bool
952{return true;}
953
954diff_context::diff_context()
955 : priv_(new diff_context::priv)
956{
957 // Setup all the diff output filters we have.
959
961 add_diff_filter(f);
962
963 // f.reset(new filtering::harmless_filter);
964 // add_diff_filter(f);
965
966 // f.reset(new filtering::harmful_filter);
967 // add_diff_filter(f);
968}
969
970diff_context::~diff_context() = default;
971
972/// Test if logging was requested.
973///
974/// @return true iff logging was requested.
975bool
977{return priv_->do_log_;}
978
979/// Set logging as requested.
980///
981/// @param f the flag
982void
984{priv_->do_log_ = f;}
985
986/// Set the corpus diff relevant to this context.
987///
988/// @param d the corpus_diff we are interested in.
989void
991{priv_->corpus_diff_ = d;}
992
993/// Get the corpus diff for the current context.
994///
995/// @return the corpus diff of this context.
996const corpus_diff_sptr&
998{return priv_->corpus_diff_;}
999
1000/// Getter for the first corpus of the corpus diff of the current context.
1001///
1002/// @return the first corpus of the corpus diff of the current
1003/// context, if no corpus diff is associated to the context.
1004corpus_sptr
1006{
1007 if (priv_->corpus_diff_)
1008 return priv_->corpus_diff_->first_corpus();
1009 return corpus_sptr();
1010}
1011
1012/// Getter for the second corpus of the corpus diff of the current
1013/// context.
1014///
1015/// @return the second corpus of the corpus diff of the current
1016/// context, if no corpus diff is associated to the context.
1017corpus_sptr
1019{
1020 if (priv_->corpus_diff_)
1021 return priv_->corpus_diff_->second_corpus();
1022 return corpus_sptr();
1023}
1024
1025/// Getter of the reporter to be used in this context.
1026///
1027/// @return the reporter to be used in this context.
1030{
1031 if (!priv_->reporter_)
1032 {
1034 priv_->reporter_.reset(new leaf_reporter);
1035 else
1036 priv_->reporter_.reset(new default_reporter);
1037 }
1038 ABG_ASSERT(priv_->reporter_);
1039 return priv_->reporter_;
1040}
1041
1042/// Setter of the reporter to be used in this context.
1043///
1044/// @param r the reporter to be used in this context.
1045void
1047{priv_->reporter_ = r;}
1048
1049/// Tests if the current diff context already has a diff for two decls.
1050///
1051/// @param first the first decl to consider.
1052///
1053/// @param second the second decl to consider.
1054///
1055/// @return a pointer to the diff for @p first @p second if found,
1056/// null otherwise.
1058diff_context::has_diff_for(const type_or_decl_base_sptr first,
1059 const type_or_decl_base_sptr second) const
1060{
1061 types_or_decls_diff_map_type::const_iterator i =
1062 priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1063 if (i != priv_->types_or_decls_diff_map.end())
1064 return i->second;
1065 return diff_sptr();
1066}
1067
1068/// Tests if the current diff context already has a diff for two types.
1069///
1070/// @param first the first type to consider.
1071///
1072/// @param second the second type to consider.
1073///
1074/// @return a pointer to the diff for @p first @p second if found,
1075/// null otherwise.
1077diff_context::has_diff_for_types(const type_base_sptr first,
1078 const type_base_sptr second) const
1079{return has_diff_for(first, second);}
1080
1081/// Tests if the current diff context already has a given diff.
1082///
1083///@param d the diff to consider.
1084///
1085/// @return a pointer to the diff found for @p d
1086const diff*
1087diff_context::has_diff_for(const diff* d) const
1088{return has_diff_for(d->first_subject(), d->second_subject()).get();}
1089
1090/// Tests if the current diff context already has a given diff.
1091///
1092///@param d the diff to consider.
1093///
1094/// @return a pointer to the diff found for @p d
1096diff_context::has_diff_for(const diff_sptr d) const
1097{return has_diff_for(d->first_subject(), d->second_subject());}
1098
1099/// Getter for the bitmap that represents the set of categories that
1100/// the user wants to see reported.
1101///
1102/// @return a bitmap that represents the set of categories that the
1103/// user wants to see reported.
1106{return priv_->allowed_category_;}
1107
1108/// Setter for the bitmap that represents the set of categories that
1109/// the user wants to see reported.
1110///
1111/// @param c a bitmap that represents the set of categories that the
1112/// user wants to see represented.
1113void
1115{priv_->allowed_category_ = c;}
1116
1117/// Setter for the bitmap that represents the set of categories that
1118/// the user wants to see reported
1119///
1120/// This function perform a bitwise or between the new set of
1121/// categories and the current ones, and then sets the current
1122/// categories to the result of the or.
1123///
1124/// @param c a bitmap that represents the set of categories that the
1125/// user wants to see represented.
1126void
1128{priv_->allowed_category_ = priv_->allowed_category_ | c;}
1129
1130/// Setter for the bitmap that represents the set of categories that
1131/// the user wants to see reported
1132///
1133/// This function actually unsets bits from the current categories.
1134///
1135/// @param c a bitmap that represents the set of categories to unset
1136/// from the current categories.
1137void
1139{priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1140
1141/// Add a diff for two decls to the cache of the current diff_context.
1142///
1143/// Doing this allows to later find the added diff from its two
1144/// subject decls.
1145///
1146/// @param first the first decl to consider.
1147///
1148/// @param second the second decl to consider.
1149///
1150/// @param the diff to add.
1151void
1152diff_context::add_diff(type_or_decl_base_sptr first,
1154 const diff_sptr d)
1155{priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1156
1157/// Add a diff tree node to the cache of the current diff_context
1158///
1159/// @param d the diff tree node to add.
1160void
1161diff_context::add_diff(const diff* d)
1162{
1163 if (d)
1164 {
1165 diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1166 add_diff(d->first_subject(), d->second_subject(), dif);
1167 }
1168}
1169
1170/// Add a diff tree node to the cache of the current diff_context
1171///
1172/// @param d the diff tree node to add.
1173void
1174diff_context::add_diff(const diff_sptr d)
1175{
1176 if (d)
1177 add_diff(d->first_subject(), d->second_subject(), d);
1178}
1179
1180/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1181/// @ref diff represented by their two subjects.
1182///
1183/// @param first the first subject of the diff.
1184///
1185/// @param second the second subject of the diff.
1186///
1187/// @return the canonical diff for the diff node represented by the
1188/// two diff subjects @p first and @p second. If no canonical diff
1189/// node was registered for these subjects, then a nil node is
1190/// returned.
1193 const type_or_decl_base_sptr second) const
1194{return has_diff_for(first, second);}
1195
1196/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1197/// @ref diff represented by the two subjects of a given diff node.
1198///
1199/// @param d the diff node to get the canonical node for.
1200///
1201/// @return the canonical diff for the diff node represented by the
1202/// two diff subjects of @p d. If no canonical diff node was
1203/// registered for these subjects, then a nil node is returned.
1206{return has_diff_for(d);}
1207
1208/// Setter for the @ref CanonicalDiff "canonical diff node" for the
1209/// @ref diff represented by their two subjects.
1210///
1211/// @param first the first subject of the diff.
1212///
1213/// @param second the second subject of the diff.
1214///
1215/// @param d the new canonical diff.
1216void
1217diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1218 const type_or_decl_base_sptr second,
1219 const diff_sptr d)
1220{
1221 ABG_ASSERT(d);
1222 if (!has_diff_for(first, second))
1223 {
1224 add_diff(first, second, d);
1225 priv_->canonical_diffs.push_back(d);
1226 }
1227}
1228
1229/// If there is is a @ref CanonicalDiff "canonical diff node"
1230/// registered for two diff subjects, return it. Otherwise, register
1231/// a canonical diff node for these two diff subjects and return it.
1232///
1233/// @param first the first subject of the diff.
1234///
1235/// @param second the second subject of the diff.
1236///
1237/// @param d the new canonical diff node.
1238///
1239/// @return the canonical diff node.
1241diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1242 const type_or_decl_base_sptr second,
1243 const diff_sptr canonical_diff)
1244{
1245 ABG_ASSERT(canonical_diff);
1246
1247 diff_sptr canonical = get_canonical_diff_for(first, second);
1248 if (!canonical)
1249 {
1250 canonical = canonical_diff;
1251 set_canonical_diff_for(first, second, canonical);
1252 }
1253 return canonical;
1254}
1255
1256/// Set the canonical diff node property of a given diff node
1257/// appropriately.
1258///
1259/// For a given diff node that has no canonical diff node, retrieve
1260/// the canonical diff node (by looking at its diff subjects and at
1261/// the current context) and set the canonical diff node property of
1262/// the diff node to that canonical diff node. If no canonical diff
1263/// node has been registered to the diff context for the subjects of
1264/// the diff node then, register the canonical diff node as being the
1265/// diff node itself; and set its canonical diff node property as
1266/// such. Otherwise, if the diff node already has a canonical diff
1267/// node, do nothing.
1268///
1269/// @param diff the diff node to initialize the canonical diff node
1270/// property for.
1271void
1273{
1274 if (diff->get_canonical_diff() == 0)
1275 {
1276 diff_sptr canonical =
1277 set_or_get_canonical_diff_for(diff->first_subject(),
1279 diff);
1280 diff->set_canonical_diff(canonical.get());
1281 }
1282}
1283
1284/// Add a diff node to the set of diff nodes that are kept alive for
1285/// the life time of the current instance of diff_context.
1286///
1287/// Note that diff added to the diff cache are kept alive as well, and
1288/// don't need to be passed to this function to be kept alive.
1289///
1290/// @param d the diff node to be kept alive during the life time of
1291/// the current instance of @ref diff_context.
1292void
1294{priv_->live_diffs_.insert(d);}
1295
1296/// Test if a diff node has been traversed.
1297///
1298/// @param d the diff node to consider.
1299///
1300/// @return the first diff node against which @p d is redundant.
1301diff*
1303{
1304 const diff* canonical = d->get_canonical_diff();
1305 ABG_ASSERT(canonical);
1306
1307 size_t ptr_value = reinterpret_cast<size_t>(canonical);
1308 pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1309 if (it != priv_->visited_diff_nodes_.end())
1310 return reinterpret_cast<diff*>(it->second);
1311 else
1312 return 0;
1313}
1314
1315/// Test if a diff node has been traversed.
1316///
1317/// @param d the diff node to consider.
1318///
1319/// @return the first diff node against which @p d is redundant.
1322{
1324 return diff;
1325}
1326
1327/// Mark a diff node as traversed by a traversing algorithm.
1328///
1329/// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1330/// node that is marked as traversed.
1331///
1332/// Subsequent invocations of diff_has_been_visited() on the diff node
1333/// will yield true.
1334void
1336{
1337 if (diff_has_been_visited(d))
1338 return;
1339
1340 const diff* canonical = d->get_canonical_diff();
1341 ABG_ASSERT(canonical);
1342
1343 size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1344 size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1345 priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1346}
1347
1348/// Unmark all the diff nodes that were marked as being traversed.
1349void
1351{priv_->visited_diff_nodes_.clear();}
1352
1353/// This sets a flag that, if it's true, then during the traversing of
1354/// a diff nodes tree each node is visited at most once.
1355///
1356/// @param f if true then during the traversing of a diff nodes tree
1357/// each node is visited at most once.
1358///
1359void
1361{priv_->forbid_visiting_a_node_twice_ = f;}
1362
1363/// This function sets a flag os that if @ref
1364/// forbid_visiting_a_node_twice() returns true, then each time the
1365/// node visitor starts visiting a new interface, it resets the
1366/// memory the systems has about already visited node.
1367///
1368/// @param f the flag to set.
1369void
1371{priv_->reset_visited_diffs_for_each_interface_ = f;}
1372
1373/// Return a flag that, if true, then during the traversing of a diff
1374/// nodes tree each node is visited at most once.
1375///
1376/// @return the boolean flag.
1377bool
1379{return priv_->forbid_visiting_a_node_twice_;}
1380
1381/// Return a flag that, if true, then during the traversing of a diff
1382/// nodes tree each node is visited at most once, while visiting the
1383/// diff tree underneath a given interface (public function or
1384/// variable). Each time a new interface is visited, the nodes
1385/// visited while visiting previous interfaces can be visited again.
1386///
1387/// @return the boolean flag.
1388///
1389/// @return the boolean flag.
1390bool
1392{
1393 return (priv_->forbid_visiting_a_node_twice_
1394 && priv_->reset_visited_diffs_for_each_interface_);
1395}
1396
1397/// Getter for the diff tree nodes filters to apply to diff sub-trees.
1398///
1399/// @return the vector of tree filters to apply to diff sub-trees.
1400const filtering::filters&
1402{return priv_->filters_;}
1403
1404/// Setter for the diff filters to apply to a given diff sub-tree.
1405///
1406/// @param f the new diff filter to add to the vector of diff filters
1407/// to apply to diff sub-trees.
1408void
1410{priv_->filters_.push_back(f);}
1411
1412/// Apply the diff filters to a given diff sub-tree.
1413///
1414/// If the current context is instructed to filter out some categories
1415/// then this function walks the given sub-tree and categorizes its
1416/// nodes by using the filters held by the context.
1417///
1418/// @param diff the diff sub-tree to apply the filters to.
1419void
1421{
1422 if (!diff)
1423 return;
1424
1425 if (!diff->has_changes())
1426 return;
1427
1428 for (filtering::filters::const_iterator i = diff_filters().begin();
1429 i != diff_filters().end();
1430 ++i)
1431 {
1433 if (do_log())
1434 {
1435 std::cerr << "applying a filter to diff '"
1437 << "'...\n";
1438 t.start();
1439 }
1440
1442
1443 if (do_log())
1444 {
1445 t.stop();
1446 std::cerr << "filter applied!:" << t << "\n";
1447
1448 std::cerr << "propagating categories for the same diff node ... \n";
1449 t.start();
1450 }
1451
1453
1454 if (do_log())
1455 {
1456 t.stop();
1457 std::cerr << "category propagated!: " << t << "\n";
1458 }
1459 }
1460
1461 }
1462
1463/// Apply the diff filters to the diff nodes of a @ref corpus_diff
1464/// instance.
1465///
1466/// If the current context is instructed to filter out some categories
1467/// then this function walks the diff tree and categorizes its nodes
1468/// by using the filters held by the context.
1469///
1470/// @param diff the corpus diff to apply the filters to.
1471void
1473{
1474
1475 if (!diff || !diff->has_changes())
1476 return;
1477
1478 for (filtering::filters::const_iterator i = diff_filters().begin();
1479 i != diff_filters().end();
1480 ++i)
1481 {
1484 }
1485}
1486
1487/// Getter for the vector of suppressions that specify which diff node
1488/// reports should be dropped on the floor.
1489///
1490/// @return the set of suppressions.
1491const suppressions_type&
1493{return priv_->suppressions_;}
1494
1495/// Getter for the vector of suppressions that specify which diff node
1496/// reports should be dropped on the floor.
1497///
1498/// @return the set of suppressions.
1501{
1502 // Invalidate negated and direct suppressions caches that are built
1503 // from priv_->suppressions_;
1504 priv_->negated_suppressions_.clear();
1505 priv_->direct_suppressions_.clear();
1506 return priv_->suppressions_;
1507}
1508
1509/// Getter of the negated suppression specifications that are
1510/// comprised in the general vector of suppression specifications
1511/// returned by diff_context::suppressions().
1512///
1513/// Note that the first invocation of this function scans the vector
1514/// returned by diff_context::suppressions() and caches the negated
1515/// suppressions from there.
1516///
1517/// Subsequent invocations of this function just return the cached
1518/// negated suppressions.
1519///
1520/// @return the negated suppression specifications stored in this diff
1521/// context.
1524{
1525 if (priv_->negated_suppressions_.empty())
1526 for (auto s : suppressions())
1528 priv_->negated_suppressions_.push_back(s);
1529
1530 return priv_->negated_suppressions_;
1531}
1532
1533/// Getter of the direct suppression specification (those that are
1534/// not negated) comprised in the general vector of suppression
1535/// specifications returned by diff_context::suppression().
1536///
1537/// Note that the first invocation of this function scans the vector
1538/// returned by diff_context::suppressions() and caches the direct
1539/// suppressions from there.
1540///
1541/// Subsequent invocations of this function just return the cached
1542/// direct suppressions.
1543///
1544/// @return the direct suppression specifications.
1547{
1548 if (priv_->direct_suppressions_.empty())
1549 {
1550 for (auto s : suppressions())
1551 if (!is_negated_suppression(s))
1552 priv_->direct_suppressions_.push_back(s);
1553 }
1554 return priv_->direct_suppressions_;
1555}
1556
1557/// Add a new suppression specification that specifies which diff node
1558/// reports should be dropped on the floor.
1559///
1560/// @param suppr the new suppression specification to add to the
1561/// existing set of suppressions specifications of the diff context.
1562void
1564{
1565 priv_->suppressions_.push_back(suppr);
1566 // Invalidate negated and direct suppressions caches that are built
1567 // from priv_->suppressions_;
1568 priv_->negated_suppressions_.clear();
1569 priv_->direct_suppressions_.clear();
1570}
1571
1572/// Add new suppression specifications that specify which diff node
1573/// reports should be dropped on the floor.
1574///
1575/// @param supprs the new suppression specifications to add to the
1576/// existing set of suppression specifications of the diff context.
1577void
1579{
1580 priv_->suppressions_.insert(priv_->suppressions_.end(),
1581 supprs.begin(), supprs.end());
1582}
1583
1584/// Test if it's requested to perform diff node categorization.
1585///
1586/// @return true iff it's requested to perform diff node
1587/// categorization.
1588bool
1590{return priv_->perform_change_categorization_;}
1591
1592/// Request change categorization or not.
1593///
1594/// @param f true iff change categorization is requested.
1595void
1597{priv_->perform_change_categorization_ = f;}
1598
1599/// Set the flag that indicates if the diff using this context should
1600/// show only leaf changes or not.
1601///
1602/// @param f the new value of the flag that indicates if the diff
1603/// using this context should show only leaf changes or not.
1604void
1606{
1607 // This function can be called only if the reporter hasn't yet been
1608 // created. Once it's been created, we are supposed to live with
1609 // it.
1610 ABG_ASSERT(priv_->reporter_ == 0);
1611 priv_->leaf_changes_only_ = f;
1612}
1613
1614/// Get the flag that indicates if the diff using this context should
1615/// show only leaf changes or not.
1616///
1617/// @return the value of the flag that indicates if the diff using
1618/// this context should show only leaf changes or not.
1619bool
1621{return priv_->leaf_changes_only_;}
1622
1623/// Get the flag that indicates if the diff reports using this context
1624/// should show sizes and offsets in an hexadecimal base or not. If
1625/// not, then they are to be shown in a decimal base.
1626///
1627/// @return true iff sizes and offsets are to be shown in an
1628/// hexadecimal base.
1629bool
1631{return priv_->hex_values_;}
1632
1633/// Set the flag that indicates if diff reports using this context
1634/// should show sizes and offsets in an hexadecimal base or not. If
1635/// not, then they are to be shown in a decimal base.
1636///
1637/// @param f if true then sizes and offsets are to be shown in an
1638/// hexadecimal base.
1639void
1641{priv_->hex_values_ = f;}
1642
1643/// Get the flag that indicates if diff reports using this context
1644/// should show sizes and offsets in bits, rather than bytes.
1645///
1646/// @return true iff sizes and offsets are to be shown in bits.
1647/// Otherwise they are to be shown in bytes.
1648bool
1650{return priv_->show_offsets_sizes_in_bits_;}
1651
1652/// Set the flag that indicates if diff reports using this context
1653/// should show sizes and offsets in bits, rather than bytes.
1654///
1655/// @param f if true then sizes and offsets are to be shown in bits.
1656/// Otherwise they are to be shown in bytes.
1657void
1659{priv_->show_offsets_sizes_in_bits_ = f;}
1660
1661/// Set a flag saying if offset changes should be reported in a
1662/// relative way. That is, if the report should say how of many bits
1663/// a class/struct data member did move.
1664///
1665/// @param f the new boolean value of the flag.
1666void
1668{priv_->show_relative_offset_changes_ = f;}
1669
1670/// Get the flag saying if offset changes should be reported in a
1671/// relative way. That is, if the report should say how of many bits
1672/// a class/struct data member did move.
1673///
1674/// @return the boolean value of the flag.
1675bool
1677{return priv_->show_relative_offset_changes_;}
1678
1679/// Set a flag saying if the comparison module should only show the
1680/// diff stats.
1681///
1682/// @param f the flag to set.
1683void
1685{priv_->show_stats_only_ = f;}
1686
1687/// Test if the comparison module should only show the diff stats.
1688///
1689/// @return true if the comparison module should only show the diff
1690/// stats, false otherwise.
1691bool
1693{return priv_->show_stats_only_;}
1694
1695/// Setter for the property that says if the comparison module should
1696/// show the soname changes in its report.
1697///
1698/// @param f the new value of the property.
1699void
1701{priv_->show_soname_change_ = f;}
1702
1703/// Getter for the property that says if the comparison module should
1704/// show the soname changes in its report.
1705///
1706/// @return the value of the property.
1707bool
1709{return priv_->show_soname_change_;}
1710
1711/// Setter for the property that says if the comparison module should
1712/// show the architecture changes in its report.
1713///
1714/// @param f the new value of the property.
1715void
1717{priv_->show_architecture_change_ = f;}
1718
1719/// Getter for the property that says if the comparison module should
1720/// show the architecture changes in its report.
1721///
1722/// @return the value of the property.
1723bool
1725{return priv_->show_architecture_change_;}
1726
1727/// Set a flag saying to show the deleted functions.
1728///
1729/// @param f true to show deleted functions.
1730void
1732{priv_->show_deleted_fns_ = f;}
1733
1734/// @return true if we want to show the deleted functions, false
1735/// otherwise.
1736bool
1738{return priv_->show_deleted_fns_;}
1739
1740/// Set a flag saying to show the changed functions.
1741///
1742/// @param f true to show the changed functions.
1743void
1745{priv_->show_changed_fns_ = f;}
1746
1747/// @return true if we want to show the changed functions, false otherwise.
1748bool
1750{return priv_->show_changed_fns_;}
1751
1752/// Set a flag saying to show the added functions.
1753///
1754/// @param f true to show the added functions.
1755void
1757{priv_->show_added_fns_ = f;}
1758
1759/// @return true if we want to show the added functions, false
1760/// otherwise.
1761bool
1763{return priv_->show_added_fns_;}
1764
1765/// Set a flag saying to show the deleted variables.
1766///
1767/// @param f true to show the deleted variables.
1768void
1770{priv_->show_deleted_vars_ = f;}
1771
1772/// @return true if we want to show the deleted variables, false
1773/// otherwise.
1774bool
1776{return priv_->show_deleted_vars_;}
1777
1778/// Set a flag saying to show the changed variables.
1779///
1780/// @param f true to show the changed variables.
1781void
1783{priv_->show_changed_vars_ = f;}
1784
1785/// @return true if we want to show the changed variables, false otherwise.
1786bool
1788{return priv_->show_changed_vars_;}
1789
1790/// Set a flag saying to show the added variables.
1791///
1792/// @param f true to show the added variables.
1793void
1795{priv_->show_added_vars_ = f;}
1796
1797/// @return true if we want to show the added variables, false
1798/// otherwise.
1799bool
1801{return priv_->show_added_vars_;}
1802
1803bool
1804diff_context::show_linkage_names() const
1805{return priv_->show_linkage_names_;}
1806
1807void
1808diff_context::show_linkage_names(bool f)
1809{priv_->show_linkage_names_= f;}
1810
1811/// Set a flag saying to show location information.
1812///
1813/// @param f true to show location information.
1814void
1816{priv_->show_locs_= f;}
1817
1818/// @return true if we want to show location information, false
1819/// otherwise.
1820bool
1822{return priv_->show_locs_;}
1823
1824/// A getter for the flag that says if we should report about
1825/// functions or variables diff nodes that have *exclusively*
1826/// redundant diff tree children nodes.
1827///
1828/// @return the flag.
1829bool
1831{return priv_->show_redundant_changes_;}
1832
1833/// A setter for the flag that says if we should report about
1834/// functions or variables diff nodes that have *exclusively*
1835/// redundant diff tree children nodes.
1836///
1837/// @param f the flag to set.
1838void
1840{priv_->show_redundant_changes_ = f;}
1841
1842/// Getter for the flag that indicates if symbols not referenced by
1843/// any debug info are to be compared and reported about.
1844///
1845/// @return the boolean flag.
1846bool
1848{return priv_->show_syms_unreferenced_by_di_;}
1849
1850/// Setter for the flag that indicates if symbols not referenced by
1851/// any debug info are to be compared and reported about.
1852///
1853/// @param f the new flag to set.
1854void
1856{priv_->show_syms_unreferenced_by_di_ = f;}
1857
1858/// Getter for the flag that indicates if symbols not referenced by
1859/// any debug info and that got added are to be reported about.
1860///
1861/// @return true iff symbols not referenced by any debug info and that
1862/// got added are to be reported about.
1863bool
1865{return priv_->show_added_syms_unreferenced_by_di_;}
1866
1867/// Setter for the flag that indicates if symbols not referenced by
1868/// any debug info and that got added are to be reported about.
1869///
1870/// @param f the new flag that says if symbols not referenced by any
1871/// debug info and that got added are to be reported about.
1872void
1874{priv_->show_added_syms_unreferenced_by_di_ = f;}
1875
1876/// Setter for the flag that indicates if changes on types unreachable
1877/// from global functions and variables are to be reported.
1878///
1879/// @param f if true, then changes on types unreachable from global
1880/// functions and variables are to be reported.
1881void
1883{priv_->show_unreachable_types_ = f;}
1884
1885/// Getter for the flag that indicates if changes on types unreachable
1886/// from global functions and variables are to be reported.
1887///
1888/// @return true iff changes on types unreachable from global
1889/// functions and variables are to be reported.
1890bool
1892{return priv_->show_unreachable_types_;}
1893
1894/// Getter of the flag that indicates if the leaf reporter should
1895/// display a summary of the interfaces impacted by a given leaf
1896/// change or not.
1897///
1898/// @return the flag that indicates if the leaf reporter should
1899/// display a summary of the interfaces impacted by a given leaf
1900/// change or not.
1901bool
1903{return priv_->show_impacted_interfaces_;}
1904
1905/// Setter of the flag that indicates if the leaf reporter should
1906/// display a summary of the interfaces impacted by a given leaf
1907/// change or not.
1908///
1909/// @param f the new value of the flag that indicates if the leaf
1910/// reporter should display a summary of the interfaces impacted by a
1911/// given leaf change or not.
1912void
1914{priv_->show_impacted_interfaces_ = f;}
1915
1916/// Setter for the default output stream used by code of the
1917/// comparison engine. By default the default output stream is a NULL
1918/// pointer.
1919///
1920/// @param o a pointer to the default output stream.
1921void
1923{priv_->default_output_stream_ = o;}
1924
1925/// Getter for the default output stream used by code of the
1926/// comparison engine. By default the default output stream is a NULL
1927/// pointer.
1928///
1929/// @return a pointer to the default output stream.
1930ostream*
1932{return priv_->default_output_stream_;}
1933
1934/// Setter for the errror output stream used by code of the comparison
1935/// engine. By default the error output stream is a NULL pointer.
1936///
1937/// @param o a pointer to the error output stream.
1938void
1940{priv_->error_output_stream_ = o;}
1941
1942/// Getter for the errror output stream used by code of the comparison
1943/// engine. By default the error output stream is a NULL pointer.
1944///
1945/// @return a pointer to the error output stream.
1946ostream*
1948{return priv_->error_output_stream_;}
1949
1950/// Test if the comparison engine should dump the diff tree for the
1951/// changed functions and variables it has.
1952///
1953/// @return true if after the comparison, the engine should dump the
1954/// diff tree for the changed functions and variables it has.
1955bool
1957{return priv_->dump_diff_tree_;}
1958
1959/// Set if the comparison engine should dump the diff tree for the
1960/// changed functions and variables it has.
1961///
1962/// @param f true if after the comparison, the engine should dump the
1963/// diff tree for the changed functions and variables it has.
1964void
1966{priv_->dump_diff_tree_ = f;}
1967
1968/// Emit a textual representation of a diff tree to the error output
1969/// stream of the current context, for debugging purposes.
1970///
1971/// @param d the diff tree to serialize to the error output associated
1972/// to the current instance of @ref diff_context.
1973void
1975{
1976 if (error_output_stream())
1978}
1979
1980/// Emit a textual representation of a @ref corpus_diff tree to the error
1981/// output stream of the current context, for debugging purposes.
1982///
1983/// @param d the @ref corpus_diff tree to serialize to the error
1984/// output associated to the current instance of @ref diff_context.
1985void
1987{
1988 if (error_output_stream())
1990}
1991// </diff_context stuff>
1992
1993// <diff stuff>
1994
1995/// Constructor for the @ref diff type.
1996///
1997/// This constructs a diff between two subjects that are actually
1998/// declarations; the first and the second one.
1999///
2000/// @param first_subject the first decl (subject) of the diff.
2001///
2002/// @param second_subject the second decl (subject) of the diff.
2003diff::diff(type_or_decl_base_sptr first_subject,
2004 type_or_decl_base_sptr second_subject)
2005 : priv_(new priv(first_subject, second_subject,
2008 /*reported_once=*/false,
2009 /*currently_reporting=*/false))
2010{}
2011
2012/// Constructor for the @ref diff type.
2013///
2014/// This constructs a diff between two subjects that are actually
2015/// declarations; the first and the second one.
2016///
2017/// @param first_subject the first decl (subject) of the diff.
2018///
2019/// @param second_subject the second decl (subject) of the diff.
2020///
2021/// @param ctxt the context of the diff. Note that this context
2022/// object must stay alive during the entire life time of the current
2023/// instance of @ref diff. Otherwise, memory corruption issues occur.
2024diff::diff(type_or_decl_base_sptr first_subject,
2025 type_or_decl_base_sptr second_subject,
2026 diff_context_sptr ctxt)
2027 : priv_(new priv(first_subject, second_subject,
2028 ctxt, NO_CHANGE_CATEGORY,
2029 /*reported_once=*/false,
2030 /*currently_reporting=*/false))
2031{}
2032
2033/// Test if logging was requested
2034///
2035/// @return true iff logging was requested.
2036bool
2038{return context()->do_log();}
2039
2040/// Request logging (or not)
2041///
2042/// @param f true iff logging is to be requested.
2043void
2045{context()->do_log(f);}
2046
2047/// Flag a given diff node as being traversed.
2048///
2049/// For certain diff nodes like @ref class_diff, it's important to
2050/// avoid traversing the node again while it's already being
2051/// traversed; otherwise this leads to infinite loops. So the
2052/// diff::begin_traversing() and diff::end_traversing() methods flag a
2053/// given node as being traversed (or not), so that
2054/// diff::is_traversing() can tell if the node is being traversed.
2055///
2056/// Note that traversing a node means visiting it *and* visiting its
2057/// children nodes.
2058///
2059/// The canonical node is marked as being traversed too.
2060///
2061/// These functions are called by the traversing code.
2062void
2064{
2066 if (priv_->canonical_diff_)
2067 priv_->canonical_diff_->priv_->traversing_ = true;
2068 priv_->traversing_ = true;
2069}
2070
2071/// Tell if a given node is being traversed or not.
2072///
2073/// Note that traversing a node means visiting it *and* visiting its
2074/// children nodes.
2075///
2076/// It's the canonical node which is looked at, actually.
2077///
2078/// Please read the comments for the diff::begin_traversing() for mode
2079/// context.
2080///
2081/// @return true if the current instance of @diff is being traversed.
2082bool
2084{
2085 if (priv_->canonical_diff_)
2086 return priv_->canonical_diff_->priv_->traversing_;
2087 return priv_->traversing_;
2088}
2089
2090/// Flag a given diff node as not being traversed anymore.
2091///
2092/// Note that traversing a node means visiting it *and* visiting its
2093/// children nodes.
2094///
2095/// Please read the comments of the function diff::begin_traversing()
2096/// for mode context.
2097void
2099{
2101 if (priv_->canonical_diff_)
2102 priv_->canonical_diff_->priv_->traversing_ = false;
2103 priv_->traversing_ = false;
2104}
2105
2106/// Finish the insertion of a diff tree node into the diff graph.
2107///
2108/// This function might be called several times. It must perform the
2109/// insertion only once.
2110///
2111/// For instance, certain kinds of diff tree node have specific
2112/// children nodes that are populated after the constructor of the
2113/// diff tree node has been called. In that case, calling overloads
2114/// of this method ensures that these children nodes are properly
2115/// gathered and setup.
2116void
2118{
2119 if (diff::priv_->finished_)
2120 return;
2122 diff::priv_->finished_ = true;
2123}
2124
2125/// Getter of the first subject of the diff.
2126///
2127/// @return the first subject of the diff.
2130{return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2131
2132/// Getter of the second subject of the diff.
2133///
2134/// @return the second subject of the diff.
2137{return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2138
2139/// Getter for the children nodes of the current @ref diff node.
2140///
2141/// @return a vector of the children nodes.
2142const vector<diff*>&
2144{return priv_->children_;}
2145
2146/// Getter for the parent node of the current @ref diff node.
2147///
2148/// @return the parent node of the current @ref diff node.
2149const diff*
2151{return priv_->parent_;}
2152
2153/// Getter for the canonical diff of the current instance of @ref
2154/// diff.
2155///
2156/// Note that the canonical diff node for the current instanc eof diff
2157/// node must have been set by invoking
2158/// class_diff::initialize_canonical_diff() on the current instance of
2159/// diff node.
2160///
2161/// @return the canonical diff node or null if none was set.
2162diff*
2164{return priv_->canonical_diff_;}
2165
2166/// Setter for the canonical diff of the current instance of @ref
2167/// diff.
2168///
2169/// @param d the new canonical node to set.
2170void
2172{priv_->canonical_diff_ = d;}
2173
2174/// Add a new child node to the vector of children nodes for the
2175/// current @ref diff node.
2176///
2177/// @param d the new child node to add to the children nodes.
2178void
2180{
2181 ABG_ASSERT(d);
2182
2183 // Ensure 'd' is kept alive for the life time of the context of this
2184 // diff.
2185 context()->keep_diff_alive(d);
2186
2187 // Add the underlying pointer of 'd' to the vector of children.
2188 // Note that this vector holds no reference to 'd'. This is to avoid
2189 // reference cycles. The reference to 'd' is held by the context of
2190 // this diff, thanks to the call to context()->keep_diff_alive(d)
2191 // above.
2192 priv_->children_.push_back(d.get());
2193
2194 d->priv_->parent_ = this;
2195}
2196
2197/// Getter of the context of the current diff.
2198///
2199/// @return the context of the current diff.
2202{return priv_->get_context();}
2203
2204/// Setter of the context of the current diff.
2205///
2206/// @param c the new context to set.
2207void
2209{priv_->ctxt_ = c;}
2210
2211/// Tests if we are currently in the middle of emitting a report for
2212/// this diff.
2213///
2214/// @return true if we are currently emitting a report for the
2215/// current diff, false otherwise.
2216bool
2218{
2219 if (priv_->canonical_diff_)
2220 return priv_->canonical_diff_->priv_->currently_reporting_;
2221 return priv_->currently_reporting_;
2222}
2223
2224/// Sets a flag saying if we are currently in the middle of emitting
2225/// a report for this diff.
2226///
2227/// @param f true if we are currently emitting a report for the
2228/// current diff, false otherwise.
2229void
2231{
2232 if (priv_->canonical_diff_)
2233 priv_->canonical_diff_->priv_->currently_reporting_ = f;
2234 priv_->currently_reporting_ = f;
2235}
2236
2237/// Tests if a report has already been emitted for the current diff.
2238///
2239/// @return true if a report has already been emitted for the
2240/// current diff, false otherwise.
2241bool
2243{
2244 ABG_ASSERT(priv_->canonical_diff_);
2245 return priv_->canonical_diff_->priv_->reported_once_;
2246}
2247
2248/// The generic traversing code that walks a given diff sub-tree.
2249///
2250/// Note that there is a difference between traversing a diff node and
2251/// visiting it. Basically, traversing a diff node means visiting it
2252/// and visiting its children nodes too. So one can visit a node
2253/// without traversing it. But traversing a node without visiting it
2254/// is not possible.
2255///
2256/// Note that the insertion of the "generic view" of the diff node
2257/// into the graph being traversed is done "on the fly". The
2258/// insertion of the "typed view" of the diff node into the graph is
2259/// done implicitely. To learn more about the generic and typed view
2260/// of the diff node, please read the introductory comments of the
2261/// @ref diff class.
2262///
2263/// Note that by default this traversing code visits a given class of
2264/// equivalence of a diff node only once. This behaviour can been
2265/// changed by calling
2266/// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2267/// very risky as it might create endless loops while visiting a diff
2268/// tree graph that has changes that refer to themselves; that is,
2269/// diff tree graphs with cycles.
2270///
2271/// When a diff node is encountered, the
2272/// diff_node_visitor::visit_begin() method is invoked on the diff
2273/// node first.
2274///
2275/// If the diff node has already been visited, then
2276/// node_visitor::visit_end() is called on it and the node traversing
2277/// is done; the children of the diff node are not visited in this
2278/// case.
2279///
2280/// If the diff node has *NOT* been visited yet, then the
2281/// diff_node_visitor::visit() method is invoked with it's 'pre'
2282/// argument set to true. Then if the diff_node_visitor::visit()
2283/// returns true, then the children nodes of the diff node are
2284/// visited. Otherwise, no children nodes of the diff node is
2285/// visited and the diff_node_visitor::visit_end() is called.
2286
2287/// After the children nodes are visited (and only if they are
2288/// visited) the diff_node_visitor::visit() method is invoked with
2289/// it's 'pre' argument set to false. And then the
2290/// diff_node_visitor::visit_end() is called.
2291///
2292/// @param v the entity that visits each node of the diff sub-tree.
2293///
2294/// @return true to tell the caller that all of the sub-tree could be
2295/// walked. This instructs the caller to keep walking the rest of the
2296/// tree. Return false otherwise.
2297bool
2299{
2300 // Insert the "generic view" of the diff node into its graph.
2302
2303 v.visit_begin(this);
2304
2305 bool already_visited = false;
2306 if (context()->visiting_a_node_twice_is_forbidden()
2307 && context()->diff_has_been_visited(this))
2308 already_visited = true;
2309
2310 bool mark_visited_nodes_as_traversed =
2312
2313 if (!already_visited && !v.visit(this, /*pre=*/true))
2314 {
2315 v.visit_end(this);
2316 if (mark_visited_nodes_as_traversed)
2317 context()->mark_diff_as_visited(this);
2318 return false;
2319 }
2320
2322 && !is_traversing()
2323 && !already_visited)
2324 {
2326 for (vector<diff*>::const_iterator i = children_nodes().begin();
2327 i != children_nodes().end();
2328 ++i)
2329 {
2330 if (!(*i)->traverse(v))
2331 {
2332 v.visit_end(this);
2333 if (mark_visited_nodes_as_traversed)
2334 context()->mark_diff_as_visited(this);
2336 return false;
2337 }
2338 }
2340 }
2341
2342 if (!v.visit(this, /*pref=*/false))
2343 {
2344 v.visit_end(this);
2345 if (mark_visited_nodes_as_traversed)
2346 context()->mark_diff_as_visited(this);
2347 return false;
2348 }
2349
2350 v.visit_end(this);
2351 if (!already_visited && mark_visited_nodes_as_traversed)
2352 context()->mark_diff_as_visited(this);
2353
2354 return true;
2355}
2356
2357/// Sets a flag saying if a report has already been emitted for the
2358/// current diff.
2359///
2360/// @param f true if a report has already been emitted for the
2361/// current diff, false otherwise.
2362void
2364{
2365 ABG_ASSERT(priv_->canonical_diff_);
2366 priv_->canonical_diff_->priv_->reported_once_ = f;
2367 priv_->reported_once_ = f;
2368}
2369
2370/// Getter for the local category of the current diff tree node.
2371///
2372/// The local category represents the set of categories of a diff
2373/// node, not taking in account the categories inherited from its
2374/// children nodes.
2375///
2376/// @return the local category of the current diff tree node.
2379{return priv_->local_category_;}
2380
2381/// Getter of the category of the class of equivalence of the current
2382/// diff tree node.
2383///
2384/// That is, if the current diff tree node has a canonical node,
2385/// return the category of that canonical node. Otherwise, return the
2386/// category of the current node.
2387///
2388/// @return the category of the class of equivalence of the current
2389/// tree node.
2392{
2393 diff* canonical = get_canonical_diff();
2394 return canonical ? canonical->get_category() : get_category();
2395}
2396
2397/// Getter for the category of the current diff tree node.
2398///
2399/// This category represents the union of the local category and the
2400/// categories inherited from the children diff nodes.
2401///
2402/// @return the category of the current diff tree node.
2405{return priv_->category_;}
2406
2407/// Adds the current diff tree node to an additional set of
2408/// categories. Note that the categories include thoses inherited
2409/// from the children nodes of this diff node.
2410///
2411/// @param c a bit-map representing the set of categories to add the
2412/// current diff tree node to.
2413///
2414/// @return the resulting bit-map representing the categories this
2415/// current diff tree node belongs to, including those inherited from
2416/// its children nodes.
2419{
2420 priv_->category_ = priv_->category_ | c;
2421 return priv_->category_;
2422}
2423
2424/// Adds the current diff tree node to the categories resulting from
2425/// the local changes of the current diff node.
2426///
2427/// @param c a bit-map representing the set of categories to add the
2428/// current diff tree node to.
2429///
2430/// @return the resulting bit-map representing the categories this
2431/// current diff tree node belongs to.
2434{
2435 priv_->local_category_ = priv_->local_category_ | c;
2436 return priv_->local_category_;
2437}
2438
2439/// Adds the current diff tree node to the categories resulting from
2440/// the local and inherited changes of the current diff node.
2441///
2442/// @param c a bit-map representing the set of categories to add the
2443/// current diff tree node to.
2444void
2446{
2448 add_to_category(c);
2449}
2450
2451/// Remove the current diff tree node from an a existing sef of
2452/// categories. The categories include those inherited from the
2453/// children nodes of the current diff node.
2454///
2455/// @param c a bit-map representing the set of categories to add the
2456/// current diff tree node to.
2457///
2458/// @return the resulting bit-map representing the categories this
2459/// current diff tree onde belongs to, including the categories
2460/// inherited from the children nodes of the current diff node.
2463{
2464 priv_->category_ = priv_->category_ & ~c;
2465 return priv_->category_;
2466}
2467
2468/// Remove the current diff tree node from the categories resulting
2469/// from the local changes.
2470///
2471/// @param c a bit-map representing the set of categories to add the
2472/// current diff tree node to.
2473///
2474/// @return the resulting bit-map representing the categories this
2475/// current diff tree onde belongs to.
2478{
2479 priv_->local_category_ = priv_->local_category_ & ~c;
2480 return priv_->local_category_;
2481}
2482
2483/// Set the category of the current @ref diff node. This category
2484/// includes the categories inherited from the children nodes of the
2485/// current diff node.
2486///
2487/// @param c the new category for the current diff node.
2488void
2490{priv_->category_ = c;}
2491
2492/// Set the local category of the current @ref diff node.
2493///
2494/// @param c the new category for the current diff node.
2495void
2497{priv_->local_category_ = c;}
2498
2499/// Test if this diff tree node is to be filtered out for reporting
2500/// purposes.
2501///
2502/// There is a difference between a diff node being filtered out and
2503/// being suppressed. Being suppressed means that there is a
2504/// suppression specification that suppresses the diff node
2505/// specifically. Being filtered out mean the node is either
2506/// suppressed, or it's filtered out because the suppression of a set
2507/// of (children) nodes caused this node to be filtered out as well.
2508/// For instance, if a function diff has all its children diff nodes
2509/// suppressed and if the function diff node carries no local change,
2510/// then the function diff node itself is going to be filtered out.
2511///
2512/// The function tests if the categories of the diff tree node are
2513/// "forbidden" by the context or not.
2514///
2515/// @return true iff the current diff node should NOT be reported.
2516bool
2518{
2519 if (diff * canonical = get_canonical_diff())
2520 if ((canonical->get_category() & SUPPRESSED_CATEGORY
2521 || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2522 && !canonical->is_allowed_by_specific_negated_suppression()
2523 && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2524 && !canonical->has_parent_allowed_by_specific_negated_suppression())
2525 // The canonical type was suppressed either by a user-provided
2526 // suppression specification or by a "private-type" suppression
2527 // specification.. This means all the classes of equivalence of
2528 // that canonical type were suppressed. So this node should be
2529 // filtered out.
2530 return true;
2531 return priv_->is_filtered_out(get_category());
2532}
2533
2534/// Test if this diff tree node is to be filtered out for reporting
2535/// purposes, but by considering only the categories that were *NOT*
2536/// inherited from its children nodes.
2537///
2538/// The function tests if the local categories of the diff tree node
2539/// are "forbidden" by the context or not.
2540///
2541/// @return true iff the current diff node should NOT be reported,
2542/// with respect to its local categories.
2543bool
2545{return priv_->is_filtered_out(get_local_category());}
2546
2547/// Test if this diff tree node is to be filtered out for reporting
2548/// purposes, but without considering the categories that can /force/
2549/// the node to be unfiltered.
2550///
2551/// The function tests if the categories of the diff tree node are
2552/// "forbidden" by the context or not.
2553///
2554/// @return true iff the current diff node should should NOT be
2555/// reported, with respect to the categories that might filter it out
2556/// only.
2557bool
2559{
2564
2565 return priv_->is_filtered_out(c);
2566}
2567
2568/// Test if the current diff node has been suppressed by a
2569/// user-provided suppression specification.
2570///
2571/// @return true if the current diff node has been suppressed by a
2572/// user-provided suppression list.
2573bool
2575{
2576 bool is_private = false;
2577 return is_suppressed(is_private);
2578}
2579
2580/// Test if the current diff node has been suppressed by a
2581/// user-provided suppression specification or by an auto-generated
2582/// "private type" suppression specification.
2583///
2584/// Note that private type suppressions are auto-generated from the
2585/// path to where public headers are, as given by the user.
2586///
2587/// Here is the current algorithm:
2588///
2589/// First, suppress this diff node if it's not matched by any
2590/// negated suppression specifications. If it's not
2591/// suppressed, then suppress it if it's matched by direct
2592/// suppression specifications.
2593///
2594/// @param is_private_type out parameter if the current diff node was
2595/// suppressed because it's a private type then this parameter is set
2596/// to true.
2597///
2598/// @return true if the current diff node has been suppressed by a
2599/// user-provided suppression list.
2600bool
2601diff::is_suppressed(bool &is_private_type) const
2602{
2603 // If there is at least one negated suppression, then suppress the
2604 // current diff node by default ...
2605 bool do_suppress = !context()->negated_suppressions().empty();
2606
2607 // ... unless there is at least one negated suppression that
2608 // specifically asks to keep this diff node around (un-suppressed).
2609 for (auto n : context()->negated_suppressions())
2610 if (!n->suppresses_diff(this))
2611 {
2612 do_suppress = false;
2613 break;
2614 }
2615
2616 // Then walk the set of non-negated, AKA direct, suppressions. If at
2617 // least one suppression suppresses the current diff node then the
2618 // diff node must be suppressed.
2619 for (auto d : context()->direct_suppressions())
2620 if (d->suppresses_diff(this))
2621 {
2622 do_suppress = true;
2624 is_private_type = true;
2625 break;
2626 }
2627
2628 return do_suppress;
2629}
2630
2631/// Test if this diff tree node should be reported.
2632///
2633/// @return true iff the current node should be reported.
2634bool
2636{
2637 if (has_changes() && !is_filtered_out())
2638 return true;
2639 return false;
2640}
2641
2642/// Test if this diff tree node should be reported when considering
2643/// the categories that were *NOT* inherited from its children nodes.
2644///
2645/// @return true iff the current node should be reported.
2646bool
2648{
2649 if (has_local_changes()
2651 return true;
2652 return false;
2653}
2654
2655/// Test if this diff node is allowed (prevented from being
2656/// suppressed) by at least one negated suppression specification.
2657///
2658/// @return true if this diff node is meant to be allowed by at least
2659/// one negated suppression specification.
2660bool
2662{
2663 const suppressions_type& suppressions = context()->suppressions();
2664 for (suppressions_type::const_iterator i = suppressions.begin();
2665 i != suppressions.end();
2666 ++i)
2667 {
2669 && !(*i)->suppresses_diff(this))
2670 return true;
2671 }
2672 return false;
2673}
2674
2675/// Test if the current diff node has a descendant node which is
2676/// specifically allowed by a negated suppression specification.
2677///
2678/// @return true iff the current diff node has a descendant node
2679/// which is specifically allowed by a negated suppression
2680/// specification.
2681bool
2683{
2685 return result;
2686}
2687
2688/// Test if the current diff node has a parent node which is
2689/// specifically allowed by a negated suppression specification.
2690///
2691/// @return true iff the current diff node has a parent node which is
2692/// specifically allowed by a negated suppression specification.
2693bool
2695{
2697 return result;
2698}
2699
2700/// Get a pretty representation of the current @ref diff node.
2701///
2702/// This is suitable for e.g. emitting debugging traces for the diff
2703/// tree nodes.
2704///
2705/// @return the pretty representation of the diff node.
2706const string&
2708{
2709 if (priv_->pretty_representation_.empty())
2710 priv_->pretty_representation_ = "empty_diff";
2711 return priv_->pretty_representation_;
2712}
2713
2714/// Default implementation of the hierachy chaining virtual function.
2715///
2716/// There are several types of diff nodes that have logical children
2717/// nodes; for instance, a typedef_diff has the diff of the underlying
2718/// type as a child node. A var_diff has the diff of the types of the
2719/// variables as a child node, etc.
2720///
2721/// But because the @ref diff base has a generic representation for
2722/// children nodes of the all the types of @ref diff nodes (regardless
2723/// of the specific most-derived type of diff node) that one can get
2724/// using the method diff::children_nodes(), one need to populate that
2725/// vector of children node.
2726///
2727/// Populating that vector of children node is done by this function;
2728/// it must be overloaded by each most-derived type of diff node that
2729/// extends the @ref diff type.
2730void
2732{}
2733
2734// </diff stuff>
2735
2736// <type_diff_base stuff>
2737
2738type_diff_base::type_diff_base(type_base_sptr first_subject,
2739 type_base_sptr second_subject,
2740 diff_context_sptr ctxt)
2741 : diff(first_subject, second_subject, ctxt),
2742 priv_(new priv)
2743{}
2744
2745type_diff_base::~type_diff_base()
2746{}
2747// </type_diff_base stuff>
2748
2749// <decl_diff_base stuff>
2750
2751/// Constructor of @ref decl_diff_base.
2752///
2753/// @param first_subject the first subject of the diff.
2754///
2755/// @param second_subject the second subject of the diff.
2756///
2757/// @param ctxt the context of the diff. This object must stay alive
2758/// at least during the life time of the current instance of @ref
2759/// decl_diff_base, otherwise, memory corruption issues occur.
2760decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2761 decl_base_sptr second_subject,
2762 diff_context_sptr ctxt)
2763 : diff(first_subject, second_subject, ctxt),
2764 priv_(new priv)
2765{}
2766
2767decl_diff_base::~decl_diff_base()
2768{}
2769
2770// </decl_diff_base stuff>
2771
2772// <distinct_diff stuff>
2773
2774/// @return a pretty representation for the @ref distinct_diff node.
2775const string&
2777{
2778 if (diff::priv_->pretty_representation_.empty())
2779 {
2780 std::ostringstream o;
2781 o << "distinct_diff[";
2782 if (first_subject())
2783 o << first_subject()->get_pretty_representation();
2784 else
2785 o << "null";
2786 o << ", ";
2787 if (second_subject())
2788 o << second_subject()->get_pretty_representation() ;
2789 else
2790 o << "null";
2791 o << "]" ;
2792 diff::priv_->pretty_representation_ = o.str();
2793 }
2794 return diff::priv_->pretty_representation_;
2795}
2796
2797/// Populate the vector of children node of the @ref diff base type
2798/// sub-object of this instance of @distinct_diff.
2799///
2800/// The children nodes can then later be retrieved using
2801/// diff::children_nodes().
2802void
2804{
2806
2809}
2810
2811/// Constructor for @ref distinct_diff.
2812///
2813/// Note that the two entities considered for the diff (and passed in
2814/// parameter) must be of different kinds.
2815///
2816/// @param first the first entity to consider for the diff.
2817///
2818/// @param second the second entity to consider for the diff.
2819///
2820/// @param ctxt the context of the diff. Note that this context
2821/// object must stay alive at least during the life time of the
2822/// current instance of @ref distinct_diff. Otherwise memory
2823/// corruption issues occur.
2826 diff_context_sptr ctxt)
2827 : diff(first, second, ctxt),
2828 priv_(new priv)
2830
2831/// Getter for the first subject of the diff.
2832///
2833/// @return the first subject of the diff.
2836{return first_subject();}
2837
2838/// Getter for the second subject of the diff.
2839///
2840/// @return the second subject of the diff.
2843{return second_subject();}
2844
2845/// Getter for the child diff of this distinct_diff instance.
2846///
2847/// When a distinct_diff has two subjects that are different but
2848/// compatible, then the distinct_diff instance has a child diff node
2849/// (named the compatible child diff) that is the diff between the two
2850/// subjects stripped from their typedefs. Otherwise, the compatible
2851/// child diff is nul.
2852///
2853/// Note that two diff subjects (that compare different) are
2854/// considered compatible if stripping typedefs out of them makes them
2855/// comparing equal.
2856///
2857/// @return the compatible child diff node, if any. Otherwise, null.
2858const diff_sptr
2860{
2861 if (!priv_->compatible_child_diff)
2862 {
2863 type_base_sptr fs = strip_typedef(is_type(first())),
2864 ss = strip_typedef(is_type(second()));
2865
2866 if (fs && ss
2869 priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2871 context());
2872 }
2873 return priv_->compatible_child_diff;
2874}
2875
2876/// Test if the two arguments are of different kind, or that are both
2877/// NULL.
2878///
2879/// @param first the first argument to test for similarity in kind.
2880///
2881/// @param second the second argument to test for similarity in kind.
2882///
2883/// @return true iff the two arguments are of different kind.
2884bool
2887{
2888 if (!!first != !!second)
2889 return true;
2890 if (!first && !second)
2891 // We do consider diffs of two empty decls as a diff of distinct
2892 // kinds, for now.
2893 return true;
2894 if (first == second)
2895 return false;
2896
2897 const type_or_decl_base &f = *first, &s = *second;
2898 return typeid(f) != typeid(s);
2899}
2900
2901/// @return true if the two subjects of the diff are different, false
2902/// otherwise.
2903bool
2905{return first() != second();}
2906
2907/// @return the kind of local change carried by the current diff node.
2908/// The value returned is zero if the current node carries no local
2909/// change.
2910enum change_kind
2912{
2913 // Changes on a distinct_diff are all local.
2914 if (has_changes())
2916 return NO_CHANGE_KIND;
2917}
2918
2919/// Emit a report about the current diff instance.
2920///
2921/// @param out the output stream to send the diff report to.
2922///
2923/// @param indent the indentation string to use in the report.
2924void
2925distinct_diff::report(ostream& out, const string& indent) const
2926{
2927 context()->get_reporter()->report(*this, out, indent);
2928}
2929
2930/// Try to diff entities that are of distinct kinds.
2931///
2932/// @param first the first entity to consider for the diff.
2933///
2934/// @param second the second entity to consider for the diff.
2935///
2936/// @param ctxt the context of the diff.
2937///
2938/// @return a non-null diff if a diff object could be built, null
2939/// otherwise.
2942 const type_or_decl_base_sptr second,
2943 diff_context_sptr ctxt)
2944{
2946 return distinct_diff_sptr();
2947
2948 distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2949
2950 ctxt->initialize_canonical_diff(result);
2951
2952 return result;
2953}
2954
2955/// </distinct_diff stuff>
2956
2957/// Try to compute a diff on two instances of DiffType representation.
2958///
2959/// The function template performs the diff if and only if the decl
2960/// representations are of a DiffType.
2961///
2962/// @tparm DiffType the type of instances to diff.
2963///
2964/// @param first the first representation of decl to consider in the
2965/// diff computation.
2966///
2967/// @param second the second representation of decl to consider in the
2968/// diff computation.
2969///
2970/// @param ctxt the diff context to use.
2971///
2972///@return the diff of the two types @p first and @p second if and
2973///only if they represent the parametrized type DiffType. Otherwise,
2974///returns a NULL pointer value.
2975template<typename DiffType>
2978 const type_or_decl_base_sptr second,
2979 diff_context_sptr ctxt)
2980{
2981 if (shared_ptr<DiffType> f =
2982 dynamic_pointer_cast<DiffType>(first))
2983 {
2984 shared_ptr<DiffType> s =
2985 dynamic_pointer_cast<DiffType>(second);
2986 if (!s)
2987 return diff_sptr();
2988 return compute_diff(f, s, ctxt);
2989 }
2990 return diff_sptr();
2991}
2992
2993
2994/// This is a specialization of @ref try_to_diff() template to diff
2995/// instances of @ref class_decl.
2996///
2997/// @param first the first representation of decl to consider in the
2998/// diff computation.
2999///
3000/// @param second the second representation of decl to consider in the
3001/// diff computation.
3002///
3003/// @param ctxt the diff context to use.
3004template<>
3007 const type_or_decl_base_sptr second,
3008 diff_context_sptr ctxt)
3009{
3010 if (class_decl_sptr f =
3011 dynamic_pointer_cast<class_decl>(first))
3012 {
3013 class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
3014 if (!s)
3015 return diff_sptr();
3016
3017 if (f->get_is_declaration_only())
3018 {
3019 class_decl_sptr f2 =
3020 is_class_type (f->get_definition_of_declaration());
3021 if (f2)
3022 f = f2;
3023 }
3024 if (s->get_is_declaration_only())
3025 {
3026 class_decl_sptr s2 =
3027 is_class_type(s->get_definition_of_declaration());
3028 if (s2)
3029 s = s2;
3030 }
3031 return compute_diff(f, s, ctxt);
3032 }
3033 return diff_sptr();
3034}
3035
3036/// Try to diff entities that are of distinct kinds.
3037///
3038/// @param first the first entity to consider for the diff.
3039///
3040/// @param second the second entity to consider for the diff.
3041///
3042/// @param ctxt the context of the diff.
3043///
3044/// @return a non-null diff if a diff object could be built, null
3045/// otherwise.
3046static diff_sptr
3047try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3048 const type_or_decl_base_sptr second,
3049 diff_context_sptr ctxt)
3050{return compute_diff_for_distinct_kinds(first, second, ctxt);}
3051
3052/// Compute the difference between two types.
3053///
3054/// The function considers every possible types known to libabigail
3055/// and runs the appropriate diff function on them.
3056///
3057/// Whenever a new kind of type decl is supported by abigail, if we
3058/// want to be able to diff two instances of it, we need to update
3059/// this function to support it.
3060///
3061/// @param first the first type decl to consider for the diff
3062///
3063/// @param second the second type decl to consider for the diff.
3064///
3065/// @param ctxt the diff context to use.
3066///
3067/// @return the resulting diff. It's a pointer to a descendent of
3068/// abigail::comparison::diff.
3069static diff_sptr
3070compute_diff_for_types(const type_or_decl_base_sptr& first,
3071 const type_or_decl_base_sptr& second,
3072 const diff_context_sptr& ctxt)
3073{
3074 type_or_decl_base_sptr f = first;
3075 type_or_decl_base_sptr s = second;
3076
3077 diff_sptr d;
3078
3079 ((d = try_to_diff<type_decl>(f, s, ctxt))
3080 ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3081 ||(d = try_to_diff<union_decl>(f, s,ctxt))
3082 ||(d = try_to_diff<class_decl>(f, s,ctxt))
3083 ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3084 ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3085 ||(d = try_to_diff<ptr_to_mbr_type>(f, s, ctxt))
3086 ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3087 ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3088 ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3089 ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3090 ||(d = try_to_diff<function_type>(f, s, ctxt))
3091 ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3092
3093 ABG_ASSERT(d);
3094
3095 return d;
3096}
3097
3100{return static_cast<diff_category>(static_cast<unsigned>(c1)
3101 | static_cast<unsigned>(c2));}
3102
3104operator|=(diff_category& c1, diff_category c2)
3105{
3106 c1 = c1 | c2;
3107 return c1;
3108}
3109
3111operator&=(diff_category& c1, diff_category c2)
3112{
3113 c1 = c1 & c2;
3114 return c1;
3115}
3116
3118operator^(diff_category c1, diff_category c2)
3119{return static_cast<diff_category>(static_cast<unsigned>(c1)
3120 ^ static_cast<unsigned>(c2));}
3121
3124{return static_cast<diff_category>(static_cast<unsigned>(c1)
3125 & static_cast<unsigned>(c2));}
3126
3129{return static_cast<diff_category>(~static_cast<unsigned>(c));}
3130
3131
3132/// Getter of a bitmap made of the set of change categories that are
3133/// considered harmless.
3134///
3135/// @return the bitmap made of the set of change categories that are
3136/// considered harmless.
3139{
3156}
3157
3158/// Getter of a bitmap made of the set of change categories that are
3159/// considered harmful.
3160///
3161/// @return the bitmap made of the set of change categories that are
3162/// considered harmful.
3165{
3169}
3170
3171/// Serialize an instance of @ref diff_category to an output stream.
3172///
3173/// @param o the output stream to serialize @p c to.
3174///
3175/// @param c the instance of diff_category to serialize.
3176///
3177/// @return the output stream to serialize @p c to.
3178ostream&
3179operator<<(ostream& o, diff_category c)
3180{
3181 bool emitted_a_category = false;
3182
3183 if (c == NO_CHANGE_CATEGORY)
3184 {
3185 o << "NO_CHANGE_CATEGORY";
3186 emitted_a_category = true;
3187 }
3188
3189 if (c & ACCESS_CHANGE_CATEGORY)
3190 {
3191 if (emitted_a_category)
3192 o << "|";
3193 o << "ACCESS_CHANGE_CATEGORY";
3194 emitted_a_category |= true;
3195 }
3196
3198 {
3199 if (emitted_a_category)
3200 o << "|";
3201 o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3202 emitted_a_category |= true;
3203 }
3204
3206 {
3207 if (emitted_a_category)
3208 o << "|";
3209 o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3210 emitted_a_category |= true;
3211 }
3212
3214 {
3215 if (emitted_a_category)
3216 o << "|";
3217 o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3218 emitted_a_category |= true;
3219 }
3220
3222 {
3223 if (emitted_a_category)
3224 o << "|";
3225 o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3226 emitted_a_category |= true;
3227 }
3228
3230 {
3231 if (emitted_a_category)
3232 o << "|";
3233 o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3234 emitted_a_category |= true;
3235 }
3236
3238 {
3239 if (emitted_a_category)
3240 o << "|";
3241 o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3242 emitted_a_category |= true;
3243 }
3244
3246 {
3247 if (emitted_a_category)
3248 o << "|";
3249 o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3250 emitted_a_category |= true;
3251 }
3252
3254 {
3255 if (emitted_a_category)
3256 o << "|";
3257 o << "HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY";
3258 emitted_a_category |= true;
3259 }
3260
3261 if (c & SUPPRESSED_CATEGORY)
3262 {
3263 if (emitted_a_category)
3264 o << "|";
3265 o << "SUPPRESSED_CATEGORY";
3266 emitted_a_category |= true;
3267 }
3268
3269 if (c & PRIVATE_TYPE_CATEGORY)
3270 {
3271 if (emitted_a_category)
3272 o << "|";
3273 o << "PRIVATE_TYPE_CATEGORY";
3274 emitted_a_category |= true;
3275 }
3276
3278 {
3279 if (emitted_a_category)
3280 o << "|";
3281 o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3282 emitted_a_category |= true;
3283 }
3284
3286 {
3287 if (emitted_a_category)
3288 o << "|";
3289 o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3290 emitted_a_category |= true;
3291 }
3292
3293 if (c & REDUNDANT_CATEGORY)
3294 {
3295 if (emitted_a_category)
3296 o << "|";
3297 o << "REDUNDANT_CATEGORY";
3298 emitted_a_category |= true;
3299 }
3300
3302 {
3303 if (emitted_a_category)
3304 o << "|";
3305 o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3306 emitted_a_category |= true;
3307 }
3308
3310 {
3311 if (emitted_a_category)
3312 o << "|";
3313 o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3314 emitted_a_category |= true;
3315 }
3316
3318 {
3319 if (emitted_a_category)
3320 o << "|";
3321 o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3322 emitted_a_category |= true;
3323 }
3324
3326 {
3327 if (emitted_a_category)
3328 o << "|";
3329 o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3330 emitted_a_category |= true;
3331 }
3332
3334 {
3335 if (emitted_a_category)
3336 o << "|";
3337 o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3338 emitted_a_category |= true;
3339 }
3340
3342 {
3343 if (emitted_a_category)
3344 o << "|";
3345 o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3346 emitted_a_category |= true;
3347 }
3348
3350 {
3351 if (emitted_a_category)
3352 o << "|";
3353 o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3354 emitted_a_category |= true;
3355 }
3356
3358 {
3359 if (emitted_a_category)
3360 o << "|";
3361 o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3362 emitted_a_category |= true;
3363 }
3364
3366 {
3367 if (emitted_a_category)
3368 o << "|";
3369 o << "HAS_ALLOWED_CHANGE_CATEGORY";
3370 emitted_a_category |= true;
3371 }
3372
3374 {
3375 if (emitted_a_category)
3376 o << "|";
3377 o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3378 emitted_a_category |= true;
3379 }
3380
3382 {
3383 if (emitted_a_category)
3384 o << "|";
3385 o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3386 emitted_a_category |= true;
3387 }
3388
3389 return o;
3390}
3391
3392/// Compute the difference between two decls.
3393///
3394/// The function consider every possible decls known to libabigail and
3395/// runs the appropriate diff function on them.
3396///
3397/// Whenever a new kind of non-type decl is supported by abigail, if
3398/// we want to be able to diff two instances of it, we need to update
3399/// this function to support it.
3400///
3401/// @param first the first decl to consider for the diff
3402///
3403/// @param second the second decl to consider for the diff.
3404///
3405/// @param ctxt the diff context to use.
3406///
3407/// @return the resulting diff.
3408static diff_sptr
3409compute_diff_for_decls(const decl_base_sptr first,
3410 const decl_base_sptr second,
3411 diff_context_sptr ctxt)
3412{
3413
3414 diff_sptr d;
3415
3416 ((d = try_to_diff<function_decl>(first, second, ctxt))
3417 || (d = try_to_diff<var_decl>(first, second, ctxt))
3418 || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3419
3420 ABG_ASSERT(d);
3421
3422 return d;
3423}
3424
3425/// Compute the difference between two decls. The decls can represent
3426/// either type declarations, or non-type declaration.
3427///
3428/// Note that the two decls must have been created in the same @ref
3429/// environment, otherwise, this function aborts.
3430///
3431/// @param first the first decl to consider.
3432///
3433/// @param second the second decl to consider.
3434///
3435/// @param ctxt the diff context to use.
3436///
3437/// @return the resulting diff, or NULL if the diff could not be
3438/// computed.
3440compute_diff(const decl_base_sptr first,
3441 const decl_base_sptr second,
3442 diff_context_sptr ctxt)
3443{
3444 if (!first || !second)
3445 return diff_sptr();
3446
3447 diff_sptr d;
3448 if (is_type(first) && is_type(second))
3449 d = compute_diff_for_types(first, second, ctxt);
3450 else
3451 d = compute_diff_for_decls(first, second, ctxt);
3452 ABG_ASSERT(d);
3453 return d;
3454}
3455
3456/// Compute the difference between two types.
3457///
3458/// Note that the two types must have been created in the same @ref
3459/// environment, otherwise, this function aborts.
3460///
3461/// @param first the first type to consider.
3462///
3463/// @param second the second type to consider.
3464///
3465/// @param ctxt the diff context to use.
3466///
3467/// @return the resulting diff, or NULL if the diff couldn't be
3468/// computed.
3470compute_diff(const type_base_sptr first,
3471 const type_base_sptr second,
3472 diff_context_sptr ctxt)
3473{
3474 decl_base_sptr f = get_type_declaration(first),
3475 s = get_type_declaration(second);
3476
3477 diff_sptr d = compute_diff_for_types(f,s, ctxt);
3478 ABG_ASSERT(d);
3479 return d;
3480}
3481
3482/// Get a copy of the pretty representation of a diff node.
3483///
3484/// @param d the diff node to consider.
3485///
3486/// @return the pretty representation string.
3487string
3489{
3490 if (!d)
3491 return "";
3492 string prefix= "diff of ";
3493 return prefix + get_pretty_representation(d->first_subject());
3494}
3495
3496// <var_diff stuff>
3497
3498/// Populate the vector of children node of the @ref diff base type
3499/// sub-object of this instance of @ref var_diff.
3500///
3501/// The children node can then later be retrieved using
3502/// diff::children_node().
3503void
3506
3507/// @return the pretty representation for this current instance of
3508/// @ref var_diff.
3509const string&
3511{
3512 if (diff::priv_->pretty_representation_.empty())
3513 {
3514 std::ostringstream o;
3515 o << "var_diff["
3516 << first_subject()->get_pretty_representation()
3517 << ", "
3518 << second_subject()->get_pretty_representation()
3519 << "]";
3520 diff::priv_->pretty_representation_ = o.str();
3521 }
3522 return diff::priv_->pretty_representation_;
3523}
3524/// Constructor for @ref var_diff.
3525///
3526/// @param first the first instance of @ref var_decl to consider in
3527/// the diff.
3528///
3529/// @param second the second instance of @ref var_decl to consider in
3530/// the diff.
3531///
3532/// @param type_diff the diff between types of the instances of
3533/// var_decl.
3534///
3535/// @param ctxt the diff context to use.
3537 var_decl_sptr second,
3538 diff_sptr type_diff,
3539 diff_context_sptr ctxt)
3540 : decl_diff_base(first, second, ctxt),
3541 priv_(new priv)
3542{priv_->type_diff_ = type_diff;}
3543
3544/// Getter for the first @ref var_decl of the diff.
3545///
3546/// @return the first @ref var_decl of the diff.
3549{return dynamic_pointer_cast<var_decl>(first_subject());}
3550
3551/// Getter for the second @ref var_decl of the diff.
3552///
3553/// @return the second @ref var_decl of the diff.
3556{return dynamic_pointer_cast<var_decl>(second_subject());}
3557
3558/// Getter for the diff of the types of the instances of @ref
3559/// var_decl.
3560///
3561/// @return the diff of the types of the instances of @ref var_decl.
3564{
3565 if (diff_sptr result = priv_->type_diff_.lock())
3566 return result;
3567 else
3568 {
3569 result = compute_diff(first_var()->get_type(),
3570 second_var()->get_type(),
3571 context());
3572 context()->keep_diff_alive(result);
3573 priv_->type_diff_ = result;
3574 return result;
3575 }
3576}
3577
3578/// Return true iff the diff node has a change.
3579///
3580/// @return true iff the diff node has a change.
3581bool
3583{return *first_var() != *second_var();}
3584
3585/// @return the kind of local change carried by the current diff node.
3586/// The value returned is zero if the current node carries no local
3587/// change.
3588enum change_kind
3590{
3591 ir::change_kind k = ir::NO_CHANGE_KIND;
3592 if (!equals(*first_var(), *second_var(), &k))
3593 return k & ir::ALL_LOCAL_CHANGES_MASK;
3594 return ir::NO_CHANGE_KIND;
3595}
3596
3597/// Report the diff in a serialized form.
3598///
3599/// @param out the stream to serialize the diff to.
3600///
3601/// @param indent the prefix to use for the indentation of this
3602/// serialization.
3603void
3604var_diff::report(ostream& out, const string& indent) const
3605{
3606 context()->get_reporter()->report(*this, out, indent);
3607}
3608
3609/// Compute the diff between two instances of @ref var_decl.
3610///
3611/// Note that the two decls must have been created in the same @ref
3612/// environment, otherwise, this function aborts.
3613///
3614/// @param first the first @ref var_decl to consider for the diff.
3615///
3616/// @param second the second @ref var_decl to consider for the diff.
3617///
3618/// @param ctxt the diff context to use.
3619///
3620/// @return the resulting diff between the two @ref var_decl.
3623 const var_decl_sptr second,
3624 diff_context_sptr ctxt)
3625{
3626 var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3627 ctxt->initialize_canonical_diff(d);
3628
3629 return d;
3630}
3631
3632// </var_diff stuff>
3633
3634// <pointer_type_def stuff>
3635
3636/// Populate the vector of children node of the @ref diff base type
3637/// sub-object of this instance of @ref pointer_diff.
3638///
3639/// The children node can then later be retrieved using
3640/// diff::children_node().
3641void
3644
3645/// Constructor for a pointer_diff.
3646///
3647/// @param first the first pointer to consider for the diff.
3648///
3649/// @param second the secon pointer to consider for the diff.
3650///
3651/// @param ctxt the diff context to use.
3653 pointer_type_def_sptr second,
3654 diff_sptr underlying,
3655 diff_context_sptr ctxt)
3656 : type_diff_base(first, second, ctxt),
3657 priv_(new priv(underlying))
3658{}
3659
3660/// Getter for the first subject of a pointer diff
3661///
3662/// @return the first pointer considered in this pointer diff.
3665{return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3666
3667/// Getter for the second subject of a pointer diff
3668///
3669/// @return the second pointer considered in this pointer diff.
3672{return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3673
3674/// @return the pretty represenation for the current instance of @ref
3675/// pointer_diff.
3676const string&
3678{
3679 if (diff::priv_->pretty_representation_.empty())
3680 {
3681 std::ostringstream o;
3682 o << "pointer_diff["
3683 << first_subject()->get_pretty_representation()
3684 << ", "
3685 << second_subject()->get_pretty_representation()
3686 << "]";
3687 diff::priv_->pretty_representation_ = o.str();
3688 }
3689 return diff::priv_->pretty_representation_;
3690}
3691
3692/// Return true iff the current diff node carries a change.
3693///
3694/// @return true iff the current diff node carries a change.
3695bool
3697{return first_pointer() != second_pointer();}
3698
3699/// @return the kind of local change carried by the current diff node.
3700/// The value returned is zero if the current node carries no local
3701/// change.
3702enum change_kind
3704{
3705 ir::change_kind k = ir::NO_CHANGE_KIND;
3706 if (!equals(*first_pointer(), *second_pointer(), &k))
3707 return k & ir::ALL_LOCAL_CHANGES_MASK;
3708 return ir::NO_CHANGE_KIND;
3709}
3710
3711/// Getter for the diff between the pointed-to types of the pointers
3712/// of this diff.
3713///
3714/// @return the diff between the pointed-to types.
3717{return priv_->underlying_type_diff_;}
3718
3719/// Setter for the diff between the pointed-to types of the pointers
3720/// of this diff.
3721///
3722/// @param d the new diff between the pointed-to types of the pointers
3723/// of this diff.
3724void
3726{priv_->underlying_type_diff_ = d;}
3727
3728/// Report the diff in a serialized form.
3729///
3730/// @param out the stream to serialize the diff to.
3731///
3732/// @param indent the prefix to use for the indentation of this
3733/// serialization.
3734void
3735pointer_diff::report(ostream& out, const string& indent) const
3736{
3737 context()->get_reporter()->report(*this, out, indent);
3738}
3739
3740/// Compute the diff between between two pointers.
3741///
3742/// Note that the two types must have been created in the same @ref
3743/// environment, otherwise, this function aborts.
3744///
3745/// @param first the pointer to consider for the diff.
3746///
3747/// @param second the pointer to consider for the diff.
3748///
3749/// @return the resulting diff between the two pointers.
3750///
3751/// @param ctxt the diff context to use.
3754 pointer_type_def_sptr second,
3755 diff_context_sptr ctxt)
3756{
3757 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3758 second->get_pointed_to_type(),
3759 ctxt);
3760 pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3761 ctxt->initialize_canonical_diff(result);
3762
3763 return result;
3764}
3765
3766// </pointer_type_def>
3767
3768// <subrange_diff >
3769
3770/// Constructor of the @ref subrange_diff diff node type.
3771///
3772/// @param first the first subrange type to consider for the diff.
3773///
3774/// @param second the second subrange type to consider for the diff.
3775///
3776/// @param underlying_type_diff the underlying type diff between @p
3777/// first and @p second.
3778///
3779/// @param ctxt the diff context to use.
3781(const array_type_def::subrange_sptr& first,
3782 const array_type_def::subrange_sptr& second,
3783 const diff_sptr& underlying_type_diff,
3784 const diff_context_sptr ctxt)
3785 : type_diff_base(first, second, ctxt),
3786 priv_(new priv(underlying_type_diff))
3787{}
3788
3789
3790/// Getter of the first subrange of the current instance @ref
3791/// subrange_diff.
3792///
3793/// @return The first subrange of the current instance @ref subrange_diff.
3797
3798/// Getter of the second subrange of the current instance @ref
3799/// subrange_diff.
3800///
3801/// @return The second subrange of the current instance @ref
3802/// subrange_diff.
3806
3807/// Getter of the diff node of the underlying types of the current
3808/// @ref subrange_diff diff node.
3809///
3810/// @return The diff node of the underlying types of the current @ref
3811/// subrange_diff diff node.
3812const diff_sptr
3814{return priv_->underlying_type_diff_;}
3815
3816/// Getter the pretty representation of the @ref subrange_diff diff
3817/// node.
3818///
3819/// @return The pretty representation of the @ref subrange_diff diff node.
3820const string&
3822{
3823 if (diff::priv_->pretty_representation_.empty())
3824 {
3825 std::ostringstream o;
3826 o << "subrange_diff["
3827 << first_subject()->get_pretty_representation()
3828 << ","
3829 << second_subject()->get_pretty_representation()
3830 << "]";
3831 diff::priv_->pretty_representation_ = o.str();
3832 }
3833 return diff::priv_->pretty_representation_;
3834}
3835
3836/// Test if the current @ref subrange_diff node carries any change.
3837///
3838/// @return true iff the current @ref subrange_diff node carries any
3839/// change.
3840bool
3842{return *first_subrange() != *second_subrange();}
3843
3844/// Test if the current @ref subrange_diff node carries any local
3845/// change.
3846///
3847/// @return true iff the current @ref subrange_diff node carries any
3848/// local change.
3849enum change_kind
3851{
3852 ir::change_kind k = ir::NO_CHANGE_KIND;
3853 if (!equals(*first_subrange(), *second_subrange(), &k))
3854 return k & ir::ALL_LOCAL_CHANGES_MASK;
3855 return ir::NO_CHANGE_KIND;
3856}
3857
3858/// Report about the changes carried by this node.
3859///
3860/// @param out the output stream to send the report to.
3861///
3862/// @param indent the indentation string to use.
3863void
3864subrange_diff::report(ostream& out, const string& indent) const
3865{context()->get_reporter()->report(*this, out, indent);}
3866
3867/// Populate the vector of children node of the @ref diff base type
3868/// sub-object of this instance of @ref subrange_diff.
3869///
3870/// The children node can then later be retrieved using
3871/// diff::children_node().
3872void
3875
3876/// Compute the diff between two instances of @ref subrange_diff.
3877///
3878/// Note that the two decls must have been created in the same @ref
3879/// environment, otherwise, this function aborts.
3880///
3881/// @param first the first @ref subrange_diff to consider for the diff.
3882///
3883/// @param second the second @ref subrange_diff to consider for the diff.
3884///
3885/// @param ctxt the diff context to use.
3886///
3887/// @return the resulting diff between the two @ref subrange_diff.
3891 diff_context_sptr ctxt)
3892{
3893 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3894 second->get_underlying_type(),
3895 ctxt);
3896
3897 subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
3898 ctxt->initialize_canonical_diff(result);
3899 return result;
3900}
3901
3902//</subrange_diff >
3903
3904
3905// <array_type_def>
3906
3907/// Populate the vector of children node of the @ref diff base type
3908/// sub-object of this instance of @ref array_diff.
3909///
3910/// The children node can then later be retrieved using
3911/// diff::children_node().
3912void
3915
3916/// Constructor for array_diff
3917///
3918/// @param first the first array_type of the diff.
3919///
3920/// @param second the second array_type of the diff.
3921///
3922/// @param element_type_diff the diff between the two array element
3923/// types.
3924///
3925/// @param ctxt the diff context to use.
3927 const array_type_def_sptr second,
3928 diff_sptr element_type_diff,
3929 diff_context_sptr ctxt)
3930 : type_diff_base(first, second, ctxt),
3931 priv_(new priv(element_type_diff))
3932{}
3933
3934/// Getter for the first array of the diff.
3935///
3936/// @return the first array of the diff.
3939{return dynamic_pointer_cast<array_type_def>(first_subject());}
3940
3941/// Getter for the second array of the diff.
3942///
3943/// @return for the second array of the diff.
3946{return dynamic_pointer_cast<array_type_def>(second_subject());}
3947
3948/// Getter for the diff between the two types of array elements.
3949///
3950/// @return the diff between the two types of array elements.
3951const diff_sptr&
3953{return priv_->element_type_diff_;}
3954
3955/// Setter for the diff between the two array element types.
3956///
3957/// @param d the new diff betweend the two array element types.
3958void
3960{priv_->element_type_diff_ = d;}
3961
3962/// @return the pretty representation for the current instance of @ref
3963/// array_diff.
3964const string&
3966{
3967 if (diff::priv_->pretty_representation_.empty())
3968 {
3969 std::ostringstream o;
3970 o << "array_diff["
3971 << first_subject()->get_pretty_representation()
3972 << ", "
3973 << second_subject()->get_pretty_representation()
3974 << "]";
3975 diff::priv_->pretty_representation_ = o.str();
3976 }
3977 return diff::priv_->pretty_representation_;
3978}
3979
3980/// Return true iff the current diff node carries a change.
3981///
3982/// @return true iff the current diff node carries a change.
3983bool
3985{
3986 bool l = false;
3987
3988 // the array element types match check for differing dimensions
3989 // etc...
3991 f = dynamic_pointer_cast<array_type_def>(first_subject()),
3992 s = dynamic_pointer_cast<array_type_def>(second_subject());
3993
3994 if (f->get_name() != s->get_name())
3995 l |= true;
3996 if (f->get_size_in_bits() != s->get_size_in_bits())
3997 l |= true;
3998 if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3999 l |= true;
4000
4001 l |= element_type_diff()
4002 ? element_type_diff()->has_changes()
4003 : false;
4004
4005 return l;
4006}
4007
4008
4009/// @return the kind of local change carried by the current diff node.
4010/// The value returned is zero if the current node carries no local
4011/// change.
4012enum change_kind
4014{
4015 ir::change_kind k = ir::NO_CHANGE_KIND;
4016 if (!equals(*first_array(), *second_array(), &k))
4017 return k & ir::ALL_LOCAL_CHANGES_MASK;
4018 return ir::NO_CHANGE_KIND;
4019}
4020
4021/// Report the diff in a serialized form.
4022///
4023/// @param out the output stream to serialize the dif to.
4024///
4025/// @param indent the string to use for indenting the report.
4026void
4027array_diff::report(ostream& out, const string& indent) const
4028{
4029 context()->get_reporter()->report(*this, out, indent);
4030}
4031
4032/// Compute the diff between two arrays.
4033///
4034/// Note that the two types must have been created in the same @ref
4035/// environment, otherwise, this function aborts.
4036///
4037/// @param first the first array to consider for the diff.
4038///
4039/// @param second the second array to consider for the diff.
4040///
4041/// @param ctxt the diff context to use.
4044 array_type_def_sptr second,
4045 diff_context_sptr ctxt)
4046{
4047 diff_sptr d = compute_diff_for_types(first->get_element_type(),
4048 second->get_element_type(),
4049 ctxt);
4050 array_diff_sptr result(new array_diff(first, second, d, ctxt));
4051 ctxt->initialize_canonical_diff(result);
4052 return result;
4053}
4054// </array_type_def>
4055
4056// <reference_type_def>
4057
4058/// Populate the vector of children node of the @ref diff base type
4059/// sub-object of this instance of @ref reference_diff.
4060///
4061/// The children node can then later be retrieved using
4062/// diff::children_node().
4063void
4066
4067/// Constructor for reference_diff
4068///
4069/// @param first the first reference_type of the diff.
4070///
4071/// @param second the second reference_type of the diff.
4072///
4073/// @param ctxt the diff context to use.
4075 const reference_type_def_sptr second,
4076 diff_sptr underlying,
4077 diff_context_sptr ctxt)
4078 : type_diff_base(first, second, ctxt),
4079 priv_(new priv(underlying))
4080{}
4081
4082/// Getter for the first reference of the diff.
4083///
4084/// @return the first reference of the diff.
4087{return dynamic_pointer_cast<reference_type_def>(first_subject());}
4088
4089/// Getter for the second reference of the diff.
4090///
4091/// @return for the second reference of the diff.
4094{return dynamic_pointer_cast<reference_type_def>(second_subject());}
4095
4096
4097/// Getter for the diff between the two referred-to types.
4098///
4099/// @return the diff between the two referred-to types.
4100const diff_sptr&
4102{return priv_->underlying_type_diff_;}
4103
4104/// Setter for the diff between the two referred-to types.
4105///
4106/// @param d the new diff betweend the two referred-to types.
4107diff_sptr&
4109{
4110 priv_->underlying_type_diff_ = d;
4111 return priv_->underlying_type_diff_;
4112}
4113
4114/// @return the pretty representation for the current instance of @ref
4115/// reference_diff.
4116const string&
4118{
4119 if (diff::priv_->pretty_representation_.empty())
4120 {
4121 std::ostringstream o;
4122 o << "reference_diff["
4123 << first_subject()->get_pretty_representation()
4124 << ", "
4125 << second_subject()->get_pretty_representation()
4126 << "]";
4127 diff::priv_->pretty_representation_ = o.str();
4128 }
4129 return diff::priv_->pretty_representation_;
4130}
4131
4132/// Return true iff the current diff node carries a change.
4133///
4134/// @return true iff the current diff node carries a change.
4135bool
4137{
4138 return first_reference() != second_reference();
4139}
4140
4141/// @return the kind of local change carried by the current diff node.
4142/// The value returned is zero if the current node carries no local
4143/// change.
4144enum change_kind
4146{
4147 ir::change_kind k = ir::NO_CHANGE_KIND;
4148 if (!equals(*first_reference(), *second_reference(), &k))
4149 return k & ir::ALL_LOCAL_CHANGES_MASK;
4150 return ir::NO_CHANGE_KIND;
4151}
4152
4153/// Report the diff in a serialized form.
4154///
4155/// @param out the output stream to serialize the dif to.
4156///
4157/// @param indent the string to use for indenting the report.
4158void
4159reference_diff::report(ostream& out, const string& indent) const
4160{
4161 context()->get_reporter()->report(*this, out, indent);
4162}
4163
4164/// Compute the diff between two references.
4165///
4166/// Note that the two types must have been created in the same @ref
4167/// environment, otherwise, this function aborts.
4168///
4169/// @param first the first reference to consider for the diff.
4170///
4171/// @param second the second reference to consider for the diff.
4172///
4173/// @param ctxt the diff context to use.
4177 diff_context_sptr ctxt)
4178{
4179 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4180 second->get_pointed_to_type(),
4181 ctxt);
4182 reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4183 ctxt->initialize_canonical_diff(result);
4184 return result;
4185}
4186// </reference_type_def>
4187
4188// <ptr_to_mbr_diff stuff>
4189
4190
4191/// Constructor of @ref ptr_to_mbr_diff.
4192///
4193/// @param first the first pointer-to-member subject of the diff.
4194///
4195/// @param second the second pointer-to-member subject of the diff.
4196///
4197/// @param member_type_diff the diff node carrying changes to the
4198/// member type of the pointer-to-member we are considering.
4199///
4200/// @param containing_type_diff the diff node carrying changes to the
4201/// containing type of the pointer-to-member we are considering.
4202///
4203/// @param ctxt the context of the diff we are considering.
4204ptr_to_mbr_diff::ptr_to_mbr_diff(const ptr_to_mbr_type_sptr& first,
4205 const ptr_to_mbr_type_sptr& second,
4206 const diff_sptr& member_type_diff,
4207 const diff_sptr& containing_type_diff,
4208 diff_context_sptr ctxt)
4209 : type_diff_base(first, second, ctxt),
4210 priv_(new priv(member_type_diff, containing_type_diff))
4211{}
4212
4213/// Getter of the first pointer-to-member subject of the current diff
4214/// node.
4215///
4216/// @return the first pointer-to-member subject of the current diff
4217/// node.
4220{return dynamic_pointer_cast<ptr_to_mbr_type>(first_subject());}
4221
4222/// Getter of the second pointer-to-member subject of the current diff
4223/// node.
4224///
4225/// @return the second pointer-to-member subject of the current diff
4226/// node.
4229{return dynamic_pointer_cast<ptr_to_mbr_type>(second_subject());}
4230
4231/// Getter of the diff node carrying changes to the member type of
4232/// first subject of the current diff node.
4233///
4234/// @return The diff node carrying changes to the member type of first
4235/// subject of the current diff node.
4236const diff_sptr
4238{return priv_->member_type_diff_;}
4239
4240/// Getter of the diff node carrying changes to the containing type of
4241/// first subject of the current diff node.
4242///
4243/// @return The diff node carrying changes to the containing type of
4244/// first subject of the current diff node.
4245const diff_sptr
4247{return priv_->containing_type_diff_;}
4248
4249/// Test whether the current diff node carries any change.
4250///
4251/// @return true iff the current diff node carries any change.
4252bool
4254{
4256}
4257
4258/// Test whether the current diff node carries any local change.
4259///
4260/// @return true iff the current diff node carries any local change.
4261enum change_kind
4263{
4264 ir::change_kind k = ir::NO_CHANGE_KIND;
4266 return k & ir::ALL_LOCAL_CHANGES_MASK;
4267 return ir::NO_CHANGE_KIND;
4268}
4269
4270/// Get the pretty representation of the current @ref ptr_to_mbr_diff
4271/// node.
4272///
4273/// @return the pretty representation of the current diff node.
4274const string&
4276{
4277 if (diff::priv_->pretty_representation_.empty())
4278 {
4279 std::ostringstream o;
4280 o << "ptr_to_mbr_diff["
4281 << first_subject()->get_pretty_representation()
4282 << ", "
4283 << second_subject()->get_pretty_representation()
4284 << "]";
4285 diff::priv_->pretty_representation_ = o.str();
4286 }
4287 return diff::priv_->pretty_representation_;
4288}
4289
4290void
4291ptr_to_mbr_diff::report(ostream& out, const string& indent) const
4292{
4293 context()->get_reporter()->report(*this, out, indent);
4294}
4295
4296/// Populate the vector of children node of the @ref diff base type
4297/// sub-object of this instance of @ref ptr_to_mbr_diff.
4298///
4299/// The children node can then later be retrieved using
4300/// diff::children_node().
4301void
4303{
4306}
4307
4308/// Destructor of @ref ptr_to_mbr_diff.
4310{
4311}
4312
4313/// Compute the diff between two @ref ptr_to_mbr_type types.
4314///
4315/// Note that the two types must have been created in the same @ref
4316/// environment, otherwise, this function aborts.
4317///
4318/// @param first the first pointer-to-member type to consider for the diff.
4319///
4320/// @param second the second pointer-to-member type to consider for the diff.
4321///
4322/// @param ctxt the diff context to use.
4325 const ptr_to_mbr_type_sptr& second,
4326 diff_context_sptr& ctxt)
4327{
4328 diff_sptr member_type_diff =
4329 compute_diff(is_type(first->get_member_type()),
4330 is_type(second->get_member_type()),
4331 ctxt);
4332
4333 diff_sptr containing_type_diff =
4334 compute_diff(is_type(first->get_containing_type()),
4335 is_type(second->get_containing_type()),
4336 ctxt);
4337
4338 ptr_to_mbr_diff_sptr result(new ptr_to_mbr_diff(first, second,
4339 member_type_diff,
4340 containing_type_diff,
4341 ctxt));
4342 ctxt->initialize_canonical_diff(result);
4343 return result;
4344}
4345
4346// </ptr_to_mbr_diff stuff>
4347
4348// <qualified_type_diff stuff>
4349
4350/// Populate the vector of children node of the @ref diff base type
4351/// sub-object of this instance of @ref qualified_type_diff.
4352///
4353/// The children node can then later be retrieved using
4354/// diff::children_node().
4355void
4358
4359/// Constructor for qualified_type_diff.
4360///
4361/// @param first the first qualified type of the diff.
4362///
4363/// @param second the second qualified type of the diff.
4364///
4365/// @param ctxt the diff context to use.
4366qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4367 qualified_type_def_sptr second,
4368 diff_sptr under,
4369 diff_context_sptr ctxt)
4370 : type_diff_base(first, second, ctxt),
4371 priv_(new priv(under))
4372{}
4373
4374/// Getter for the first qualified type of the diff.
4375///
4376/// @return the first qualified type of the diff.
4377const qualified_type_def_sptr
4379{return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4380
4381/// Getter for the second qualified type of the diff.
4382///
4383/// @return the second qualified type of the diff.
4384const qualified_type_def_sptr
4386{return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4387
4388/// Getter for the diff between the underlying types of the two
4389/// qualified types.
4390///
4391/// @return the diff between the underlying types of the two qualified
4392/// types.
4395{return priv_->underlying_type_diff;}
4396
4397/// Getter for the diff between the most underlying non-qualified
4398/// types of two qualified types.
4399///
4400/// @return the diff between the most underlying non-qualified types
4401/// of two qualified types.
4404{
4405 if (!priv_->leaf_underlying_type_diff)
4406 priv_->leaf_underlying_type_diff
4407 = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4409 context());
4410
4411 return priv_->leaf_underlying_type_diff;
4412}
4413
4414/// Setter for the diff between the underlying types of the two
4415/// qualified types.
4416///
4417/// @return the diff between the underlying types of the two qualified
4418/// types.
4419void
4421{priv_->underlying_type_diff = d;}
4422
4423/// @return the pretty representation of the current instance of @ref
4424/// qualified_type_diff.
4425const string&
4427{
4428 if (diff::priv_->pretty_representation_.empty())
4429 {
4430 std::ostringstream o;
4431 o << "qualified_type_diff["
4432 << first_subject()->get_pretty_representation()
4433 << ", "
4434 << second_subject()->get_pretty_representation()
4435 << "]";
4436 diff::priv_->pretty_representation_ = o.str();
4437 }
4438 return diff::priv_->pretty_representation_;
4439}
4440
4441/// Return true iff the current diff node carries a change.
4442///
4443/// @return true iff the current diff node carries a change.
4444bool
4447
4448/// @return the kind of local change carried by the current diff node.
4449/// The value returned is zero if the current node carries no local
4450/// change.
4451enum change_kind
4453{
4454 ir::change_kind k = ir::NO_CHANGE_KIND;
4456 return k & ir::ALL_LOCAL_CHANGES_MASK;
4457 return ir::NO_CHANGE_KIND;
4458}
4459
4460/// Report the diff in a serialized form.
4461///
4462/// @param out the output stream to serialize to.
4463///
4464/// @param indent the string to use to indent the lines of the report.
4465void
4466qualified_type_diff::report(ostream& out, const string& indent) const
4467{
4468 context()->get_reporter()->report(*this, out, indent);
4469}
4470
4471/// Compute the diff between two qualified types.
4472///
4473/// Note that the two types must have been created in the same @ref
4474/// environment, otherwise, this function aborts.
4475///
4476/// @param first the first qualified type to consider for the diff.
4477///
4478/// @param second the second qualified type to consider for the diff.
4479///
4480/// @param ctxt the diff context to use.
4481qualified_type_diff_sptr
4482compute_diff(const qualified_type_def_sptr first,
4483 const qualified_type_def_sptr second,
4484 diff_context_sptr ctxt)
4485{
4486 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4487 second->get_underlying_type(),
4488 ctxt);
4489 qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4490 d, ctxt));
4491 ctxt->initialize_canonical_diff(result);
4492 return result;
4493}
4494
4495// </qualified_type_diff stuff>
4496
4497// <enum_diff stuff>
4498
4499/// Clear the lookup tables useful for reporting an enum_diff.
4500///
4501/// This function must be updated each time a lookup table is added or
4502/// removed from the class_diff::priv.
4503void
4504enum_diff::clear_lookup_tables()
4505{
4506 priv_->deleted_enumerators_.clear();
4507 priv_->inserted_enumerators_.clear();
4508 priv_->changed_enumerators_.clear();
4509}
4510
4511/// Tests if the lookup tables are empty.
4512///
4513/// @return true if the lookup tables are empty, false otherwise.
4514bool
4515enum_diff::lookup_tables_empty() const
4516{
4517 return (priv_->deleted_enumerators_.empty()
4518 && priv_->inserted_enumerators_.empty()
4519 && priv_->changed_enumerators_.empty());
4520}
4521
4522/// If the lookup tables are not yet built, walk the differences and
4523/// fill the lookup tables.
4524void
4525enum_diff::ensure_lookup_tables_populated()
4526{
4527 if (!lookup_tables_empty())
4528 return;
4529
4530 {
4531 edit_script e = priv_->enumerators_changes_;
4532
4533 for (vector<deletion>::const_iterator it = e.deletions().begin();
4534 it != e.deletions().end();
4535 ++it)
4536 {
4537 unsigned i = it->index();
4538 const enum_type_decl::enumerator& n =
4539 first_enum()->get_enumerators()[i];
4540 const string& name = n.get_name();
4541 ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4542 == priv_->deleted_enumerators_.end());
4543 priv_->deleted_enumerators_[name] = n;
4544 }
4545
4546 for (vector<insertion>::const_iterator it = e.insertions().begin();
4547 it != e.insertions().end();
4548 ++it)
4549 {
4550 for (vector<unsigned>::const_iterator iit =
4551 it->inserted_indexes().begin();
4552 iit != it->inserted_indexes().end();
4553 ++iit)
4554 {
4555 unsigned i = *iit;
4556 const enum_type_decl::enumerator& n =
4557 second_enum()->get_enumerators()[i];
4558 const string& name = n.get_name();
4559 ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4560 == priv_->inserted_enumerators_.end());
4561 string_enumerator_map::const_iterator j =
4562 priv_->deleted_enumerators_.find(name);
4563 if (j == priv_->deleted_enumerators_.end())
4564 priv_->inserted_enumerators_[name] = n;
4565 else
4566 {
4567 if (j->second != n)
4568 priv_->changed_enumerators_[j->first] =
4569 std::make_pair(j->second, n);
4570 priv_->deleted_enumerators_.erase(j);
4571 }
4572 }
4573 }
4574 }
4575}
4576
4577/// Populate the vector of children node of the @ref diff base type
4578/// sub-object of this instance of @ref enum_diff.
4579///
4580/// The children node can then later be retrieved using
4581/// diff::children_node().
4582void
4585
4586/// Constructor for enum_diff.
4587///
4588/// @param first the first enum type of the diff.
4589///
4590/// @param second the second enum type of the diff.
4591///
4592/// @param underlying_type_diff the diff of the two underlying types
4593/// of the two enum types.
4594///
4595/// @param ctxt the diff context to use.
4597 const enum_type_decl_sptr second,
4598 const diff_sptr underlying_type_diff,
4599 const diff_context_sptr ctxt)
4600 : type_diff_base(first, second, ctxt),
4601 priv_(new priv(underlying_type_diff))
4602{}
4603
4604/// @return the first enum of the diff.
4607{return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4608
4609/// @return the second enum of the diff.
4612{return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4613
4614/// @return the diff of the two underlying enum types.
4617{return priv_->underlying_type_diff_;}
4618
4619/// @return a map of the enumerators that were deleted.
4622{return priv_->deleted_enumerators_;}
4623
4624/// @return a map of the enumerators that were inserted
4627{return priv_->inserted_enumerators_;}
4628
4629/// @return a map of the enumerators that were changed
4632{return priv_->changed_enumerators_;}
4633
4634/// @return the pretty representation of the current instance of @ref
4635/// enum_diff.
4636const string&
4638{
4639 if (diff::priv_->pretty_representation_.empty())
4640 {
4641 std::ostringstream o;
4642 o << "enum_diff["
4643 << first_subject()->get_pretty_representation()
4644 << ", "
4645 << second_subject()->get_pretty_representation()
4646 << "]";
4647 diff::priv_->pretty_representation_ = o.str();
4648 }
4649 return diff::priv_->pretty_representation_;
4650}
4651
4652/// Return true iff the current diff node carries a change.
4653///
4654/// @return true iff the current diff node carries a change.
4655bool
4657{return first_enum() != second_enum();}
4658
4659/// @return the kind of local change carried by the current diff node.
4660/// The value returned is zero if the current node carries no local
4661/// change.
4662enum change_kind
4664{
4665 ir::change_kind k = ir::NO_CHANGE_KIND;
4666 if (!equals(*first_enum(), *second_enum(), &k))
4667 return k & ir::ALL_LOCAL_CHANGES_MASK;
4668 return ir::NO_CHANGE_KIND;
4669}
4670
4671/// Report the differences between the two enums.
4672///
4673/// @param out the output stream to send the report to.
4674///
4675/// @param indent the string to use for indentation.
4676void
4677enum_diff::report(ostream& out, const string& indent) const
4678{
4679 context()->get_reporter()->report(*this, out, indent);
4680}
4681
4682/// Compute the set of changes between two instances of @ref
4683/// enum_type_decl.
4684///
4685/// Note that the two types must have been created in the same @ref
4686/// environment, otherwise, this function aborts.
4687///
4688/// @param first a pointer to the first enum_type_decl to consider.
4689///
4690/// @param second a pointer to the second enum_type_decl to consider.
4691///
4692/// @return the resulting diff of the two enums @p first and @p
4693/// second.
4694///
4695/// @param ctxt the diff context to use.
4696enum_diff_sptr
4698 const enum_type_decl_sptr second,
4699 diff_context_sptr ctxt)
4700{
4701 diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4702 second->get_underlying_type(),
4703 ctxt);
4704 enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4705 if (first != second)
4706 {
4707 compute_diff(first->get_enumerators().begin(),
4708 first->get_enumerators().end(),
4709 second->get_enumerators().begin(),
4710 second->get_enumerators().end(),
4711 d->priv_->enumerators_changes_);
4712 d->ensure_lookup_tables_populated();
4713 }
4714 ctxt->initialize_canonical_diff(d);
4715
4716 return d;
4717}
4718// </enum_diff stuff>
4719
4720// <class_or_union_diff stuff>
4721
4722/// Test if the current diff node carries a member type change for a
4723/// member type which name is the same as the name of a given type
4724/// declaration.
4725///
4726/// @param d the type declaration which name should be equal to the
4727/// name of the member type that might have changed.
4728///
4729/// @return the member type that has changed, iff there were a member
4730/// type (which name is the same as the name of @p d) that changed.
4731/// Note that the member type that is returned is the new value of the
4732/// member type that changed.
4735{
4736 string qname = d->get_qualified_name();
4737 string_diff_sptr_map::const_iterator it =
4738 changed_member_types_.find(qname);
4739
4740 return ((it == changed_member_types_.end())
4742 : it->second->second_subject());
4743}
4744
4745/// Test if the current diff node carries a data member change for a
4746/// data member which name is the same as the name of a given type
4747/// declaration.
4748///
4749/// @param d the type declaration which name should be equal to the
4750/// name of the data member that might have changed.
4751///
4752/// @return the data member that has changed, iff there were a data
4753/// member type (which name is the same as the name of @p d) that
4754/// changed. Note that the data member that is returned is the new
4755/// value of the data member that changed.
4756decl_base_sptr
4758{
4759 string qname = d->get_qualified_name();
4760 string_var_diff_sptr_map::const_iterator it =
4761 subtype_changed_dm_.find(qname);
4762
4763 if (it == subtype_changed_dm_.end())
4764 return decl_base_sptr();
4765 return it->second->second_var();
4766}
4767
4768/// Test if the current diff node carries a member class template
4769/// change for a member class template which name is the same as the
4770/// name of a given type declaration.
4771///
4772/// @param d the type declaration which name should be equal to the
4773/// name of the member class template that might have changed.
4774///
4775/// @return the member class template that has changed, iff there were
4776/// a member class template (which name is the same as the name of @p
4777/// d) that changed. Note that the member class template that is
4778/// returned is the new value of the member class template that
4779/// changed.
4780decl_base_sptr
4782{
4783 string qname = d->get_qualified_name();
4784 string_diff_sptr_map::const_iterator it =
4785 changed_member_class_tmpls_.find(qname);
4786
4787 return ((it == changed_member_class_tmpls_.end())
4788 ? decl_base_sptr()
4789 : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4790}
4791
4792/// Get the number of non static data members that were deleted.
4793///
4794/// @return the number of non static data members that were deleted.
4795size_t
4797{
4798 size_t result = 0;
4799
4800 for (string_decl_base_sptr_map::const_iterator i =
4801 deleted_data_members_.begin();
4802 i != deleted_data_members_.end();
4803 ++i)
4804 if (is_member_decl(i->second)
4805 && !get_member_is_static(i->second))
4806 ++result;
4807
4808 return result;
4809}
4810
4811/// Get the number of non static data members that were inserted.
4812///
4813/// @return the number of non static data members that were inserted.
4814size_t
4816{
4817 size_t result = 0;
4818
4819 for (string_decl_base_sptr_map::const_iterator i =
4820 inserted_data_members_.begin();
4821 i != inserted_data_members_.end();
4822 ++i)
4823 if (is_member_decl(i->second)
4824 && !get_member_is_static(i->second))
4825 ++result;
4826
4827 return result;
4828}
4829
4830/// Get the number of data member sub-type changes carried by the
4831/// current diff node that were filtered out.
4832///
4833/// @param local_only if true, it means that only (filtered) local
4834/// changes are considered.
4835///
4836/// @return the number of data member sub-type changes carried by the
4837/// current diff node that were filtered out.
4838size_t
4840{
4841 size_t num_filtered= 0;
4842 for (var_diff_sptrs_type::const_iterator i =
4843 sorted_subtype_changed_dm_.begin();
4844 i != sorted_subtype_changed_dm_.end();
4845 ++i)
4846 {
4847 if (local_only)
4848 {
4849 if ((*i)->has_changes()
4850 && !(*i)->has_local_changes_to_be_reported())
4851 ++num_filtered;
4852 }
4853 else
4854 {
4855 if ((*i)->is_filtered_out())
4856 ++num_filtered;
4857 }
4858 }
4859 return num_filtered;
4860}
4861
4862/// Get the number of data member changes carried by the current diff
4863/// node that were filtered out.
4864///
4865/// @param local_only if true, it means that only (filtered) local
4866/// changes are considered.
4867///
4868/// @return the number of data member changes carried by the current
4869/// diff node that were filtered out.
4870size_t
4872{
4873 size_t num_filtered= 0;
4874
4875 for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4876 i != changed_dm_.end();
4877 ++i)
4878 {
4879 diff_sptr diff = i->second;
4880 if (local_only)
4881 {
4883 || diff->is_filtered_out())
4884 ++num_filtered;
4885 }
4886 else
4887 {
4888 if (diff->is_filtered_out())
4889 ++num_filtered;
4890 }
4891 }
4892 return num_filtered;
4893}
4894
4895/// Skip the processing of the current member function if its
4896/// virtual-ness is disallowed by the user.
4897///
4898/// This is to be used in the member functions below that are used to
4899/// count the number of filtered inserted, deleted and changed member
4900/// functions.
4901#define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
4902 do { \
4903 if (get_member_function_is_virtual(f) \
4904 || get_member_function_is_virtual(s)) \
4905 { \
4906 if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
4907 continue; \
4908 } \
4909 else \
4910 { \
4911 if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
4912 continue; \
4913 } \
4914 } while (false)
4915
4916/// Get the number of member functions changes carried by the current
4917/// diff node that were filtered out.
4918///
4919/// @return the number of member functions changes carried by the
4920/// current diff node that were filtered out.
4921size_t
4923(const diff_context_sptr& ctxt)
4924{
4925 size_t count = 0;
4926 diff_category allowed_category = ctxt->get_allowed_category();
4927
4928 for (function_decl_diff_sptrs_type::const_iterator i =
4929 sorted_changed_member_functions_.begin();
4930 i != sorted_changed_member_functions_.end();
4931 ++i)
4932 {
4933 method_decl_sptr f =
4934 dynamic_pointer_cast<method_decl>
4935 ((*i)->first_function_decl());
4936 ABG_ASSERT(f);
4937
4938 method_decl_sptr s =
4939 dynamic_pointer_cast<method_decl>
4940 ((*i)->second_function_decl());
4941 ABG_ASSERT(s);
4942
4944
4945 diff_sptr diff = *i;
4946 ctxt->maybe_apply_filters(diff);
4947
4948 if (diff->is_filtered_out())
4949 ++count;
4950 }
4951
4952 return count;
4953}
4954
4955/// Get the number of member functions insertions carried by the current
4956/// diff node that were filtered out.
4957///
4958/// @return the number of member functions insertions carried by the
4959/// current diff node that were filtered out.
4960size_t
4962(const diff_context_sptr& ctxt)
4963{
4964 size_t count = 0;
4965 diff_category allowed_category = ctxt->get_allowed_category();
4966
4967 for (string_member_function_sptr_map::const_iterator i =
4968 inserted_member_functions_.begin();
4969 i != inserted_member_functions_.end();
4970 ++i)
4971 {
4972 method_decl_sptr f = i->second,
4973 s = i->second;
4974
4976
4977 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4978 ctxt->maybe_apply_filters(diff);
4979
4981 && diff->is_filtered_out())
4982 ++count;
4983 }
4984
4985 return count;
4986}
4987
4988/// Get the number of member functions deletions carried by the current
4989/// diff node that were filtered out.
4990///
4991/// @return the number of member functions deletions carried by the
4992/// current diff node that were filtered out.
4993size_t
4995(const diff_context_sptr& ctxt)
4996{
4997 size_t count = 0;
4998 diff_category allowed_category = ctxt->get_allowed_category();
4999
5000 for (string_member_function_sptr_map::const_iterator i =
5001 deleted_member_functions_.begin();
5002 i != deleted_member_functions_.end();
5003 ++i)
5004 {
5005 method_decl_sptr f = i->second,
5006 s = i->second;
5007
5009
5010 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5011 ctxt->maybe_apply_filters(diff);
5012
5014 && diff->is_filtered_out())
5015 ++count;
5016 }
5017
5018 return count;
5019}
5020
5021/// Clear the lookup tables useful for reporting.
5022///
5023/// This function must be updated each time a lookup table is added or
5024/// removed from the class_or_union_diff::priv.
5025void
5027{
5028 priv_->deleted_member_types_.clear();
5029 priv_->inserted_member_types_.clear();
5030 priv_->changed_member_types_.clear();
5031 priv_->deleted_data_members_.clear();
5032 priv_->inserted_data_members_.clear();
5033 priv_->subtype_changed_dm_.clear();
5034 priv_->deleted_member_functions_.clear();
5035 priv_->inserted_member_functions_.clear();
5036 priv_->changed_member_functions_.clear();
5037 priv_->deleted_member_class_tmpls_.clear();
5038 priv_->inserted_member_class_tmpls_.clear();
5039 priv_->changed_member_class_tmpls_.clear();
5040}
5041
5042/// Tests if the lookup tables are empty.
5043///
5044/// @return true if the lookup tables are empty, false otherwise.
5045bool
5047{
5048 return (priv_->deleted_member_types_.empty()
5049 && priv_->inserted_member_types_.empty()
5050 && priv_->changed_member_types_.empty()
5051 && priv_->deleted_data_members_.empty()
5052 && priv_->inserted_data_members_.empty()
5053 && priv_->subtype_changed_dm_.empty()
5054 && priv_->inserted_member_functions_.empty()
5055 && priv_->deleted_member_functions_.empty()
5056 && priv_->changed_member_functions_.empty()
5057 && priv_->deleted_member_class_tmpls_.empty()
5058 && priv_->inserted_member_class_tmpls_.empty()
5059 && priv_->changed_member_class_tmpls_.empty());
5060}
5061
5062/// If the lookup tables are not yet built, walk the differences and
5063/// fill them.
5064void
5066{
5067 {
5068 edit_script& e = priv_->member_types_changes_;
5069
5070 for (vector<deletion>::const_iterator it = e.deletions().begin();
5071 it != e.deletions().end();
5072 ++it)
5073 {
5074 unsigned i = it->index();
5075 decl_base_sptr d =
5076 get_type_declaration(first_class_or_union()->get_member_types()[i]);
5077 class_or_union_sptr record_type = is_class_or_union_type(d);
5078 if (record_type && record_type->get_is_declaration_only())
5079 continue;
5080 string name = d->get_name();
5081 priv_->deleted_member_types_[name] = d;
5082 }
5083
5084 for (vector<insertion>::const_iterator it = e.insertions().begin();
5085 it != e.insertions().end();
5086 ++it)
5087 {
5088 for (vector<unsigned>::const_iterator iit =
5089 it->inserted_indexes().begin();
5090 iit != it->inserted_indexes().end();
5091 ++iit)
5092 {
5093 unsigned i = *iit;
5094 decl_base_sptr d =
5095 get_type_declaration(second_class_or_union()->get_member_types()[i]);
5096 class_or_union_sptr record_type = is_class_or_union_type(d);
5097 if (record_type && record_type->get_is_declaration_only())
5098 continue;
5099 string name = d->get_name();
5100 string_decl_base_sptr_map::const_iterator j =
5101 priv_->deleted_member_types_.find(name);
5102 if (j != priv_->deleted_member_types_.end())
5103 {
5104 if (*j->second != *d)
5105 priv_->changed_member_types_[name] =
5106 compute_diff(j->second, d, context());
5107
5108 priv_->deleted_member_types_.erase(j);
5109 }
5110 else
5111 priv_->inserted_member_types_[name] = d;
5112 }
5113 }
5114 }
5115
5116 {
5117 edit_script& e = priv_->data_members_changes_;
5118
5119 for (vector<deletion>::const_iterator it = e.deletions().begin();
5120 it != e.deletions().end();
5121 ++it)
5122 {
5123 unsigned i = it->index();
5124 var_decl_sptr data_member =
5125 is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
5126 string name = data_member->get_anon_dm_reliable_name();
5127
5128 ABG_ASSERT(priv_->deleted_data_members_.find(name)
5129 == priv_->deleted_data_members_.end());
5130 priv_->deleted_data_members_[name] = data_member;
5131 }
5132
5133 for (vector<insertion>::const_iterator it = e.insertions().begin();
5134 it != e.insertions().end();
5135 ++it)
5136 {
5137 for (vector<unsigned>::const_iterator iit =
5138 it->inserted_indexes().begin();
5139 iit != it->inserted_indexes().end();
5140 ++iit)
5141 {
5142 unsigned i = *iit;
5143 decl_base_sptr d =
5144 second_class_or_union()->get_non_static_data_members()[i];
5145 var_decl_sptr added_dm = is_var_decl(d);
5146 string name = added_dm->get_anon_dm_reliable_name();
5147 ABG_ASSERT(priv_->inserted_data_members_.find(name)
5148 == priv_->inserted_data_members_.end());
5149
5150 bool ignore_added_anonymous_data_member = false;
5151 if (is_anonymous_data_member(added_dm))
5152 {
5153 //
5154 // Handle insertion of anonymous data member to
5155 // replace existing data members.
5156 //
5157 // For instance consider this:
5158 // struct S
5159 // {
5160 // int a;
5161 // int b;
5162 // int c;
5163 // };// end struct S
5164 //
5165 // Where the data members 'a' and 'b' are replaced
5166 // by an anonymous data member without changing the
5167 // effective bit layout of the structure:
5168 //
5169 // struct S
5170 // {
5171 // struct
5172 // {
5173 // union
5174 // {
5175 // int a;
5176 // char a_1;
5177 // };
5178 // union
5179 // {
5180 // int b;
5181 // char b_1;
5182 // };
5183 // };
5184 // int c;
5185 // }; // end struct S
5186 //
5187 var_decl_sptr replaced_dm, replacing_dm;
5188 bool added_anon_dm_changes_dm = false;
5189 // The vector of data members replaced by anonymous
5190 // data members.
5191 vector<var_decl_sptr> dms_replaced_by_anon_dm;
5192
5193 //
5194 // Let's start collecting the set of data members
5195 // which have been replaced by anonymous types in a
5196 // harmless way. These are going to be collected into
5197 // dms_replaced_by_anon_dm and, ultimately, into
5198 // priv_->dms_replaced_by_adms_
5199 //
5200 for (string_decl_base_sptr_map::const_iterator it =
5201 priv_->deleted_data_members_.begin();
5202 it != priv_->deleted_data_members_.end();
5203 ++it)
5204 {
5205 // We don't support this pattern for anonymous
5206 // data members themselves being replaced. If
5207 // that occurs then we'll just report it verbatim.
5208 if (is_anonymous_data_member(it->second))
5209 continue;
5210
5211 string deleted_dm_name = it->second->get_name();
5212 if ((replacing_dm =
5214 deleted_dm_name)))
5215 {
5216 // So it looks like replacing_dm might have
5217 // replaced the data member which name is
5218 // 'deleted_dm_name'. Let's look deeper to be
5219 // sure.
5220 //
5221 // Note that replacing_dm is part (member) of
5222 // an anonymous data member that might replace
5223 // replaced_dm.
5224
5225 // So let's get that replaced data member.
5226 replaced_dm = is_var_decl(it->second);
5227 size_t replaced_dm_offset =
5228 get_data_member_offset(replaced_dm),
5229 replacing_dm_offset =
5230 get_absolute_data_member_offset(replacing_dm);
5231
5232 if (replaced_dm_offset != replacing_dm_offset)
5233 {
5234 // So the replacing data member and the
5235 // replaced data member don't have the
5236 // same offset. This is not the pattern we
5237 // are looking for. Rather, it looks like
5238 // the anonymous data member has *changed*
5239 // the data member.
5240 added_anon_dm_changes_dm = true;
5241 break;
5242 }
5243
5244 if (replaced_dm->get_type()->get_size_in_bits()
5245 == replaced_dm->get_type()->get_size_in_bits())
5246 dms_replaced_by_anon_dm.push_back(replaced_dm);
5247 else
5248 {
5249 added_anon_dm_changes_dm = true;
5250 break;
5251 }
5252 }
5253 }
5254
5255 // Now walk dms_replaced_by_anon_dm to fill up
5256 // priv_->dms_replaced_by_adms_ with the set of data
5257 // members replaced by anonymous data members.
5258 if (!added_anon_dm_changes_dm
5259 && !dms_replaced_by_anon_dm.empty())
5260 {
5261 // See if the added data member isn't too big.
5262 type_base_sptr added_dm_type = added_dm->get_type();
5263 ABG_ASSERT(added_dm_type);
5264 var_decl_sptr new_next_dm =
5266 added_dm);
5267 var_decl_sptr old_next_dm =
5268 first_class_or_union()->find_data_member(new_next_dm);
5269
5270 if (!old_next_dm
5271 || (old_next_dm
5272 && (get_absolute_data_member_offset(old_next_dm)
5273 == get_absolute_data_member_offset(new_next_dm))))
5274 {
5275 // None of the data members that are replaced
5276 // by the added union should be considered as
5277 // having been deleted.
5278 ignore_added_anonymous_data_member = true;
5279 for (vector<var_decl_sptr>::const_iterator i =
5280 dms_replaced_by_anon_dm.begin();
5281 i != dms_replaced_by_anon_dm.end();
5282 ++i)
5283 {
5284 string n = (*i)->get_name();
5285 priv_->dms_replaced_by_adms_[n] =
5286 added_dm;
5287 priv_->deleted_data_members_.erase(n);
5288 }
5289 }
5290 }
5291 }
5292
5293 if (!ignore_added_anonymous_data_member)
5294 {
5295 // Detect changed data members.
5296 //
5297 // A changed data member (that we shall name D) is a data
5298 // member that satisfies the conditions below:
5299 //
5300 // 1/ It must have been added.
5301 //
5302 // 2/ It must have been deleted as well.
5303 //
5304 // 3/ There must be a non-empty difference between the
5305 // deleted D and the added D.
5306 string_decl_base_sptr_map::const_iterator j =
5307 priv_->deleted_data_members_.find(name);
5308 if (j != priv_->deleted_data_members_.end())
5309 {
5310 if (*j->second != *d)
5311 {
5312 var_decl_sptr old_dm = is_var_decl(j->second);
5313 priv_->subtype_changed_dm_[name]=
5314 compute_diff(old_dm, added_dm, context());
5315 }
5316 priv_->deleted_data_members_.erase(j);
5317 }
5318 else
5319 priv_->inserted_data_members_[name] = d;
5320 }
5321 }
5322 }
5323
5324 // Now detect when a data member is deleted from offset N and
5325 // another one is added to offset N. In that case, we want to be
5326 // able to say that the data member at offset N changed.
5327 for (string_decl_base_sptr_map::const_iterator i =
5328 priv_->deleted_data_members_.begin();
5329 i != priv_->deleted_data_members_.end();
5330 ++i)
5331 {
5332 unsigned offset = get_data_member_offset(i->second);
5333 priv_->deleted_dm_by_offset_[offset] = i->second;
5334 }
5335
5336 for (string_decl_base_sptr_map::const_iterator i =
5337 priv_->inserted_data_members_.begin();
5338 i != priv_->inserted_data_members_.end();
5339 ++i)
5340 {
5341 unsigned offset = get_data_member_offset(i->second);
5342 priv_->inserted_dm_by_offset_[offset] = i->second;
5343 }
5344
5345 for (unsigned_decl_base_sptr_map::const_iterator i =
5346 priv_->inserted_dm_by_offset_.begin();
5347 i != priv_->inserted_dm_by_offset_.end();
5348 ++i)
5349 {
5350 unsigned_decl_base_sptr_map::const_iterator j =
5351 priv_->deleted_dm_by_offset_.find(i->first);
5352 if (j != priv_->deleted_dm_by_offset_.end())
5353 {
5354 var_decl_sptr old_dm = is_var_decl(j->second);
5355 var_decl_sptr new_dm = is_var_decl(i->second);
5356 priv_->changed_dm_[i->first] =
5357 compute_diff(old_dm, new_dm, context());
5358 }
5359 }
5360
5361 for (unsigned_var_diff_sptr_map::const_iterator i =
5362 priv_->changed_dm_.begin();
5363 i != priv_->changed_dm_.end();
5364 ++i)
5365 {
5366 priv_->deleted_dm_by_offset_.erase(i->first);
5367 priv_->inserted_dm_by_offset_.erase(i->first);
5368 priv_->deleted_data_members_.erase
5369 (i->second->first_var()->get_anon_dm_reliable_name());
5370 priv_->inserted_data_members_.erase
5371 (i->second->second_var()->get_anon_dm_reliable_name());
5372 }
5373
5374 // Now detect anonymous data members that might appear as deleted
5375 // even though all their data members are still present. Consider
5376 // these as being non-deleted.
5377 string_decl_base_sptr_map non_anonymous_dms_in_second_class;
5379 non_anonymous_dms_in_second_class);
5380 vector<string> deleted_data_members_to_delete;
5381 // Walk data members considered deleted ...
5382 for (auto& entry : priv_->deleted_data_members_)
5383 {
5384 var_decl_sptr data_member = is_var_decl(entry.second);
5385 ABG_ASSERT(data_member);
5386 if (is_anonymous_data_member(data_member))
5387 {
5388 // Let's look at this anonymous data member that is
5389 // considered deleted because it's moved from where it was
5390 // initially, at very least. If its leaf data members are
5391 // still present in the second class then, we won't
5392 // consider it as deleted.
5393 class_or_union_sptr cou = anonymous_data_member_to_class_or_union(data_member);
5394 ABG_ASSERT(cou);
5395 string_decl_base_sptr_map non_anonymous_data_members;
5396 // Lets collect the leaf data members of the anonymous
5397 // data member.
5398 collect_non_anonymous_data_members(cou, non_anonymous_data_members);
5399 bool anonymous_dm_members_present = true;
5400 // Let's see if at least one of the leaf members of the
5401 // anonymous data member is NOT present in the second
5402 // version of the class.
5403 for (auto& e : non_anonymous_data_members)
5404 {
5405 if (non_anonymous_dms_in_second_class.find(e.first)
5406 == non_anonymous_dms_in_second_class.end())
5407 // Grrr, OK, it looks like at least one leaf data
5408 // member of the original anonymous data member was
5409 // removed from the class, so yeah, the anonymous
5410 // data member might have been removed after all.
5411 anonymous_dm_members_present = false;
5412 }
5413 if (anonymous_dm_members_present)
5414 // All leaf data members of the anonymous data member
5415 // are still present in the second version of the class.
5416 // So let's mark that anonymous data member as NOT being
5417 // deleted.
5418 deleted_data_members_to_delete.push_back(data_member->get_anon_dm_reliable_name());
5419 }
5420 }
5421 // All anonymous data members that were recognized as being NOT
5422 // deleted should be removed from the set of deleted data members
5423 // now.
5424 for (string& name_of_dm_to_delete: deleted_data_members_to_delete)
5425 priv_->deleted_data_members_.erase(name_of_dm_to_delete);
5426 }
5427 sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5428 priv_->sorted_subtype_changed_dm_);
5429 sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5430 priv_->sorted_changed_dm_);
5431
5432 {
5433 edit_script& e = priv_->member_class_tmpls_changes_;
5434
5435 for (vector<deletion>::const_iterator it = e.deletions().begin();
5436 it != e.deletions().end();
5437 ++it)
5438 {
5439 unsigned i = it->index();
5440 decl_base_sptr d =
5441 first_class_or_union()->get_member_class_templates()[i]->
5442 as_class_tdecl();
5443 string name = d->get_name();
5444 ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5445 == priv_->deleted_member_class_tmpls_.end());
5446 priv_->deleted_member_class_tmpls_[name] = d;
5447 }
5448
5449 for (vector<insertion>::const_iterator it = e.insertions().begin();
5450 it != e.insertions().end();
5451 ++it)
5452 {
5453 for (vector<unsigned>::const_iterator iit =
5454 it->inserted_indexes().begin();
5455 iit != it->inserted_indexes().end();
5456 ++iit)
5457 {
5458 unsigned i = *iit;
5459 decl_base_sptr d =
5460 second_class_or_union()->get_member_class_templates()[i]->
5461 as_class_tdecl();
5462 string name = d->get_name();
5463 ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5464 == priv_->inserted_member_class_tmpls_.end());
5465 string_decl_base_sptr_map::const_iterator j =
5466 priv_->deleted_member_class_tmpls_.find(name);
5467 if (j != priv_->deleted_member_class_tmpls_.end())
5468 {
5469 if (*j->second != *d)
5470 priv_->changed_member_types_[name]=
5471 compute_diff(j->second, d, context());
5472 priv_->deleted_member_class_tmpls_.erase(j);
5473 }
5474 else
5475 priv_->inserted_member_class_tmpls_[name] = d;
5476 }
5477 }
5478 }
5479 sort_string_diff_sptr_map(priv_->changed_member_types_,
5480 priv_->sorted_changed_member_types_);
5481}
5482
5483/// Allocate the memory for the priv_ pimpl data member of the @ref
5484/// class_or_union_diff class.
5485void
5487{
5488 if (!priv_)
5489 priv_.reset(new priv);
5490}
5491
5492/// Constructor for the @ref class_or_union_diff class.
5493///
5494/// @param first_scope the first @ref class_or_union of the diff node.
5495///
5496/// @param second_scope the second @ref class_or_union of the diff node.
5497///
5498/// @param ctxt the context of the diff.
5499class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5500 class_or_union_sptr second_scope,
5501 diff_context_sptr ctxt)
5502 : type_diff_base(first_scope, second_scope, ctxt)
5503 //priv_(new priv)
5504{}
5505
5506/// Getter of the private data of the @ref class_or_union_diff type.
5507///
5508/// Note that due to an optimization, the private data of @ref
5509/// class_or_union_diff can be shared among several instances of
5510/// class_or_union_diff, so you should never try to access
5511/// class_or_union_diff::priv directly.
5512///
5513/// When class_or_union_diff::priv is shared, this function returns
5514/// the correct shared one.
5515///
5516/// @return the (possibly) shared private data of the current instance
5517/// of @ref class_or_union_diff.
5518const class_or_union_diff::priv_ptr&
5520{
5521 if (priv_)
5522 return priv_;
5523
5524 // If the current class_or_union_diff::priv member is empty, then look for
5525 // the shared one, from the canonical type.
5526 class_or_union_diff *canonical =
5527 dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5528 ABG_ASSERT(canonical);
5529 ABG_ASSERT(canonical->priv_);
5530
5531 return canonical->priv_;
5532}
5533
5534/// Destructor of class_or_union_diff.
5536{
5537}
5538
5539/// @return the first @ref class_or_union involved in the diff.
5540class_or_union_sptr
5543
5544/// @return the second @ref class_or_union involved in the diff.
5545class_or_union_sptr
5548
5549/// @return the edit script of the member types of the two @ref
5550/// class_or_union.
5551const edit_script&
5553{return get_priv()->member_types_changes_;}
5554
5555/// @return the edit script of the member types of the two @ref
5556/// class_or_union.
5559{return get_priv()->member_types_changes_;}
5560
5561/// @return the edit script of the data members of the two @ref
5562/// class_or_union.
5563const edit_script&
5565{return get_priv()->data_members_changes_;}
5566
5567/// @return the edit script of the data members of the two @ref
5568/// class_or_union.
5571{return get_priv()->data_members_changes_;}
5572
5573/// Getter for the data members that got inserted.
5574///
5575/// @return a map of data members that got inserted.
5578{return get_priv()->inserted_data_members_;}
5579
5580/// Getter for the data members that got deleted.
5581///
5582/// @return a map of data members that got deleted.
5585{return get_priv()->deleted_data_members_;}
5586
5587/// @return the edit script of the member functions of the two @ref
5588/// class_or_union.
5589const edit_script&
5591{return get_priv()->member_fns_changes_;}
5592
5593/// Getter for the virtual members functions that have had a change in
5594/// a sub-type, without having a change in their symbol name.
5595///
5596/// @return a sorted vector of virtual member functions that have a
5597/// sub-type change.
5600{return get_priv()->sorted_changed_member_functions_;}
5601
5602/// @return the edit script of the member functions of the two
5603/// classes.
5606{return get_priv()->member_fns_changes_;}
5607
5608/// @return a map of member functions that got deleted.
5611{return get_priv()->deleted_member_functions_;}
5612
5613/// @return a map of member functions that got inserted.
5616{return get_priv()->inserted_member_functions_;}
5617
5618/// Getter of the map of data members that got replaced by another
5619/// data member. The key of the map is the offset at which the
5620/// element got replaced and the value is a pointer to the @ref
5621/// var_diff representing the replacement of the data member.
5622///
5623/// @return sorted vector of changed data member.
5626{return get_priv()->changed_dm_;}
5627
5628/// Getter of the sorted vector of data members that got replaced by
5629/// another data member.
5630///
5631/// @return sorted vector of changed data member.
5634{return get_priv()->sorted_changed_dm_;}
5635
5636/// Count the number of /filtered/ data members that got replaced by
5637/// another data member.
5638///
5639/// @return the number of changed data member that got filtered out.
5640size_t
5642{return get_priv()->count_filtered_changed_dm(local);}
5643
5644/// Getter of the sorted vector of data members with a (sub-)type change.
5645///
5646/// @return sorted vector of changed data member.
5649{return get_priv()->sorted_subtype_changed_dm_;}
5650
5651/// Count the number of /filtered/ data members with a sub-type change.
5652///
5653/// @return the number of changed data member that got filtered out.
5654size_t
5656{return get_priv()->count_filtered_subtype_changed_dm(local);}
5657
5658/// Get the map of data members that got replaced by anonymous data
5659/// members.
5660///
5661/// The key of a map entry is the name of the replaced data member and
5662/// the value is the anonymous data member that replaces it.
5663///
5664/// @return the map of data members replaced by anonymous data
5665/// members.
5668{return get_priv()->dms_replaced_by_adms_;}
5669
5670/// Get an ordered vector of of data members that got replaced by
5671/// anonymous data members.
5672///
5673/// This returns a vector of pair of two data members: the one that
5674/// was replaced, and the anonymous data member that replaced it.
5675///
5676/// @return the sorted vector data members replaced by anonymous data members.
5679{
5680 if (priv_->dms_replaced_by_adms_ordered_.empty())
5681 {
5682 for (string_decl_base_sptr_map::const_iterator it =
5683 priv_->dms_replaced_by_adms_.begin();
5684 it != priv_->dms_replaced_by_adms_.end();
5685 ++it)
5686 {
5687 const var_decl_sptr dm =
5688 first_class_or_union()->find_data_member(it->first);
5689 ABG_ASSERT(dm);
5690 changed_var_sptr changed_dm(dm, is_data_member(it->second));
5691 priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5692 }
5693 sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5694 }
5695
5696 return priv_->dms_replaced_by_adms_ordered_;
5697}
5698
5699/// @return the edit script of the member function templates of the two
5700/// @ref class_or_union.
5701const edit_script&
5703{return get_priv()->member_fn_tmpls_changes_;}
5704
5705/// @return the edit script of the member function templates of the
5706/// two @ref class_or_union.
5709{return get_priv()->member_fn_tmpls_changes_;}
5710
5711/// @return the edit script of the member class templates of the two
5712/// @ref class_or_union.
5713const edit_script&
5715{return get_priv()->member_class_tmpls_changes_;}
5716
5717/// @return the edit script of the member class templates of the two
5718/// @ref class_or_union.
5721{return get_priv()->member_class_tmpls_changes_;}
5722
5723/// Test if the current diff node carries a change.
5724bool
5727
5728/// @return the kind of local change carried by the current diff node.
5729/// The value returned is zero if the current node carries no local
5730/// change.
5731enum change_kind
5733{
5734 ir::change_kind k = ir::NO_CHANGE_KIND;
5736 return k & ir::ALL_LOCAL_CHANGES_MASK;
5737 return ir::NO_CHANGE_KIND;
5738}
5739
5740
5741/// Report the changes carried by the current @ref class_or_union_diff
5742/// node in a textual format.
5743///
5744/// @param out the output stream to write the textual report to.
5745///
5746/// @param indent the number of white space to use as indentation.
5747void
5748class_or_union_diff::report(ostream& out, const string& indent) const
5749{
5750 context()->get_reporter()->report(*this, out, indent);
5751}
5752
5753/// Populate the vector of children node of the @ref diff base type
5754/// sub-object of this instance of @ref class_or_union_diff.
5755///
5756/// The children node can then later be retrieved using
5757/// diff::children_node().
5758void
5760{
5761 // data member changes
5762 for (var_diff_sptrs_type::const_iterator i =
5763 get_priv()->sorted_subtype_changed_dm_.begin();
5764 i != get_priv()->sorted_subtype_changed_dm_.end();
5765 ++i)
5766 if (diff_sptr d = *i)
5768
5769 for (var_diff_sptrs_type::const_iterator i =
5770 get_priv()->sorted_changed_dm_.begin();
5771 i != get_priv()->sorted_changed_dm_.end();
5772 ++i)
5773 if (diff_sptr d = *i)
5775
5776 // member types changes
5777 for (diff_sptrs_type::const_iterator i =
5778 get_priv()->sorted_changed_member_types_.begin();
5779 i != get_priv()->sorted_changed_member_types_.end();
5780 ++i)
5781 if (diff_sptr d = *i)
5783
5784 // member function changes
5785 for (function_decl_diff_sptrs_type::const_iterator i =
5786 get_priv()->sorted_changed_member_functions_.begin();
5787 i != get_priv()->sorted_changed_member_functions_.end();
5788 ++i)
5789 if (diff_sptr d = *i)
5791}
5792
5793// </class_or_union_diff stuff>
5794
5795//<class_diff stuff>
5796
5797/// Clear the lookup tables useful for reporting.
5798///
5799/// This function must be updated each time a lookup table is added or
5800/// removed from the class_diff::priv.
5801void
5802class_diff::clear_lookup_tables(void)
5803{
5804 priv_->deleted_bases_.clear();
5805 priv_->inserted_bases_.clear();
5806 priv_->changed_bases_.clear();
5807}
5808
5809/// Tests if the lookup tables are empty.
5810///
5811/// @return true if the lookup tables are empty, false otherwise.
5812bool
5813class_diff::lookup_tables_empty(void) const
5814{
5815 return (priv_->deleted_bases_.empty()
5816 && priv_->inserted_bases_.empty()
5817 && priv_->changed_bases_.empty());
5818}
5819
5820/// Find a virtual destructor in a map of member functions
5821///
5822/// @param map the map of member functions. Note that the key of the
5823/// map is the member function name. The key is the member function.
5824///
5825/// @return an iterator to the destructor found or, if no virtual destructor
5826/// was found, return map.end()
5827static string_member_function_sptr_map::const_iterator
5828find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
5829{
5830 for (string_member_function_sptr_map::const_iterator i = map.begin();
5831 i !=map.end();
5832 ++i)
5833 {
5834 if (get_member_function_is_dtor(i->second)
5835 && get_member_function_is_virtual(i->second))
5836 return i;
5837 }
5838 return map.end();
5839}
5840
5841/// If the lookup tables are not yet built, walk the differences and
5842/// fill them.
5843void
5844class_diff::ensure_lookup_tables_populated(void) const
5845{
5847
5848 if (!lookup_tables_empty())
5849 return;
5850
5851 {
5852 edit_script& e = get_priv()->base_changes_;
5853
5854 for (vector<deletion>::const_iterator it = e.deletions().begin();
5855 it != e.deletions().end();
5856 ++it)
5857 {
5858 unsigned i = it->index();
5860 first_class_decl()->get_base_specifiers()[i];
5861 string name = b->get_base_class()->get_qualified_name();
5862 ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5863 == get_priv()->deleted_bases_.end());
5864 get_priv()->deleted_bases_[name] = b;
5865 }
5866
5867 for (vector<insertion>::const_iterator it = e.insertions().begin();
5868 it != e.insertions().end();
5869 ++it)
5870 {
5871 for (vector<unsigned>::const_iterator iit =
5872 it->inserted_indexes().begin();
5873 iit != it->inserted_indexes().end();
5874 ++iit)
5875 {
5876 unsigned i = *iit;
5878 second_class_decl()->get_base_specifiers()[i];
5879 string name = b->get_base_class()->get_qualified_name();
5880 ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5881 == get_priv()->inserted_bases_.end());
5882 string_base_sptr_map::const_iterator j =
5883 get_priv()->deleted_bases_.find(name);
5884 if (j != get_priv()->deleted_bases_.end())
5885 {
5886 if (j->second != b)
5887 get_priv()->changed_bases_[name] =
5888 compute_diff(j->second, b, context());
5889 else
5890 // The base class changed place. IOW, the base
5891 // classes got re-arranged. Let's keep track of the
5892 // base classes that moved.
5893 get_priv()->moved_bases_.push_back(b);
5894 get_priv()->deleted_bases_.erase(j);
5895 }
5896 else
5897 get_priv()->inserted_bases_[name] = b;
5898 }
5899 }
5900
5901 // ===============================================================
5902 // Detect when a data member is deleted from the class but is now
5903 // present in one of the bases at the same offset. In that case,
5904 // the data member should not be considered as removed.
5905 // ===============================================================
5907 class_or_union_diff::priv_->deleted_data_members_;
5908
5909 vector<var_decl_sptr> deleted_data_members_present_in_bases;
5910 for (auto entry : deleted_data_members)
5911 {
5912 var_decl_sptr deleted_member = is_var_decl(entry.second);
5913 ABG_ASSERT(deleted_member);
5914 for (class_decl::base_spec_sptr base : second_class_decl()->get_base_specifiers())
5915 {
5916 class_decl_sptr klass = base->get_base_class();
5917 var_decl_sptr member = klass->find_data_member(deleted_member->get_name());
5918 if (member)
5919 deleted_data_members_present_in_bases.push_back(member);
5920 }
5921 }
5922 // Walk the deleted data members that are now in one of the bases,
5923 // of the new type, at the same offset, and let's see if they have
5924 // sub-type changes. In any cases, these should not be considered
5925 // as being deleted.
5926 for (var_decl_sptr m : deleted_data_members_present_in_bases)
5927 {
5928 string name = m->get_name();
5929 auto it = deleted_data_members.find(name);
5930 ABG_ASSERT(it != deleted_data_members.end());
5931 var_decl_sptr deleted_member = is_var_decl(it->second);
5932 if (*deleted_member != *m)
5933 {
5934 var_diff_sptr dif = compute_diff(deleted_member, m, context());
5935 ABG_ASSERT(dif);
5936 class_or_union_diff::priv_->subtype_changed_dm_[name]= dif;
5937 }
5938 deleted_data_members.erase(name);
5939 }
5940 }
5941
5942 sort_string_base_sptr_map(get_priv()->deleted_bases_,
5943 get_priv()->sorted_deleted_bases_);
5944 sort_string_base_sptr_map(get_priv()->inserted_bases_,
5945 get_priv()->sorted_inserted_bases_);
5946 sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5947 get_priv()->sorted_changed_bases_);
5948
5949 {
5950 const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5951
5952 edit_script& e = p->member_fns_changes_;
5953
5954 for (vector<deletion>::const_iterator it = e.deletions().begin();
5955 it != e.deletions().end();
5956 ++it)
5957 {
5958 unsigned i = it->index();
5959 method_decl_sptr mem_fn =
5960 first_class_decl()->get_virtual_mem_fns()[i];
5961 string name = mem_fn->get_linkage_name();
5962 if (name.empty())
5963 name = mem_fn->get_pretty_representation();
5964 ABG_ASSERT(!name.empty());
5965 if (p->deleted_member_functions_.find(name)
5966 != p->deleted_member_functions_.end())
5967 continue;
5968 p->deleted_member_functions_[name] = mem_fn;
5969 }
5970
5971 for (vector<insertion>::const_iterator it = e.insertions().begin();
5972 it != e.insertions().end();
5973 ++it)
5974 {
5975 for (vector<unsigned>::const_iterator iit =
5976 it->inserted_indexes().begin();
5977 iit != it->inserted_indexes().end();
5978 ++iit)
5979 {
5980 unsigned i = *iit;
5981
5982 method_decl_sptr mem_fn =
5983 second_class_decl()->get_virtual_mem_fns()[i];
5984 string name = mem_fn->get_linkage_name();
5985 if (name.empty())
5986 name = mem_fn->get_pretty_representation();
5987 ABG_ASSERT(!name.empty());
5988 if (p->inserted_member_functions_.find(name)
5989 != p->inserted_member_functions_.end())
5990 continue;
5991 string_member_function_sptr_map::const_iterator j =
5992 p->deleted_member_functions_.find(name);
5993
5994 if (j != p->deleted_member_functions_.end())
5995 {
5996 if (*j->second != *mem_fn)
5997 p->changed_member_functions_[name] =
5998 compute_diff(static_pointer_cast<function_decl>(j->second),
5999 static_pointer_cast<function_decl>(mem_fn),
6000 context());
6001 p->deleted_member_functions_.erase(j);
6002 }
6003 else
6004 p->inserted_member_functions_[name] = mem_fn;
6005 }
6006 }
6007
6008 // Now walk the allegedly deleted member functions; check if their
6009 // underlying symbols are deleted as well; otherwise, consider
6010 // that the member function in question hasn't been deleted.
6011
6012 // Also, while walking the deleted member functions, we attend at
6013 // a particular cleanup business related to (virtual) C++
6014 // destructors:
6015 //
6016 // In the binary, there can be at least three types of
6017 // destructors, defined in the document
6018 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
6019 //
6020 // 1/ Base object destructor (aka D2 destructor):
6021 //
6022 // "A function that runs the destructors for non-static data
6023 // members of T and non-virtual direct base classes of T. "
6024 //
6025 // 2/ Complete object destructor (aka D1 destructor):
6026 //
6027 // "A function that, in addition to the actions required of a
6028 // base object destructor, runs the destructors for the
6029 // virtual base classes of T."
6030 //
6031 // 3/ Deleting destructor (aka D0 destructor):
6032 //
6033 // "A function that, in addition to the actions required of a
6034 // complete object destructor, calls the appropriate
6035 // deallocation function (i.e,. operator delete) for T."
6036 //
6037 // With binaries generated by GCC, these destructors might be ELF
6038 // clones of each others, meaning, their ELF symbols can be
6039 // aliases.
6040 //
6041 // Also, note that because the actual destructor invoked by user
6042 // code is virtual, it's invoked through the vtable. So the
6043 // presence of the underlying D0, D1, D2 in the binary might vary
6044 // without that variation being an ABI issue, provided that the
6045 // destructor invoked through the vtable is present.
6046 //
6047 // So, a particular virtual destructor implementation for a class
6048 // might disapear and be replaced by another one in a subsequent
6049 // version of the binary. If all versions of the binary have an
6050 // actual virtual destructor, things might be considered fine.
6051 vector<string> to_delete;
6052 corpus_sptr f = context()->get_first_corpus(),
6053 s = context()->get_second_corpus();
6054 if (s)
6055 for (string_member_function_sptr_map::const_iterator i =
6056 deleted_member_fns().begin();
6057 i != deleted_member_fns().end();
6058 ++i)
6059 {
6060 if (get_member_function_is_virtual(i->second))
6061 {
6062 if (get_member_function_is_dtor(i->second))
6063 {
6064 // If a particular virtual destructor is deleted,
6065 // but the new binary still have a virtual
6066 // destructor for that class we consider that things
6067 // are fine. For instance, in the
6068 // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
6069 // test, a new D4 destructor replaces the old ones.
6070 // But because the virtual destructor is still
6071 // there, this is not an ABI issue. So let's detect
6072 // this case.
6073 auto it =
6074 find_virtual_dtor_in_map(p->inserted_member_functions_);
6075 if (it != p->inserted_member_functions_.end())
6076 {
6077 // So the deleted virtual destructor is not
6078 // really deleted, because a proper virtual
6079 // destructor was added to the new version.
6080 // Let's remove the deleted/added virtual
6081 // destructor then.
6082 string name =
6083 (!i->second->get_linkage_name().empty())
6084 ? i->second->get_linkage_name()
6085 : i->second->get_pretty_representation();
6086 to_delete.push_back(name);
6087 p->inserted_member_functions_.erase(it);
6088 }
6089 }
6090 continue;
6091 }
6092 // We assume that all non-virtual member functions functions
6093 // we look at here have ELF symbols.
6094 if (!i->second->get_symbol()
6095 || s->lookup_function_symbol(*i->second->get_symbol()))
6096 to_delete.push_back(i->first);
6097 }
6098
6099
6100 for (vector<string>::const_iterator i = to_delete.begin();
6101 i != to_delete.end();
6102 ++i)
6103 p->deleted_member_functions_.erase(*i);
6104
6105 // Do something similar for added functions.
6106 to_delete.clear();
6107 if (f)
6108 for (string_member_function_sptr_map::const_iterator i =
6109 inserted_member_fns().begin();
6110 i != inserted_member_fns().end();
6111 ++i)
6112 {
6113 if (get_member_function_is_virtual(i->second))
6114 continue;
6115 // We assume that all non-virtual member functions functions
6116 // we look at here have ELF symbols.
6117 if (!i->second->get_symbol()
6118 || f->lookup_function_symbol(*i->second->get_symbol()))
6119 to_delete.push_back(i->first);
6120 }
6121
6122 for (vector<string>::const_iterator i = to_delete.begin();
6123 i != to_delete.end();
6124 ++i)
6125 p->inserted_member_functions_.erase(*i);
6126
6127 sort_string_member_function_sptr_map(p->deleted_member_functions_,
6128 p->sorted_deleted_member_functions_);
6129
6130 sort_string_member_function_sptr_map(p->inserted_member_functions_,
6131 p->sorted_inserted_member_functions_);
6132
6134 (p->changed_member_functions_,
6135 p->sorted_changed_member_functions_);
6136 }
6137}
6138
6139/// Allocate the memory for the priv_ pimpl data member of the @ref
6140/// class_diff class.
6141void
6142class_diff::allocate_priv_data()
6143{
6145 if (!priv_)
6146 priv_.reset(new priv);
6147}
6148
6149/// Test whether a given base class has changed. A base class has
6150/// changed if it's in both in deleted *and* inserted bases.
6151///
6152///@param d the declaration for the base class to consider.
6153///
6154/// @return the new base class if the given base class has changed, or
6155/// NULL if it hasn't.
6158{
6159 string qname = d->get_base_class()->get_qualified_name();
6160 string_base_diff_sptr_map::const_iterator it =
6161 changed_bases_.find(qname);
6162
6163 return (it == changed_bases_.end())
6165 : it->second->second_base();
6166
6167}
6168
6169/// Count the number of bases classes whose changes got filtered out.
6170///
6171/// @return the number of bases classes whose changes got filtered
6172/// out.
6173size_t
6175{
6176 size_t num_filtered = 0;
6177 for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
6178 i != sorted_changed_bases_.end();
6179 ++i)
6180 {
6181 diff_sptr diff = *i;
6182 if (diff && diff->is_filtered_out())
6183 ++num_filtered;
6184 }
6185 return num_filtered;
6186}
6187
6188/// Populate the vector of children node of the @ref diff base type
6189/// sub-object of this instance of @ref class_diff.
6190///
6191/// The children node can then later be retrieved using
6192/// diff::children_node().
6193void
6195{
6197
6198 // base class changes.
6199 for (base_diff_sptrs_type::const_iterator i =
6200 get_priv()->sorted_changed_bases_.begin();
6201 i != get_priv()->sorted_changed_bases_.end();
6202 ++i)
6203 if (diff_sptr d = *i)
6205}
6206
6207/// Constructor of class_diff
6208///
6209/// @param first_scope the first class of the diff.
6210///
6211/// @param second_scope the second class of the diff.
6212///
6213/// @param ctxt the diff context to use.
6215 class_decl_sptr second_scope,
6216 diff_context_sptr ctxt)
6217 : class_or_union_diff(first_scope, second_scope, ctxt)
6218 // We don't initialize the priv_ data member here. This is an
6219 // optimization to reduce memory consumption (and also execution
6220 // time) for cases where there are a lot of instances of
6221 // class_diff in the same equivalence class. In compute_diff(),
6222 // the priv_ is set to the priv_ of the canonical diff node.
6223 // See PR libabigail/17948.
6224{}
6225
6226class_diff::~class_diff()
6227{}
6228
6229/// Getter of the private data of the @ref class_diff type.
6230///
6231/// Note that due to an optimization, the private data of @ref
6232/// class_diff can be shared among several instances of class_diff, so
6233/// you should never try to access class_diff::priv directly.
6234///
6235/// When class_diff::priv is shared, this function returns the correct
6236/// shared one.
6237///
6238/// @return the (possibly) shared private data of the current instance
6239/// of class_diff.
6240const class_diff::priv_ptr&
6241class_diff::get_priv() const
6242{
6243 if (priv_)
6244 return priv_;
6245
6246 // If the current class_diff::priv member is empty, then look for
6247 // the shared one, from the canonical type.
6248 class_diff *canonical =
6249 dynamic_cast<class_diff*>(get_canonical_diff());
6250 ABG_ASSERT(canonical);
6251 ABG_ASSERT(canonical->priv_);
6252
6253 return canonical->priv_;
6254}
6255
6256/// @return the pretty representation of the current instance of @ref
6257/// class_diff.
6258const string&
6260{
6261 if (diff::priv_->pretty_representation_.empty())
6262 {
6263 std::ostringstream o;
6264 o << "class_diff["
6265 << first_subject()->get_pretty_representation()
6266 << ", "
6267 << second_subject()->get_pretty_representation()
6268 << "]";
6269 diff::priv_->pretty_representation_ = o.str();
6270 }
6271 return diff::priv_->pretty_representation_;
6272}
6273
6274/// Return true iff the current diff node carries a change.
6275///
6276/// @return true iff the current diff node carries a change.
6277bool
6279{return (first_class_decl() != second_class_decl());}
6280
6281/// @return the kind of local change carried by the current diff node.
6282/// The value returned is zero if the current node carries no local
6283/// change.
6284enum change_kind
6286{
6287 ir::change_kind k = ir::NO_CHANGE_KIND;
6288 if (!equals(*first_class_decl(), *second_class_decl(), &k))
6289 return k & ir::ALL_LOCAL_CHANGES_MASK;
6290 return ir::NO_CHANGE_KIND;
6291}
6292
6293/// @return the first class invoveld in the diff.
6294shared_ptr<class_decl>
6296{return dynamic_pointer_cast<class_decl>(first_subject());}
6297
6298/// Getter of the second class involved in the diff.
6299///
6300/// @return the second class invoveld in the diff
6301shared_ptr<class_decl>
6303{return dynamic_pointer_cast<class_decl>(second_subject());}
6304
6305/// @return the edit script of the bases of the two classes.
6306const edit_script&
6308{return get_priv()->base_changes_;}
6309
6310/// Getter for the deleted base classes of the diff.
6311///
6312/// @return a map containing the deleted base classes, keyed with
6313/// their pretty representation.
6316{return get_priv()->deleted_bases_;}
6317
6318/// Getter for the inserted base classes of the diff.
6319///
6320/// @return a map containing the inserted base classes, keyed with
6321/// their pretty representation.
6324{return get_priv()->inserted_bases_;}
6325
6326/// Getter for the changed base classes of the diff.
6327///
6328/// @return a sorted vector containing the changed base classes
6331{return get_priv()->sorted_changed_bases_;}
6332
6333/// Getter for the vector of bases that "moved".
6334/// That is, the vector of base types which position changed. If this
6335/// vector is not empty, it means the bases of the underlying class
6336/// type got re-ordered.
6337///
6338/// @return the vector of bases that moved.
6339const vector<class_decl::base_spec_sptr>&
6341{return get_priv()->moved_bases_;}
6342
6343/// @return the edit script of the bases of the two classes.
6346{return get_priv()->base_changes_;}
6347
6348/// Produce a basic report about the changes between two class_decl.
6349///
6350/// @param out the output stream to report the changes to.
6351///
6352/// @param indent the string to use as an indentation prefix in the
6353/// report.
6354void
6355class_diff::report(ostream& out, const string& indent) const
6356{
6357 context()->get_reporter()->report(*this, out, indent);
6358}
6359
6360/// Compute the set of changes between two instances of class_decl.
6361///
6362/// Note that the two types must have been created in the same @ref
6363/// environment, otherwise, this function aborts.
6364///
6365/// @param first the first class_decl to consider.
6366///
6367/// @param second the second class_decl to consider.
6368///
6369/// @return changes the resulting changes.
6370///
6371/// @param ctxt the diff context to use.
6374 const class_decl_sptr second,
6375 diff_context_sptr ctxt)
6376{
6379
6380 class_diff_sptr changes(new class_diff(f, s, ctxt));
6381
6382 ctxt->initialize_canonical_diff(changes);
6383 ABG_ASSERT(changes->get_canonical_diff());
6384
6385 if (!ctxt->get_canonical_diff_for(first, second))
6386 {
6387 // Either first or second is a decl-only class; let's set the
6388 // canonical diff here in that case.
6389 diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6390 ABG_ASSERT(canonical_diff);
6391 ctxt->set_canonical_diff_for(first, second, canonical_diff);
6392 }
6393
6394 // Ok, so this is an optimization. Do not freak out if it looks
6395 // weird, because, well, it does look weird. This speeds up
6396 // greatly, for instance, the test case given at PR
6397 // libabigail/17948.
6398 //
6399 // We are setting the private data of the new instance of class_diff
6400 // (which is 'changes') to the private data of its canonical
6401 // instance. That is, we are sharing the private data of 'changes'
6402 // with the private data of its canonical instance to consume less
6403 // memory in cases where the equivalence class of 'changes' is huge.
6404 //
6405 // But if changes is its own canonical instance, then we initialize
6406 // its private data properly
6407 if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6408 // changes is its own canonical instance, so it gets a brand new
6409 // private data.
6410 changes->allocate_priv_data();
6411 else
6412 {
6413 // changes has a non-empty equivalence class so it's going to
6414 // share its private data with its canonical instance. Next
6415 // time class_diff::get_priv() is invoked, it's going to return
6416 // the shared private data of the canonical instance.
6417 return changes;
6418 }
6419
6420 // Compare base specs
6421 compute_diff(f->get_base_specifiers().begin(),
6422 f->get_base_specifiers().end(),
6423 s->get_base_specifiers().begin(),
6424 s->get_base_specifiers().end(),
6425 changes->base_changes());
6426
6427 // Do *not* compare member types because it generates lots of noise
6428 // and I doubt it's really useful.
6429#if 0
6430 compute_diff(f->get_member_types().begin(),
6431 f->get_member_types().end(),
6432 s->get_member_types().begin(),
6433 s->get_member_types().end(),
6434 changes->member_types_changes());
6435#endif
6436
6437 // Compare data member
6438 compute_diff(f->get_non_static_data_members().begin(),
6439 f->get_non_static_data_members().end(),
6440 s->get_non_static_data_members().begin(),
6441 s->get_non_static_data_members().end(),
6442 changes->data_members_changes());
6443
6444 // Compare virtual member functions
6445 compute_diff(f->get_virtual_mem_fns().begin(),
6446 f->get_virtual_mem_fns().end(),
6447 s->get_virtual_mem_fns().begin(),
6448 s->get_virtual_mem_fns().end(),
6449 changes->member_fns_changes());
6450
6451 // Compare member function templates
6452 compute_diff(f->get_member_function_templates().begin(),
6453 f->get_member_function_templates().end(),
6454 s->get_member_function_templates().begin(),
6455 s->get_member_function_templates().end(),
6456 changes->member_fn_tmpls_changes());
6457
6458 // Likewise, do not compare member class templates
6459#if 0
6460 compute_diff(f->get_member_class_templates().begin(),
6461 f->get_member_class_templates().end(),
6462 s->get_member_class_templates().begin(),
6463 s->get_member_class_templates().end(),
6464 changes->member_class_tmpls_changes());
6465#endif
6466
6467 changes->ensure_lookup_tables_populated();
6468
6469 return changes;
6470}
6471
6472//</class_diff stuff>
6473
6474// <base_diff stuff>
6475
6476/// Populate the vector of children node of the @ref diff base type
6477/// sub-object of this instance of @ref base_diff.
6478///
6479/// The children node can then later be retrieved using
6480/// diff::children_node().
6481void
6484
6485/// @param first the first base spec to consider.
6486///
6487/// @param second the second base spec to consider.
6488///
6489/// @param ctxt the context of the diff. Note that this context
6490/// object must stay alive at least during the life time of the
6491/// current instance of @ref base_diff. Otherwise memory corruption
6492/// issues occur.
6495 class_diff_sptr underlying,
6496 diff_context_sptr ctxt)
6497 : diff(first, second, ctxt),
6498 priv_(new priv(underlying))
6499{}
6500
6501/// Getter for the first base spec of the diff object.
6502///
6503/// @return the first base specifier for the diff object.
6506{return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6507
6508/// Getter for the second base spec of the diff object.
6509///
6510/// @return the second base specifier for the diff object.
6513{return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6514
6515/// Getter for the diff object for the diff of the underlying base
6516/// classes.
6517///
6518/// @return the diff object for the diff of the underlying base
6519/// classes.
6520const class_diff_sptr
6522{return priv_->underlying_class_diff_;}
6523
6524/// Setter for the diff object for the diff of the underlyng base
6525/// classes.
6526///
6527/// @param d the new diff object for the diff of the underlying base
6528/// classes.
6529void
6531{priv_->underlying_class_diff_ = d;}
6532
6533/// @return the pretty representation for the current instance of @ref
6534/// base_diff.
6535const string&
6537{
6538 if (diff::priv_->pretty_representation_.empty())
6539 {
6540 std::ostringstream o;
6541 o << "base_diff["
6542 << first_subject()->get_pretty_representation()
6543 << ", "
6544 << second_subject()->get_pretty_representation()
6545 << "]";
6546 diff::priv_->pretty_representation_ = o.str();
6547 }
6548 return diff::priv_->pretty_representation_;
6549}
6550
6551/// Return true iff the current diff node carries a change.
6552///
6553/// Return true iff the current diff node carries a change.
6554bool
6556{return first_base() != second_base();}
6557
6558/// @return the kind of local change carried by the current diff node.
6559/// The value returned is zero if the current node carries no local
6560/// change.
6561enum change_kind
6563{
6564 ir::change_kind k = ir::NO_CHANGE_KIND;
6565 if (!equals(*first_base(), *second_base(), &k))
6566 return k & ir::ALL_LOCAL_CHANGES_MASK;
6567 return ir::NO_CHANGE_KIND;
6568}
6569
6570/// Generates a report for the current instance of base_diff.
6571///
6572/// @param out the output stream to send the report to.
6573///
6574/// @param indent the string to use for indentation.
6575void
6576base_diff::report(ostream& out, const string& indent) const
6577{
6578 context()->get_reporter()->report(*this, out, indent);
6579}
6580
6581/// Constructs the diff object representing a diff between two base
6582/// class specifications.
6583///
6584/// Note that the two artifacts must have been created in the same
6585/// @ref environment, otherwise, this function aborts.
6586///
6587/// @param first the first base class specification.
6588///
6589/// @param second the second base class specification.
6590///
6591/// @param ctxt the content of the diff.
6592///
6593/// @return the resulting diff object.
6596 const class_decl::base_spec_sptr second,
6597 diff_context_sptr ctxt)
6598{
6599 class_diff_sptr cl = compute_diff(first->get_base_class(),
6600 second->get_base_class(),
6601 ctxt);
6602 base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6603
6604 ctxt->initialize_canonical_diff(changes);
6605
6606 return changes;
6607}
6608
6609// </base_diff stuff>
6610
6611
6612// <union_diff stuff>
6613
6614/// Clear the lookup tables useful for reporting.
6615///
6616/// This function must be updated each time a lookup table is added or
6617/// removed from the union_diff::priv.
6618void
6619union_diff::clear_lookup_tables(void)
6621
6622/// Tests if the lookup tables are empty.
6623///
6624/// @return true if the lookup tables are empty, false otherwise.
6625bool
6626union_diff::lookup_tables_empty(void) const
6628
6629/// If the lookup tables are not yet built, walk the differences and
6630/// fill them.
6631void
6632union_diff::ensure_lookup_tables_populated(void) const
6634
6635/// Allocate the memory for the priv_ pimpl data member of the @ref
6636/// union_diff class.
6637void
6638union_diff::allocate_priv_data()
6639{
6641}
6642
6643/// Constructor for the @ref union_diff type.
6644///
6645/// @param first_union the first object of the comparison.
6646///
6647/// @param second_union the second object of the comparison.
6648///
6649/// @param ctxt the context of the comparison.
6650union_diff::union_diff(union_decl_sptr first_union,
6651 union_decl_sptr second_union,
6652 diff_context_sptr ctxt)
6653 : class_or_union_diff(first_union, second_union, ctxt)
6654{}
6655
6656/// Destructor of the union_diff node.
6658{}
6659
6660/// @return the first object of the comparison.
6661union_decl_sptr
6663{return is_union_type(first_subject());}
6664
6665/// @return the second object of the comparison.
6666union_decl_sptr
6668{return is_union_type(second_subject());}
6669
6670/// @return the pretty representation of the current diff node.
6671const string&
6673{
6674 if (diff::priv_->pretty_representation_.empty())
6675 {
6676 std::ostringstream o;
6677 o << "union_diff["
6678 << first_subject()->get_pretty_representation()
6679 << ", "
6680 << second_subject()->get_pretty_representation()
6681 << "]";
6682 diff::priv_->pretty_representation_ = o.str();
6683 }
6684 return diff::priv_->pretty_representation_;
6685}
6686
6687/// Report the changes carried by the current @ref union_diff node in
6688/// a textual format.
6689///
6690/// @param out the output stream to write the textual report to.
6691///
6692/// @param indent the number of white space to use as indentation.
6693void
6694union_diff::report(ostream& out, const string& indent) const
6695{
6696 context()->get_reporter()->report(*this, out, indent);
6697}
6698
6699/// Compute the difference between two @ref union_decl types.
6700///
6701/// Note that the two types must hav been created in the same
6702/// environment, otherwise, this function aborts.
6703///
6704/// @param first the first @ref union_decl to consider.
6705///
6706/// @param second the second @ref union_decl to consider.
6707///
6708/// @param ctxt the context of the diff to use.
6709union_diff_sptr
6710compute_diff(const union_decl_sptr first,
6711 const union_decl_sptr second,
6712 diff_context_sptr ctxt)
6713{
6714 union_diff_sptr changes(new union_diff(first, second, ctxt));
6715
6716 ctxt->initialize_canonical_diff(changes);
6717 ABG_ASSERT(changes->get_canonical_diff());
6718
6719 // Ok, so this is an optimization. Do not freak out if it looks
6720 // weird, because, well, it does look weird. This speeds up
6721 // greatly, for instance, the test case given at PR
6722 // libabigail/17948.
6723 //
6724 // We are setting the private data of the new instance of class_diff
6725 // (which is 'changes') to the private data of its canonical
6726 // instance. That is, we are sharing the private data of 'changes'
6727 // with the private data of its canonical instance to consume less
6728 // memory in cases where the equivalence class of 'changes' is huge.
6729 //
6730 // But if changes is its own canonical instance, then we initialize
6731 // its private data properly.
6732 if (is_union_diff(changes->get_canonical_diff()) == changes.get())
6733 // changes is its own canonical instance, so it gets a brand new
6734 // private data.
6735 changes->allocate_priv_data();
6736 else
6737 {
6738 // changes has a non-empty equivalence class so it's going to
6739 // share its private data with its canonical instance. Next
6740 // time class_diff::get_priv() is invoked, it's going to return
6741 // the shared private data of the canonical instance.
6742 return changes;
6743 }
6744
6745 // Compare data member
6746 compute_diff(first->get_non_static_data_members().begin(),
6747 first->get_non_static_data_members().end(),
6748 second->get_non_static_data_members().begin(),
6749 second->get_non_static_data_members().end(),
6750 changes->data_members_changes());
6751
6752#if 0
6753 // Compare member functions
6754 compute_diff(first->get_mem_fns().begin(),
6755 first->get_mem_fns().end(),
6756 second->get_mem_fns().begin(),
6757 second->get_mem_fns().end(),
6758 changes->member_fns_changes());
6759
6760 // Compare member function templates
6761 compute_diff(first->get_member_function_templates().begin(),
6762 first->get_member_function_templates().end(),
6763 second->get_member_function_templates().begin(),
6764 second->get_member_function_templates().end(),
6765 changes->member_fn_tmpls_changes());
6766#endif
6767
6768 changes->ensure_lookup_tables_populated();
6769
6770 return changes;
6771}
6772
6773// </union_diff stuff>
6774
6775//<scope_diff stuff>
6776
6777/// Clear the lookup tables that are useful for reporting.
6778///
6779/// This function must be updated each time a lookup table is added or
6780/// removed.
6781void
6782scope_diff::clear_lookup_tables()
6783{
6784 priv_->deleted_types_.clear();
6785 priv_->deleted_decls_.clear();
6786 priv_->inserted_types_.clear();
6787 priv_->inserted_decls_.clear();
6788 priv_->changed_types_.clear();
6789 priv_->changed_decls_.clear();
6790 priv_->removed_types_.clear();
6791 priv_->removed_decls_.clear();
6792 priv_->added_types_.clear();
6793 priv_->added_decls_.clear();
6794}
6795
6796/// Tests if the lookup tables are empty.
6797///
6798/// This function must be updated each time a lookup table is added or
6799/// removed.
6800///
6801/// @return true iff all the lookup tables are empty.
6802bool
6803scope_diff::lookup_tables_empty() const
6804{
6805 return (priv_->deleted_types_.empty()
6806 && priv_->deleted_decls_.empty()
6807 && priv_->inserted_types_.empty()
6808 && priv_->inserted_decls_.empty()
6809 && priv_->changed_types_.empty()
6810 && priv_->changed_decls_.empty()
6811 && priv_->removed_types_.empty()
6812 && priv_->removed_decls_.empty()
6813 && priv_->added_types_.empty()
6814 && priv_->added_decls_.empty());
6815}
6816
6817/// If the lookup tables are not yet built, walk the member_changes_
6818/// member and fill the lookup tables.
6819void
6820scope_diff::ensure_lookup_tables_populated()
6821{
6822 if (!lookup_tables_empty())
6823 return;
6824
6825 edit_script& e = priv_->member_changes_;
6826
6827 // Populate deleted types & decls lookup tables.
6828 for (const auto& deletion : e.deletions())
6829 {
6830 unsigned i = deletion.index();
6831 decl_base_sptr decl = deleted_member_at(i);
6832 string qname = decl->get_qualified_name();
6833 if (is_type(decl))
6834 {
6835 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6836 if (klass_decl && klass_decl->get_is_declaration_only())
6837 continue;
6838
6839 // Unique types are artifically put in a scope because they
6840 // have to belong somewhere, but they should not be
6841 // considered added/removed from any scope because they are
6842 // artificial and always present in the system.
6843 if (is_unique_type(is_type(decl)))
6844 continue;
6845
6846 ABG_ASSERT(priv_->deleted_types_.find(qname)
6847 == priv_->deleted_types_.end());
6848 priv_->deleted_types_[qname] = decl;
6849 }
6850 else
6851 {
6852 ABG_ASSERT(priv_->deleted_decls_.find(qname)
6853 == priv_->deleted_decls_.end());
6854 priv_->deleted_decls_[qname] = decl;
6855 }
6856 }
6857
6858 // Populate inserted types & decls as well as chagned types & decls
6859 // lookup tables.
6860 for (vector<insertion>::const_iterator it = e.insertions().begin();
6861 it != e.insertions().end();
6862 ++it)
6863 {
6864 for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6865 i != it->inserted_indexes().end();
6866 ++i)
6867 {
6868 decl_base_sptr decl = inserted_member_at(i);
6869 string qname = decl->get_qualified_name();
6870 if (is_type(decl))
6871 {
6872 class_decl_sptr klass_decl =
6873 dynamic_pointer_cast<class_decl>(decl);
6874 if (klass_decl && klass_decl->get_is_declaration_only())
6875 continue;
6876
6877 // Unique types are artifically put in a scope because they
6878 // have to belong somewhere, but they should not be
6879 // considered added/removed from any scope because they are
6880 // artificial and always present in the system.
6881 if (is_unique_type(is_type(decl)))
6882 continue;
6883
6884 ABG_ASSERT(priv_->inserted_types_.find(qname)
6885 == priv_->inserted_types_.end());
6886 string_decl_base_sptr_map::const_iterator j =
6887 priv_->deleted_types_.find(qname);
6888 if (j != priv_->deleted_types_.end())
6889 {
6890 if (*j->second != *decl)
6891 priv_->changed_types_[qname] =
6892 compute_diff(j->second, decl, context());
6893 priv_->deleted_types_.erase(j);
6894 }
6895 else
6896 priv_->inserted_types_[qname] = decl;
6897 }
6898 else
6899 {
6900 ABG_ASSERT(priv_->inserted_decls_.find(qname)
6901 == priv_->inserted_decls_.end());
6902 string_decl_base_sptr_map::const_iterator j =
6903 priv_->deleted_decls_.find(qname);
6904 if (j != priv_->deleted_decls_.end())
6905 {
6906 if (*j->second != *decl)
6907 priv_->changed_decls_[qname] =
6908 compute_diff(j->second, decl, context());
6909 priv_->deleted_decls_.erase(j);
6910 }
6911 else
6912 priv_->inserted_decls_[qname] = decl;
6913 }
6914 }
6915 }
6916
6917 sort_string_diff_sptr_map(priv_->changed_decls_,
6918 priv_->sorted_changed_decls_);
6919 sort_string_diff_sptr_map(priv_->changed_types_,
6920 priv_->sorted_changed_types_);
6921
6922 // Populate removed types/decls lookup tables
6923 for (string_decl_base_sptr_map::const_iterator i =
6924 priv_->deleted_types_.begin();
6925 i != priv_->deleted_types_.end();
6926 ++i)
6927 {
6928 string_decl_base_sptr_map::const_iterator r =
6929 priv_->inserted_types_.find(i->first);
6930 if (r == priv_->inserted_types_.end())
6931 priv_->removed_types_[i->first] = i->second;
6932 }
6933 for (string_decl_base_sptr_map::const_iterator i =
6934 priv_->deleted_decls_.begin();
6935 i != priv_->deleted_decls_.end();
6936 ++i)
6937 {
6938 string_decl_base_sptr_map::const_iterator r =
6939 priv_->inserted_decls_.find(i->first);
6940 if (r == priv_->inserted_decls_.end())
6941 priv_->removed_decls_[i->first] = i->second;
6942 }
6943
6944 // Populate added types/decls.
6945 for (string_decl_base_sptr_map::const_iterator i =
6946 priv_->inserted_types_.begin();
6947 i != priv_->inserted_types_.end();
6948 ++i)
6949 {
6950 string_decl_base_sptr_map::const_iterator r =
6951 priv_->deleted_types_.find(i->first);
6952 if (r == priv_->deleted_types_.end())
6953 priv_->added_types_[i->first] = i->second;
6954 }
6955 for (string_decl_base_sptr_map::const_iterator i =
6956 priv_->inserted_decls_.begin();
6957 i != priv_->inserted_decls_.end();
6958 ++i)
6959 {
6960 string_decl_base_sptr_map::const_iterator r =
6961 priv_->deleted_decls_.find(i->first);
6962 if (r == priv_->deleted_decls_.end())
6963 priv_->added_decls_[i->first] = i->second;
6964 }
6965}
6966
6967/// Populate the vector of children node of the @ref diff base type
6968/// sub-object of this instance of @ref scope_diff.
6969///
6970/// The children node can then later be retrieved using
6971/// diff::children_node().
6972void
6974{
6975 for (diff_sptrs_type::const_iterator i = changed_types().begin();
6976 i != changed_types().end();
6977 ++i)
6978 if (*i)
6980
6981 for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6982 i != changed_decls().end();
6983 ++i)
6984 if (*i)
6986}
6987
6988/// Constructor for scope_diff
6989///
6990/// @param first_scope the first scope to consider for the diff.
6991///
6992/// @param second_scope the second scope to consider for the diff.
6993///
6994/// @param ctxt the diff context to use. Note that this context
6995/// object must stay alive at least during the life time of the
6996/// current instance of @ref scope_diff. Otherwise memory corruption
6997/// issues occur.
6999 scope_decl_sptr second_scope,
7000 diff_context_sptr ctxt)
7001 : diff(first_scope, second_scope, ctxt),
7002 priv_(new priv)
7003{}
7004
7005/// Getter for the first scope of the diff.
7006///
7007/// @return the first scope of the diff.
7008const scope_decl_sptr
7010{return dynamic_pointer_cast<scope_decl>(first_subject());}
7011
7012/// Getter for the second scope of the diff.
7013///
7014/// @return the second scope of the diff.
7015const scope_decl_sptr
7017{return dynamic_pointer_cast<scope_decl>(second_subject());}
7018
7019/// Accessor of the edit script of the members of a scope.
7020///
7021/// This edit script is computed using the equality operator that
7022/// applies to shared_ptr<decl_base>.
7023///
7024/// That has interesting consequences. For instance, consider two
7025/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7026/// S0'. C0 and C0' have the same qualified name, but have different
7027/// members. The edit script will consider that C0 has been deleted
7028/// from S0 and that S0' has been inserted. This is a low level
7029/// canonical representation of the changes; a higher level
7030/// representation would give us a simpler way to say "the class C0
7031/// has been modified into C0'". But worry not. We do have such
7032/// higher representation as well; that is what changed_types() and
7033/// changed_decls() is for.
7034///
7035/// @return the edit script of the changes encapsulatd in this
7036/// instance of scope_diff.
7037const edit_script&
7039{return priv_->member_changes_;}
7040
7041/// Accessor of the edit script of the members of a scope.
7042///
7043/// This edit script is computed using the equality operator that
7044/// applies to shared_ptr<decl_base>.
7045///
7046/// That has interesting consequences. For instance, consider two
7047/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7048/// S0'. C0 and C0' have the same qualified name, but have different
7049/// members. The edit script will consider that C0 has been deleted
7050/// from S0 and that S0' has been inserted. This is a low level
7051/// canonical representation of the changes; a higher level
7052/// representation would give us a simpler way to say "the class C0
7053/// has been modified into C0'". But worry not. We do have such
7054/// higher representation as well; that is what changed_types() and
7055/// changed_decls() is for.
7056///
7057/// @return the edit script of the changes encapsulatd in this
7058/// instance of scope_diff.
7061{return priv_->member_changes_;}
7062
7063/// Accessor that eases the manipulation of the edit script associated
7064/// to this instance. It returns the scope member that is reported
7065/// (in the edit script) as deleted at a given index.
7066///
7067/// @param i the index (in the edit script) of an element of the first
7068/// scope that has been reported as being delete.
7069///
7070/// @return the scope member that has been reported by the edit script
7071/// as being deleted at index i.
7072const decl_base_sptr
7074{
7075 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
7076 return scope->get_member_decls()[i];
7077}
7078
7079/// Accessor that eases the manipulation of the edit script associated
7080/// to this instance. It returns the scope member (of the first scope
7081/// of this diff instance) that is reported (in the edit script) as
7082/// deleted at a given iterator.
7083///
7084/// @param i the iterator of an element of the first scope that has
7085/// been reported as being delete.
7086///
7087/// @return the scope member of the first scope of this diff that has
7088/// been reported by the edit script as being deleted at iterator i.
7089const decl_base_sptr
7090scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
7091{return deleted_member_at(i->index());}
7092
7093/// Accessor that eases the manipulation of the edit script associated
7094/// to this instance. It returns the scope member (of the second
7095/// scope of this diff instance) that is reported as being inserted
7096/// from a given index.
7097///
7098/// @param i the index of an element of the second scope this diff
7099/// that has been reported by the edit script as being inserted.
7100///
7101/// @return the scope member of the second scope of this diff that has
7102/// been reported as being inserted from index i.
7103const decl_base_sptr
7105{
7106 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
7107 return scope->get_member_decls()[i];
7108}
7109
7110/// Accessor that eases the manipulation of the edit script associated
7111/// to this instance. It returns the scope member (of the second
7112/// scope of this diff instance) that is reported as being inserted
7113/// from a given iterator.
7114///
7115/// @param i the iterator of an element of the second scope this diff
7116/// that has been reported by the edit script as being inserted.
7117///
7118/// @return the scope member of the second scope of this diff that has
7119/// been reported as being inserted from iterator i.
7120const decl_base_sptr
7121scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
7122{return inserted_member_at(*i);}
7123
7124/// @return a sorted vector of the types which content has changed
7125/// from the first scope to the other.
7126const diff_sptrs_type&
7128{return priv_->sorted_changed_types_;}
7129
7130/// @return a sorted vector of the decls which content has changed
7131/// from the first scope to the other.
7132const diff_sptrs_type&
7134{return priv_->sorted_changed_decls_;}
7135
7137scope_diff::removed_types() const
7138{return priv_->removed_types_;}
7139
7141scope_diff::removed_decls() const
7142{return priv_->removed_decls_;}
7143
7145scope_diff::added_types() const
7146{return priv_->added_types_;}
7147
7149scope_diff::added_decls() const
7150{return priv_->added_decls_;}
7151
7152/// @return the pretty representation for the current instance of @ref
7153/// scope_diff.
7154const string&
7156{
7157 if (diff::priv_->pretty_representation_.empty())
7158 {
7159 std::ostringstream o;
7160 o << "scope_diff["
7161 << first_subject()->get_pretty_representation()
7162 << ", "
7163 << second_subject()->get_pretty_representation()
7164 << "]";
7165 diff::priv_->pretty_representation_ = o.str();
7166 }
7167 return diff::priv_->pretty_representation_;
7168}
7169
7170/// Return true iff the current diff node carries a change.
7171///
7172/// Return true iff the current diff node carries a change.
7173bool
7175{
7176 // TODO: add the number of really removed/added stuff.
7177 return changed_types().size() + changed_decls().size();
7178}
7179
7180/// @return the kind of local change carried by the current diff node.
7181/// The value returned is zero if the current node carries no local
7182/// change.
7183enum change_kind
7185{
7186 ir::change_kind k = ir::NO_CHANGE_KIND;
7187 if (!equals(*first_scope(), *second_scope(), &k))
7188 return k & ir::ALL_LOCAL_CHANGES_MASK;
7189 return ir::NO_CHANGE_KIND;
7190}
7191
7192/// Report the changes of one scope against another.
7193///
7194/// @param out the out stream to report the changes to.
7195///
7196/// @param indent the string to use for indentation.
7197void
7198scope_diff::report(ostream& out, const string& indent) const
7199{
7200 context()->get_reporter()->report(*this, out, indent);
7201}
7202
7203/// Compute the diff between two scopes.
7204///
7205/// Note that the two decls must have been created in the same @ref
7206/// environment, otherwise, this function aborts.
7207///
7208/// @param first the first scope to consider in computing the diff.
7209///
7210/// @param second the second scope to consider in the diff
7211/// computation. The second scope is diffed against the first scope.
7212///
7213/// @param d a pointer to the diff object to populate with the
7214/// computed diff.
7215///
7216/// @return return the populated \a d parameter passed to this
7217/// function.
7218///
7219/// @param ctxt the diff context to use.
7222 const scope_decl_sptr second,
7224 diff_context_sptr ctxt)
7225{
7226 ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
7227
7228 compute_diff(first->get_member_decls().begin(),
7229 first->get_member_decls().end(),
7230 second->get_member_decls().begin(),
7231 second->get_member_decls().end(),
7232 d->member_changes());
7233
7234 d->ensure_lookup_tables_populated();
7235 d->context(ctxt);
7236
7237 return d;
7238}
7239
7240/// Compute the diff between two scopes.
7241///
7242/// Note that the two decls must have been created in the same @ref
7243/// environment, otherwise, this function aborts.
7244///
7245/// @param first_scope the first scope to consider in computing the diff.
7246///
7247/// @param second_scope the second scope to consider in the diff
7248/// computation. The second scope is diffed against the first scope.
7249///
7250/// @param ctxt the diff context to use.
7251///
7252/// @return return the resulting diff
7255 const scope_decl_sptr second_scope,
7256 diff_context_sptr ctxt)
7257{
7258 scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
7259 d = compute_diff(first_scope, second_scope, d, ctxt);
7260 ctxt->initialize_canonical_diff(d);
7261 return d;
7262}
7263
7264//</scope_diff stuff>
7265
7266// <fn_parm_diff stuff>
7267
7268/// Constructor for the fn_parm_diff type.
7269///
7270/// @param first the first subject of the diff.
7271///
7272/// @param second the second subject of the diff.
7273///
7274/// @param ctxt the context of the diff. Note that this context
7275/// object must stay alive at least during the life time of the
7276/// current instance of @ref fn_parm_diff. Otherwise memory
7277/// corruption issues occur.
7278fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
7279 const function_decl::parameter_sptr second,
7280 diff_context_sptr ctxt)
7281 : decl_diff_base(first, second, ctxt),
7282 priv_(new priv)
7283{
7284 ABG_ASSERT(first->get_index() == second->get_index());
7285 priv_->type_diff = compute_diff(first->get_type(),
7286 second->get_type(),
7287 ctxt);
7288 ABG_ASSERT(priv_->type_diff);
7289}
7290
7291/// Getter for the first subject of this diff node.
7292///
7293/// @return the first function_decl::parameter_sptr subject of this
7294/// diff node.
7297{return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
7298
7299/// Getter for the second subject of this diff node.
7300///
7301/// @return the second function_decl::parameter_sptr subject of this
7302/// diff node.
7305{return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7306
7307/// Getter for the diff representing the changes on the type of the
7308/// function parameter involved in the current instance of @ref
7309/// fn_parm_diff.
7310///
7311/// @return a diff_sptr representing the changes on the type of the
7312/// function parameter we are interested in.
7315{return priv_->type_diff;}
7316
7317/// Build and return a textual representation of the current instance
7318/// of @ref fn_parm_diff.
7319///
7320/// @return the string representing the current instance of
7321/// fn_parm_diff.
7322const string&
7324{
7325 if (diff::priv_->pretty_representation_.empty())
7326 {
7327 std::ostringstream o;
7328 o << "function_parameter_diff["
7329 << first_subject()->get_pretty_representation()
7330 << ", "
7331 << second_subject()->get_pretty_representation()
7332 << "]";
7333 diff::priv_->pretty_representation_ = o.str();
7334 }
7335 return diff::priv_->pretty_representation_;
7336}
7337
7338/// Return true iff the current diff node carries a change.
7339///
7340/// @return true iff the current diff node carries a change.
7341bool
7343{return *first_parameter() != *second_parameter();}
7344
7345/// Check if the current diff node carries a local change.
7346///
7347/// @return the kind of local change carried by the current diff node.
7348/// The value returned is zero if the current node carries no local
7349/// change.
7350enum change_kind
7352{
7353 ir::change_kind k = ir::NO_CHANGE_KIND;
7354 if (!equals(*first_parameter(), *second_parameter(), &k))
7355 return k & ir::ALL_LOCAL_CHANGES_MASK;
7356 return ir::NO_CHANGE_KIND;
7357}
7358
7359/// Emit a textual report about the current fn_parm_diff instance.
7360///
7361/// @param out the output stream to emit the textual report to.
7362///
7363/// @param indent the indentation string to use in the report.
7364void
7365fn_parm_diff::report(ostream& out, const string& indent) const
7366{
7367 context()->get_reporter()->report(*this, out, indent);
7368}
7369
7370/// Populate the vector of children nodes of the @ref diff base type
7371/// sub-object of this instance of @ref fn_parm_diff.
7372///
7373/// The children nodes can then later be retrieved using
7374/// diff::children_nodes()
7375void
7377{
7378 if (type_diff())
7380}
7381
7382/// Compute the difference between two function_decl::parameter_sptr;
7383/// that is, between two function parameters. Return a resulting
7384/// fn_parm_diff_sptr that represents the changes.
7385///
7386/// Note that the two decls must have been created in the same @ref
7387/// environment, otherwise, this function aborts.
7388///
7389/// @param first the first subject of the diff.
7390///
7391/// @param second the second subject of the diff.
7392///
7393/// @param ctxt the context of the diff.
7394///
7395/// @return fn_parm_diff_sptr the resulting diff node.
7398 const function_decl::parameter_sptr second,
7399 diff_context_sptr ctxt)
7400{
7401 if (!first || !second)
7402 return fn_parm_diff_sptr();
7403
7404 fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7405 ctxt->initialize_canonical_diff(result);
7406
7407 return result;
7408}
7409// </fn_parm_diff stuff>
7410
7411// <function_type_diff stuff>
7412
7413void
7414function_type_diff::ensure_lookup_tables_populated()
7415{
7416 priv_->return_type_diff_ =
7417 compute_diff(first_function_type()->get_return_type(),
7418 second_function_type()->get_return_type(),
7419 context());
7420
7421 string parm_name;
7423 for (vector<deletion>::const_iterator i =
7424 priv_->parm_changes_.deletions().begin();
7425 i != priv_->parm_changes_.deletions().end();
7426 ++i)
7427 {
7428 parm = *(first_function_type()->get_first_parm()
7429 + i->index());
7430 parm_name = parm->get_name_id();
7431 // If for a reason the type name is empty we want to know and
7432 // fix that.
7433 ABG_ASSERT(!parm_name.empty());
7434 priv_->deleted_parms_[parm_name] = parm;
7435 priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7436 }
7437
7438 for (vector<insertion>::const_iterator i =
7439 priv_->parm_changes_.insertions().begin();
7440 i != priv_->parm_changes_.insertions().end();
7441 ++i)
7442 {
7443 for (vector<unsigned>::const_iterator j =
7444 i->inserted_indexes().begin();
7445 j != i->inserted_indexes().end();
7446 ++j)
7447 {
7448 parm = *(second_function_type()->get_first_parm() + *j);
7449 parm_name = parm->get_name_id();
7450 // If for a reason the type name is empty we want to know and
7451 // fix that.
7452 ABG_ASSERT(!parm_name.empty());
7453 {
7454 string_parm_map::const_iterator k =
7455 priv_->deleted_parms_.find(parm_name);
7456 if (k != priv_->deleted_parms_.end())
7457 {
7458 if (*k->second != *parm)
7459 priv_->subtype_changed_parms_[parm_name] =
7460 compute_diff(k->second, parm, context());
7461 priv_->deleted_parms_.erase(parm_name);
7462 }
7463 else
7464 priv_->added_parms_[parm_name] = parm;
7465 }
7466 {
7467 unsigned_parm_map::const_iterator k =
7468 priv_->deleted_parms_by_id_.find(parm->get_index());
7469 if (k != priv_->deleted_parms_by_id_.end())
7470 {
7471 if (*k->second != *parm
7472 && (k->second->get_name_id() != parm_name))
7473 priv_->changed_parms_by_id_[parm->get_index()] =
7474 compute_diff(k->second, parm, context());
7475 priv_->added_parms_.erase(parm_name);
7476 priv_->deleted_parms_.erase(k->second->get_name_id());
7477 priv_->deleted_parms_by_id_.erase(parm->get_index());
7478 }
7479 else
7480 priv_->added_parms_by_id_[parm->get_index()] = parm;
7481 }
7482 }
7483 }
7484
7485 sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7486 priv_->sorted_subtype_changed_parms_);
7487 sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7488 priv_->sorted_changed_parms_by_id_);
7489 sort_string_parm_map(priv_->deleted_parms_,
7490 priv_->sorted_deleted_parms_);
7491
7492 sort_string_parm_map(priv_->added_parms_,
7493 priv_->sorted_added_parms_);
7494}
7495
7496/// In the vector of deleted parameters, get the one that is at a given
7497/// index.
7498///
7499/// @param i the index of the deleted parameter to get.
7500///
7501/// @return the parameter returned.
7503function_type_diff::deleted_parameter_at(int i) const
7504{return first_function_type()->get_parameters()[i];}
7505
7506/// Getter for the sorted vector of deleted parameters.
7507///
7508/// @return the sorted vector of deleted parameters.
7509const vector<function_decl::parameter_sptr>&
7511{return priv_->sorted_deleted_parms_;}
7512
7513/// Getter for the sorted vector of added parameters .
7514///
7515/// @return the sorted vector of added parameters.
7516const vector<function_decl::parameter_sptr>&
7518{return priv_->sorted_added_parms_;}
7519
7520/// In the vector of inserted parameters, get the one that is at a
7521/// given index.
7522///
7523/// @param i the index of the inserted parameter to get.
7524///
7525/// @return the parameter returned.
7527function_type_diff::inserted_parameter_at(int i) const
7528{return second_function_type()->get_parameters()[i];}
7529
7530/// Consutrctor of the @ref function_type type.
7531///
7532/// @param first the first @ref function_type subject of the diff to
7533/// create.
7534///
7535/// @param second the second @ref function_type subject of the diff to
7536/// create.
7537///
7538/// @param ctxt the diff context to be used by the newly created
7539/// instance of function_type_diff. Note that this context object
7540/// must stay alive at least during the life time of the current
7541/// instance of @ref function_type_diff. Otherwise memory corruption
7542/// issues occur.
7544 const function_type_sptr second,
7545 diff_context_sptr ctxt)
7546 : type_diff_base(first, second, ctxt),
7547 priv_(new priv)
7548{}
7549
7550/// Getter for the first subject of the diff.
7551///
7552/// @return the first function type involved in the diff.
7555{return dynamic_pointer_cast<function_type>(first_subject());}
7556
7557/// Getter for the second subject of the diff.
7558///
7559/// @return the second function type involved in the diff.
7562{return dynamic_pointer_cast<function_type>(second_subject());}
7563
7564/// Getter for the diff of the return types of the two function types
7565/// of the current diff.
7566///
7567/// @return the diff of the return types of the two function types of
7568/// the current diff.
7569const diff_sptr
7571{return priv_->return_type_diff_;}
7572
7573/// Getter for the map of function parameter changes of the current diff.
7574///
7575/// @return a map of function parameter changes of the current diff.
7578{return priv_->subtype_changed_parms_;}
7579
7580/// Getter for the map of parameters that got removed.
7581///
7582/// @return the map of parameters that got removed.
7583const string_parm_map&
7585{return priv_->deleted_parms_;}
7586
7587/// Getter for the map of parameters that got added.
7588///
7589/// @return the map of parameters that got added.
7590const string_parm_map&
7592{return priv_->added_parms_;}
7593
7594/// Build and return a copy of a pretty representation of the current
7595/// instance of @ref function_type_diff.
7596///
7597/// @return a copy of the pretty representation of the current
7598/// instance of @ref function_type_diff.
7599const string&
7601{
7602 if (diff::priv_->pretty_representation_.empty())
7603 {
7604 std::ostringstream o;
7605 o << "function_type_diff["
7607 << ", "
7609 << "]";
7610 diff::priv_->pretty_representation_ = o.str();
7611 }
7612 return diff::priv_->pretty_representation_;
7613}
7614
7615/// Test if the current diff node carries changes.
7616///
7617/// @return true iff the current diff node carries changes.
7618bool
7621
7622/// Test if the current diff node carries local changes.
7623///
7624/// A local change is a change that is carried by this diff node, not
7625/// by any of its children nodes.
7626///
7627/// @return the kind of local change carried by the current diff node.
7628/// The value returned is zero if the current node carries no local
7629/// change.
7630enum change_kind
7632{
7633 ir::change_kind k = ir::NO_CHANGE_KIND;
7635 return k & ir::ALL_LOCAL_CHANGES_MASK;
7636 return ir::NO_CHANGE_KIND;
7637}
7638
7639/// Build and emit a textual report about the current @ref
7640/// function_type_diff instance.
7641///
7642/// @param out the output stream.
7643///
7644/// @param indent the indentation string to use.
7645void
7646function_type_diff::report(ostream& out, const string& indent) const
7647{
7648 context()->get_reporter()->report(*this, out, indent);
7649}
7650
7651/// Populate the vector of children node of the @ref diff base type
7652/// sub-object of this instance of @ref function_type_diff.
7653///
7654/// The children node can then later be retrieved using
7655/// diff::children_node().
7656void
7658{
7659 if (diff_sptr d = return_type_diff())
7661
7662 for (vector<fn_parm_diff_sptr>::const_iterator i =
7663 priv_->sorted_subtype_changed_parms_.begin();
7664 i != priv_->sorted_subtype_changed_parms_.end();
7665 ++i)
7666 if (diff_sptr d = *i)
7668
7669 for (vector<fn_parm_diff_sptr>::const_iterator i =
7670 priv_->sorted_changed_parms_by_id_.begin();
7671 i != priv_->sorted_changed_parms_by_id_.end();
7672 ++i)
7673 if (diff_sptr d = *i)
7675}
7676
7677/// Compute the diff between two instances of @ref function_type.
7678///
7679/// Note that the two types must have been created in the same @ref
7680/// environment, otherwise, this function aborts.
7681///
7682/// @param first the first @ref function_type to consider for the diff.
7683///
7684/// @param second the second @ref function_type to consider for the diff.
7685///
7686/// @param ctxt the diff context to use.
7687///
7688/// @return the resulting diff between the two @ref function_type.
7691 const function_type_sptr second,
7692 diff_context_sptr ctxt)
7693{
7694 if (!first || !second)
7695 {
7696 // TODO: implement this for either first or second being NULL.
7697 return function_type_diff_sptr();
7698 }
7699
7700 function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7701
7702 diff_utils::compute_diff(first->get_first_parm(),
7703 first->get_parameters().end(),
7704 second->get_first_parm(),
7705 second->get_parameters().end(),
7706 result->priv_->parm_changes_);
7707
7708 result->ensure_lookup_tables_populated();
7709
7710 ctxt->initialize_canonical_diff(result);
7711
7712 return result;
7713}
7714// </function_type_diff stuff>
7715
7716// <function_decl_diff stuff>
7717
7718/// Build the lookup tables of the diff, if necessary.
7719void
7720function_decl_diff::ensure_lookup_tables_populated()
7721{
7722}
7723
7724/// Populate the vector of children node of the @ref diff base type
7725/// sub-object of this instance of @ref function_decl_diff.
7726///
7727/// The children node can then later be retrieved using
7728/// diff::children_node().
7729void
7731{
7732 if (diff_sptr d = type_diff())
7734}
7735
7736/// Constructor for function_decl_diff
7737///
7738/// @param first the first function considered by the diff.
7739///
7740/// @param second the second function considered by the diff.
7741///
7742/// @param ctxt the context of the diff. Note that this context
7743/// object must stay alive at least during the life time of the
7744/// current instance of @ref function_decl_diff. Otherwise memory
7745/// corruption issues occur.
7747 const function_decl_sptr second,
7748 diff_context_sptr ctxt)
7749 : decl_diff_base(first, second, ctxt),
7750 priv_(new priv)
7751{
7752}
7753
7754/// @return the first function considered by the diff.
7757{return dynamic_pointer_cast<function_decl>(first_subject());}
7758
7759/// @return the second function considered by the diff.
7762{return dynamic_pointer_cast<function_decl>(second_subject());}
7763
7765function_decl_diff::type_diff() const
7766{return priv_->type_diff_;}
7767
7768/// @return the pretty representation for the current instance of @ref
7769/// function_decl_diff.
7770const string&
7772{
7773 if (diff::priv_->pretty_representation_.empty())
7774 {
7775 std::ostringstream o;
7776 o << "function_diff["
7777 << first_subject()->get_pretty_representation()
7778 << ", "
7779 << second_subject()->get_pretty_representation()
7780 << "]";
7781 diff::priv_->pretty_representation_ = o.str();
7782 }
7783 return diff::priv_->pretty_representation_;
7784}
7785
7786/// Return true iff the current diff node carries a change.
7787///
7788/// @return true iff the current diff node carries a change.
7789bool
7792
7793/// @return the kind of local change carried by the current diff node.
7794/// The value returned is zero if the current node carries no local
7795/// change.
7796enum change_kind
7798{
7799 ir::change_kind k = ir::NO_CHANGE_KIND;
7801 return k & ir::ALL_LOCAL_CHANGES_MASK;
7802 return ir::NO_CHANGE_KIND;
7803}
7804
7805/// Serialize a report of the changes encapsulated in the current
7806/// instance of @ref function_decl_diff over to an output stream.
7807///
7808/// @param out the output stream to serialize the report to.
7809///
7810/// @param indent the string to use an an indentation prefix.
7811void
7812function_decl_diff::report(ostream& out, const string& indent) const
7813{
7814 context()->get_reporter()->report(*this, out, indent);
7815}
7816
7817/// Compute the diff between two function_decl.
7818///
7819/// Note that the two decls must have been created in the same @ref
7820/// environment, otherwise, this function aborts.
7821///
7822/// @param first the first function_decl to consider for the diff
7823///
7824/// @param second the second function_decl to consider for the diff
7825///
7826/// @param ctxt the diff context to use.
7827///
7828/// @return the computed diff
7831 const function_decl_sptr second,
7832 diff_context_sptr ctxt)
7833{
7834 if (!first || !second)
7835 {
7836 // TODO: implement this for either first or second being NULL.
7837 return function_decl_diff_sptr();
7838 }
7839
7840 function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7841 second->get_type(),
7842 ctxt);
7843
7844 function_decl_diff_sptr result(new function_decl_diff(first, second,
7845 ctxt));
7846 result->priv_->type_diff_ = type_diff;
7847
7848 result->ensure_lookup_tables_populated();
7849
7850 ctxt->initialize_canonical_diff(result);
7851
7852 return result;
7853}
7854
7855// </function_decl_diff stuff>
7856
7857// <type_decl_diff stuff>
7858
7859/// Constructor for type_decl_diff.
7860///
7861/// @param first the first subject of the diff.
7862///
7863/// @param second the second subject of the diff.
7864///
7865/// @param ctxt the context of the diff. Note that this context
7866/// object must stay alive at least during the life time of the
7867/// current instance of @ref type_decl_diff. Otherwise memory
7868/// corruption issues occur.
7869type_decl_diff::type_decl_diff(const type_decl_sptr first,
7870 const type_decl_sptr second,
7871 diff_context_sptr ctxt)
7872 : type_diff_base(first, second, ctxt)
7873{}
7874
7875/// Getter for the first subject of the type_decl_diff.
7876///
7877/// @return the first type_decl involved in the diff.
7878const type_decl_sptr
7880{return dynamic_pointer_cast<type_decl>(first_subject());}
7881
7882/// Getter for the second subject of the type_decl_diff.
7883///
7884/// @return the second type_decl involved in the diff.
7885const type_decl_sptr
7887{return dynamic_pointer_cast<type_decl>(second_subject());}
7888
7889/// @return the pretty representation for the current instance of @ref
7890/// type_decl_diff.
7891const string&
7893{
7894 if (diff::priv_->pretty_representation_.empty())
7895 {
7896 std::ostringstream o;
7897 o << "type_decl_diff["
7898 << first_subject()->get_pretty_representation()
7899 << ", "
7900 << second_subject()->get_pretty_representation()
7901 << "]";
7902 diff::priv_->pretty_representation_ = o.str();
7903 }
7904 return diff::priv_->pretty_representation_;
7905}
7906/// Return true iff the current diff node carries a change.
7907///
7908/// @return true iff the current diff node carries a change.
7909bool
7911{return first_type_decl() != second_type_decl();}
7912
7913/// @return the kind of local change carried by the current diff node.
7914/// The value returned is zero if the current node carries no local
7915/// change.
7916enum change_kind
7918{
7919 ir::change_kind k = ir::NO_CHANGE_KIND;
7920 if (!equals(*first_type_decl(), *second_type_decl(), &k))
7921 return k & ir::ALL_LOCAL_CHANGES_MASK;
7922 return ir::NO_CHANGE_KIND;
7923}
7924/// Ouputs a report of the differences between of the two type_decl
7925/// involved in the type_decl_diff.
7926///
7927/// @param out the output stream to emit the report to.
7928///
7929/// @param indent the string to use for indentatino indent.
7930void
7931type_decl_diff::report(ostream& out, const string& indent) const
7932{
7933 context()->get_reporter()->report(*this, out, indent);
7934}
7935
7936/// Compute a diff between two type_decl.
7937///
7938/// Note that the two types must have been created in the same @ref
7939/// environment, otherwise, this function aborts.
7940///
7941/// This function doesn't actually compute a diff. As a type_decl is
7942/// very simple (unlike compound constructs like function_decl or
7943/// class_decl) it's easy to just compare the components of the
7944/// type_decl to know what has changed. Thus this function just
7945/// builds and return a type_decl_diff object. The
7946/// type_decl_diff::report function will just compare the components
7947/// of the the two type_decl and display where and how they differ.
7948///
7949/// @param first a pointer to the first type_decl to
7950/// consider.
7951///
7952/// @param second a pointer to the second type_decl to consider.
7953///
7954/// @param ctxt the diff context to use.
7955///
7956/// @return a pointer to the resulting type_decl_diff.
7959 const type_decl_sptr second,
7960 diff_context_sptr ctxt)
7961{
7962 type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7963
7964 // We don't need to actually compute a diff here as a type_decl
7965 // doesn't have complicated sub-components. type_decl_diff::report
7966 // just walks the members of the type_decls and display information
7967 // about the ones that have changed. On a similar note,
7968 // type_decl_diff::length returns 0 if the two type_decls are equal,
7969 // and 1 otherwise.
7970
7971 ctxt->initialize_canonical_diff(result);
7972
7973 return result;
7974}
7975
7976// </type_decl_diff stuff>
7977
7978// <typedef_diff stuff>
7979
7980/// Populate the vector of children node of the @ref diff base type
7981/// sub-object of this instance of @ref typedef_diff.
7982///
7983/// The children node can then later be retrieved using
7984/// diff::children_node().
7985void
7988
7989/// Constructor for typedef_diff.
7990///
7991/// @param first the first subject of the diff.
7992///
7993/// @param second the second subject of the diff.
7994///
7995/// @param underlying the underlying diff of the @ref typedef_diff.
7996/// That is the diff between the underlying types of @p first and @p
7997/// second.
7998///
7999/// @param ctxt the context of the diff. Note that this context
8000/// object must stay alive at least during the life time of the
8001/// current instance of @ref typedef_diff. Otherwise memory
8002/// corruption issues occur.
8003typedef_diff::typedef_diff(const typedef_decl_sptr first,
8004 const typedef_decl_sptr second,
8005 const diff_sptr underlying,
8006 diff_context_sptr ctxt)
8007 : type_diff_base(first, second, ctxt),
8008 priv_(new priv(underlying))
8009{}
8010
8011/// Getter for the firt typedef_decl involved in the diff.
8012///
8013/// @return the first subject of the diff.
8016{return dynamic_pointer_cast<typedef_decl>(first_subject());}
8017
8018/// Getter for the second typedef_decl involved in the diff.
8019///
8020/// @return the second subject of the diff.
8023{return dynamic_pointer_cast<typedef_decl>(second_subject());}
8024
8025/// Getter for the diff between the two underlying types of the
8026/// typedefs.
8027///
8028/// @return the diff object reprensenting the difference between the
8029/// two underlying types of the typedefs.
8030const diff_sptr
8032{return priv_->underlying_type_diff_;}
8033
8034/// Setter for the diff between the two underlying types of the
8035/// typedefs.
8036///
8037/// @param d the new diff object reprensenting the difference between
8038/// the two underlying types of the typedefs.
8039void
8041{priv_->underlying_type_diff_ = d;}
8042
8043/// @return the pretty representation for the current instance of @ref
8044/// typedef_diff.
8045const string&
8047{
8048 if (diff::priv_->pretty_representation_.empty())
8049 {
8050 std::ostringstream o;
8051 o << "typedef_diff["
8052 << first_subject()->get_pretty_representation()
8053 << ", "
8054 << second_subject()->get_pretty_representation()
8055 << "]";
8056 diff::priv_->pretty_representation_ = o.str();
8057 }
8058 return diff::priv_->pretty_representation_;
8059}
8060
8061/// Return true iff the current diff node carries a change.
8062///
8063/// @return true iff the current diff node carries a change.
8064bool
8066{
8067 decl_base_sptr second = second_typedef_decl();
8068 return !(*first_typedef_decl() == *second);
8069}
8070
8071/// @return the kind of local change carried by the current diff node.
8072/// The value returned is zero if the current node carries no local
8073/// change.
8074enum change_kind
8076{
8077 ir::change_kind k = ir::NO_CHANGE_KIND;
8079 return k & ir::ALL_LOCAL_CHANGES_MASK;
8080 return ir::NO_CHANGE_KIND;
8081}
8082
8083/// Reports the difference between the two subjects of the diff in a
8084/// serialized form.
8085///
8086/// @param out the output stream to emit the report to.
8087///
8088/// @param indent the indentation string to use.
8089void
8090typedef_diff::report(ostream& out, const string& indent) const
8091{
8092 context()->get_reporter()->report(*this, out, indent);
8093}
8094
8095/// Compute a diff between two typedef_decl.
8096///
8097/// Note that the two types must have been created in the same @ref
8098/// environment, otherwise, this function aborts.
8099///
8100/// @param first a pointer to the first typedef_decl to consider.
8101///
8102/// @param second a pointer to the second typedef_decl to consider.
8103///
8104/// @param ctxt the diff context to use.
8105///
8106/// @return a pointer to the the resulting typedef_diff.
8109 const typedef_decl_sptr second,
8110 diff_context_sptr ctxt)
8111{
8112 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
8113 second->get_underlying_type(),
8114 ctxt);
8115 typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
8116
8117 ctxt->initialize_canonical_diff(result);
8118
8119 return result;
8120}
8121
8122/// Return the leaf underlying diff node of a @ref typedef_diff node.
8123///
8124/// If the underlying diff node of a @ref typedef_diff node is itself
8125/// a @ref typedef_diff node, then recursively look at the underlying
8126/// diff nodes to get the first one that is not a a @ref typedef_diff
8127/// node. This is what a leaf underlying diff node means.
8128///
8129/// Otherwise, if the underlying diff node of @ref typedef_diff is
8130/// *NOT* a @ref typedef_diff node, then just return the underlying
8131/// diff node.
8132///
8133/// And if the diff node considered is not a @ref typedef_diff node,
8134/// then just return it.
8135///
8136/// @return the leaf underlying diff node of a @p diff.
8137const diff*
8139{
8140 const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
8141 if (!d)
8142 return diff;
8143
8144 if (const typedef_diff* deef =
8145 dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
8147
8148 return d->underlying_type_diff().get();
8149}
8150
8151// </typedef_diff stuff>
8152
8153// <translation_unit_diff stuff>
8154
8155/// Constructor for translation_unit_diff.
8156///
8157/// @param first the first translation unit to consider for this diff.
8158///
8159/// @param second the second translation unit to consider for this diff.
8160///
8161/// @param ctxt the context of the diff. Note that this context
8162/// object must stay alive at least during the life time of the
8163/// current instance of @ref translation_unit_diff. Otherwise memory
8164/// corruption issues occur.
8166 translation_unit_sptr second,
8167 diff_context_sptr ctxt)
8168 : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
8169 priv_(new priv(first, second))
8170{
8171}
8172
8173/// Getter for the first translation unit of this diff.
8174///
8175/// @return the first translation unit of this diff.
8178{return priv_->first_;}
8179
8180/// Getter for the second translation unit of this diff.
8181///
8182/// @return the second translation unit of this diff.
8185{return priv_->second_;}
8186
8187/// Return true iff the current diff node carries a change.
8188///
8189/// @return true iff the current diff node carries a change.
8190bool
8192{return scope_diff::has_changes();}
8193
8194/// @return the kind of local change carried by the current diff node.
8195/// The value returned is zero if the current node carries no local
8196/// change.
8197enum change_kind
8199{return ir::NO_CHANGE_KIND;}
8200
8201/// Report the diff in a serialized form.
8202///
8203/// @param out the output stream to serialize the report to.
8204///
8205/// @param indent the prefix to use as indentation for the report.
8206void
8207translation_unit_diff::report(ostream& out, const string& indent) const
8208{scope_diff::report(out, indent);}
8209
8210/// Compute the diff between two translation_units.
8211///
8212/// Note that the two translation units must have been created in the
8213/// same @ref environment, otherwise, this function aborts.
8214///
8215/// @param first the first translation_unit to consider.
8216///
8217/// @param second the second translation_unit to consider.
8218///
8219/// @param ctxt the diff context to use. If null, this function will
8220/// create a new context and set to the diff object returned.
8221///
8222/// @return the newly created diff object.
8225 const translation_unit_sptr second,
8226 diff_context_sptr ctxt)
8227{
8228 ABG_ASSERT(first && second);
8229
8230 if (!ctxt)
8231 ctxt.reset(new diff_context);
8232
8233 // TODO: handle first or second having empty contents.
8234 translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
8235 ctxt));
8236 scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
8237
8238 compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
8239 static_pointer_cast<scope_decl>(second->get_global_scope()),
8240 sc_diff,
8241 ctxt);
8242
8243 ctxt->initialize_canonical_diff(tu_diff);
8244
8245 return tu_diff;
8246}
8247
8248// </translation_unit_diff stuff>
8249
8250// <diff_maps stuff>
8251
8252/// The private data of the @ref diff_maps type.
8253struct diff_maps::priv
8254{
8255 string_diff_ptr_map type_decl_diff_map_;
8256 string_diff_ptr_map enum_diff_map_;
8257 string_diff_ptr_map class_diff_map_;
8258 string_diff_ptr_map union_diff_map_;
8259 string_diff_ptr_map typedef_diff_map_;
8260 string_diff_ptr_map subrange_diff_map_;
8261 string_diff_ptr_map array_diff_map_;
8262 string_diff_ptr_map reference_diff_map_;
8263 string_diff_ptr_map function_type_diff_map_;
8264 string_diff_ptr_map function_decl_diff_map_;
8265 string_diff_ptr_map var_decl_diff_map_;
8266 string_diff_ptr_map distinct_diff_map_;
8267 string_diff_ptr_map fn_parm_diff_map_;
8268 diff_artifact_set_map_type impacted_artifacts_map_;
8269}; // end struct diff_maps::priv
8270
8271/// Default constructor of the @ref diff_maps type.
8273 : priv_(new diff_maps::priv())
8274{}
8275
8276diff_maps::~diff_maps() = default;
8277
8278/// Getter of the map that contains basic type diffs.
8279///
8280/// @return the map that contains basic type diffs.
8283{return priv_->type_decl_diff_map_;}
8284
8285/// Getter of the map that contains basic type diffs.
8286///
8287/// @return the map that contains basic type diffs.
8290{return priv_->type_decl_diff_map_;}
8291
8292/// Getter of the map that contains enum type diffs.
8293///
8294/// @return the map that contains enum type diffs.
8297{return priv_->enum_diff_map_;}
8298
8299/// Getter of the map that contains enum type diffs.
8300///
8301/// @return the map that contains enum type diffs.
8304{return priv_->enum_diff_map_;}
8305
8306/// Getter of the map that contains class type diffs.
8307///
8308/// @return the map that contains class type diffs.
8311{return priv_->class_diff_map_;}
8312
8313/// Getter of the map that contains class type diffs.
8314///
8315/// @return the map that contains class type diffs.
8318{return priv_->class_diff_map_;}
8319
8320/// Getter of the map that contains union type diffs.
8321///
8322/// @return the map that contains union type diffs.
8325{return priv_->union_diff_map_;}
8326
8327/// Getter of the map that contains union type diffs.
8328///
8329/// @return the map that contains union type diffs.
8332{return priv_->union_diff_map_;}
8333
8334/// Getter of the map that contains typedef type diffs.
8335///
8336/// @return the map that contains typedef type diffs.
8339{return priv_->typedef_diff_map_;}
8340
8341/// Getter of the map that contains typedef type diffs.
8342///
8343/// @return the map that contains typedef type diffs.
8346{return priv_->typedef_diff_map_;}
8347
8348/// Getter of the map that contains subrange type diffs.
8349///
8350/// @return the map that contains subrange type diffs.
8353{return priv_->subrange_diff_map_;}
8354
8355/// Getter of the map that contains subrange type diffs.
8356///
8357/// @return the map that contains subrange type diffs.
8360{return priv_->subrange_diff_map_;}
8361
8362/// Getter of the map that contains array type diffs.
8363///
8364/// @return the map that contains array type diffs.
8367{return priv_->array_diff_map_;}
8368
8369/// Getter of the map that contains array type diffs.
8370///
8371/// @return the map that contains array type diffs.
8374{return priv_->array_diff_map_;}
8375
8376/// Getter of the map that contains reference type diffs.
8377///
8378/// @return the map that contains reference type diffs.
8381{return priv_->reference_diff_map_;}
8382
8383/// Getter of the map that contains reference type diffs.
8384///
8385/// @return the map that contains reference type diffs.
8388{{return priv_->reference_diff_map_;}}
8389
8390/// Getter of the map that contains function parameter diffs.
8391///
8392/// @return the map that contains function parameter diffs.
8395{return priv_->fn_parm_diff_map_;}
8396
8397/// Getter of the map that contains function parameter diffs.
8398///
8399/// @return the map that contains function parameter diffs.
8402{return priv_->fn_parm_diff_map_;}
8403
8404/// Getter of the map that contains function type diffs.
8405///
8406/// @return the map that contains function type diffs.
8409{return priv_->function_type_diff_map_;}
8410
8411/// Getter of the map that contains function type diffs.
8412///
8413/// @return the map that contains function type diffs.
8416{return priv_->function_type_diff_map_;}
8417
8418/// Getter of the map that contains function decl diffs.
8419///
8420/// @return the map that contains function decl diffs.
8423{return priv_->function_decl_diff_map_;}
8424
8425/// Getter of the map that contains function decl diffs.
8426///
8427/// @return the map that contains function decl diffs.
8430{return priv_->function_decl_diff_map_;}
8431
8432/// Getter of the map that contains var decl diffs.
8433///
8434/// @return the map that contains var decl diffs.
8437{return priv_->var_decl_diff_map_;}
8438
8439/// Getter of the map that contains var decl diffs.
8440///
8441/// @return the map that contains var decl diffs.
8444{return priv_->var_decl_diff_map_;}
8445
8446/// Getter of the map that contains distinct diffs.
8447///
8448/// @return the map that contains distinct diffs.
8451{return priv_->distinct_diff_map_;}
8452
8453/// Getter of the map that contains distinct diffs.
8454///
8455/// @return the map that contains distinct diffs.
8458{return priv_->distinct_diff_map_;}
8459
8460/// Insert a new diff node into the current instance of @ref diff_maps.
8461///
8462/// @param dif the new diff node to insert into the @ref diff_maps.
8463///
8464/// @param impacted_iface the interface (global function or variable)
8465/// currently being analysed that led to analysing the diff node @p
8466/// dif. In other words, this is the interface impacted by the diff
8467/// node @p dif. Note that this can be nil in cases where we are
8468/// directly analysing changes to a type that is not reachable from
8469/// any global function or variable.
8470///
8471/// @return true iff the diff node could be added to the current
8472/// instance of @ref diff_maps.
8473bool
8475 const type_or_decl_base_sptr& impacted_iface)
8476{
8477 string n = get_pretty_representation(dif->first_subject(),
8478 /*internal=*/true);
8479 if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8480 get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8481 else if (const enum_diff *d = is_enum_diff(dif))
8482 get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8483 else if (const class_diff *d = is_class_diff(dif))
8484 get_class_diff_map()[n] = const_cast<class_diff*>(d);
8485 else if (const union_diff *d = is_union_diff(dif))
8486 get_union_diff_map()[n] = const_cast<union_diff*>(d);
8487 else if (const typedef_diff *d = is_typedef_diff(dif))
8488 get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8489 else if (const subrange_diff *d = is_subrange_diff(dif))
8490 get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8491 else if (const array_diff *d = is_array_diff(dif))
8492 get_array_diff_map()[n] = const_cast<array_diff*>(d);
8493 else if (const reference_diff *d = is_reference_diff(dif))
8494 get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8495 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8496 get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8497 else if (const function_type_diff *d = is_function_type_diff(dif))
8498 get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8499 else if (const var_diff *d = is_var_diff(dif))
8500 get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8501 else if (const function_decl_diff *d = is_function_decl_diff(dif))
8502 get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8503 else if (const distinct_diff *d = is_distinct_diff(dif))
8504 get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8505 else if (is_base_diff(dif))
8506 // we silently drop this case.
8507 return true;
8508 else
8510
8511 // Update the map that associates this diff node to the set of
8512 // interfaces it impacts.
8513
8514 if (impacted_iface)
8515 {
8516 diff_artifact_set_map_type::iterator i =
8517 priv_->impacted_artifacts_map_.find(dif);
8518
8519 if (i == priv_->impacted_artifacts_map_.end())
8520 {
8522 set.insert(impacted_iface);
8523 priv_->impacted_artifacts_map_[dif] = set;
8524 }
8525 else
8526 i->second.insert(impacted_iface);
8527 }
8528
8529 return true;
8530}
8531
8532/// Lookup the interfaces that are impacted by a given leaf diff node.
8533///
8534/// @param d the diff node to consider.
8535///
8536/// @return the set of artifacts impacted by @p d.
8539{
8540 diff_artifact_set_map_type::iterator i =
8541 priv_->impacted_artifacts_map_.find(d);
8542
8543 if (i == priv_->impacted_artifacts_map_.end())
8544 return 0;
8545
8546 return &i->second;
8547}
8548
8549//
8550// </diff_maps stuff>
8551
8552/// Constructor for the @ref diff_stat type.
8553///
8554/// @param ctxt the context of the corpus diff. Note that this
8555/// context object must stay alive at least during the life time of
8556/// the current instance of @ref corpus_diff::diff_stats. Otherwise
8557/// memory corruption issues occur.
8558corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8559 : priv_(new priv(ctxt))
8560{}
8561
8562/// Getter for the number of functions removed.
8563///
8564/// @return the number of functions removed.
8565size_t
8567{return priv_->num_func_removed;}
8568
8569/// Setter for the number of functions removed.
8570///
8571/// @param n the new number of functions removed.
8572void
8574{priv_->num_func_removed = n;}
8575
8576/// Getter for the number of removed functions that have been filtered
8577/// out.
8578///
8579/// @return the number of removed functions that have been filtered
8580/// out.
8581size_t
8583{
8584 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8585 return num_func_removed();
8586 return priv_->num_removed_func_filtered_out;
8587}
8588
8589/// Setter for the number of removed functions that have been filtered
8590/// out.
8591///
8592/// @param t the new value.
8593void
8595{priv_->num_removed_func_filtered_out = t;}
8596
8597/// Getter for the net number of function removed.
8598///
8599/// This is the difference between the number of functions removed and
8600/// the number of functons removed that have been filtered out.
8601///
8602/// @return the net number of function removed.
8603size_t
8605{
8606 ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8607 return num_func_removed() - num_removed_func_filtered_out();
8608}
8609
8610/// Getter for the number of functions added.
8611///
8612/// @return the number of functions added.
8613size_t
8615{return priv_->num_func_added;}
8616
8617/// Setter for the number of functions added.
8618///
8619/// @param n the new number of functions added.
8620void
8622{priv_->num_func_added = n;}
8623
8624/// Getter for the number of added function that have been filtered out.
8625///
8626/// @return the number of added function that have been filtered out.
8627size_t
8629{
8630 if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8631 return num_func_added();
8632 return priv_->num_added_func_filtered_out;
8633}
8634
8635/// Setter for the number of added function that have been filtered
8636/// out.
8637///
8638/// @param n the new value.
8639void
8641{priv_->num_added_func_filtered_out = n;}
8642
8643/// Getter for the net number of added functions.
8644///
8645/// The net number of added functions is the difference between the
8646/// number of added functions and the number of added functions that
8647/// have been filtered out.
8648///
8649/// @return the net number of added functions.
8650size_t
8652{
8653 ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8654 return num_func_added() - num_added_func_filtered_out();
8655}
8656
8657/// Getter for the number of functions that have a change in one of
8658/// their sub-types.
8659///
8660/// @return the number of functions that have a change in one of their
8661/// sub-types.
8662size_t
8664{return priv_->num_func_changed;}
8665
8666/// Setter for the number of functions that have a change in one of
8667/// their sub-types.
8668///
8669/// @@param n the new number of functions that have a change in one of
8670/// their sub-types.
8671void
8673{priv_->num_func_changed = n;}
8674
8675/// Getter for the number of functions that have a change in one of
8676/// their sub-types, and that have been filtered out.
8677///
8678/// @return the number of functions that have a change in one of their
8679/// sub-types, and that have been filtered out.
8680size_t
8682{return priv_->num_changed_func_filtered_out;}
8683
8684/// Setter for the number of functions that have a change in one of
8685/// their sub-types, and that have been filtered out.
8686///
8687/// @param n the new number of functions that have a change in one of their
8688/// sub-types, and that have been filtered out.
8689void
8691{priv_->num_changed_func_filtered_out = n;}
8692
8693/// Getter for the number of functions that carry virtual member
8694/// offset changes.
8695///
8696/// @return the number of functions that carry virtual member changes.
8697size_t
8699{return priv_->num_func_with_virt_offset_changes;}
8700
8701/// Setter for the number of functions that carry virtual member
8702/// offset changes.
8703///
8704/// @param n the new number of functions that carry virtual member
8705/// offset. changes.
8706void
8708{priv_->num_func_with_virt_offset_changes = n;}
8709
8710/// Getter for the number of functions that have a change in their
8711/// sub-types, minus the number of these functions that got filtered
8712/// out from the diff.
8713///
8714/// @return for the the number of functions that have a change in
8715/// their sub-types, minus the number of these functions that got
8716/// filtered out from the diff.
8717size_t
8719{return num_func_changed() - num_changed_func_filtered_out();}
8720
8721/// Getter for the number of variables removed.
8722///
8723/// @return the number of variables removed.
8724size_t
8726{return priv_->num_vars_removed;}
8727
8728/// Setter for the number of variables removed.
8729///
8730/// @param n the new number of variables removed.
8731void
8733{priv_->num_vars_removed = n;}
8734
8735/// Getter for the number removed variables that have been filtered
8736/// out.
8737///
8738/// @return the number removed variables that have been filtered out.
8739size_t
8741{
8742 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
8743 return num_vars_removed();
8744 return priv_->num_removed_vars_filtered_out;
8745}
8746
8747/// Setter for the number of removed variables that have been filtered
8748/// out.
8749///
8750/// @param n the new value.
8751void
8753{priv_->num_removed_vars_filtered_out = n;}
8754
8755/// Getter for the net number of removed variables.
8756///
8757/// The net number of removed variables is the difference between the
8758/// number of removed variables and the number of removed variables
8759/// that have been filtered out.
8760///
8761/// @return the net number of removed variables.
8762size_t
8764{
8765 ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
8766 return num_vars_removed() - num_removed_vars_filtered_out();
8767}
8768
8769/// Getter for the number of variables added.
8770///
8771/// @return the number of variables added.
8772size_t
8774{return priv_->num_vars_added;}
8775
8776/// Setter for the number of variables added.
8777///
8778/// @param n the new number of variables added.
8779void
8781{priv_->num_vars_added = n;}
8782
8783/// Getter for the number of added variables that have been filtered
8784/// out.
8785///
8786/// @return the number of added variables that have been filtered out.
8787size_t
8789{
8790 if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8791 return num_vars_added();
8792 return priv_->num_added_vars_filtered_out;
8793}
8794
8795/// Setter for the number of added variables that have been filtered
8796/// out.
8797///
8798/// @param n the new value.
8799void
8801{priv_->num_added_vars_filtered_out = n;}
8802
8803/// Getter for the net number of added variables.
8804///
8805/// The net number of added variables is the difference between the
8806/// number of added variables and the number of added variables that
8807/// have been filetered out.
8808///
8809/// @return the net number of added variables.
8810size_t
8812{
8813 ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8814 return num_vars_added() - num_added_vars_filtered_out();
8815}
8816
8817/// Getter for the number of variables that have a change in one of
8818/// their sub-types.
8819///
8820/// @return the number of variables that have a change in one of their
8821/// sub-types.
8822size_t
8824{return priv_->num_vars_changed;}
8825
8826/// Setter for the number of variables that have a change in one of
8827/// their sub-types.
8828///
8829/// @param n the new number of variables that have a change in one of
8830/// their sub-types.
8831void
8833{priv_->num_vars_changed = n;}
8834
8835/// Getter for the number of variables that have a change in one of
8836/// their sub-types, and that have been filtered out.
8837///
8838/// @return the number of functions that have a change in one of their
8839/// sub-types, and that have been filtered out.
8840size_t
8842{return priv_->num_changed_vars_filtered_out;}
8843
8844/// Setter for the number of variables that have a change in one of
8845/// their sub-types, and that have been filtered out.
8846///
8847/// @param n the new number of variables that have a change in one of their
8848/// sub-types, and that have been filtered out.
8849void
8851{priv_->num_changed_vars_filtered_out = n;}
8852
8853/// Getter for the number of variables that have a change in their
8854/// sub-types, minus the number of these variables that got filtered
8855/// out from the diff.
8856///
8857/// @return for the the number of variables that have a change in
8858/// their sub-types, minus the number of these variables that got
8859/// filtered out from the diff.
8860size_t
8862{return num_vars_changed() - num_changed_vars_filtered_out();}
8863
8864/// Getter for the number of function symbols (not referenced by any
8865/// debug info) that got removed.
8866///
8867/// @return the number of function symbols (not referenced by any
8868/// debug info) that got removed.
8869size_t
8871{return priv_->num_func_syms_removed;}
8872
8873/// Setter for the number of function symbols (not referenced by any
8874/// debug info) that got removed.
8875///
8876/// @param n the number of function symbols (not referenced by any
8877/// debug info) that got removed.
8878void
8880{priv_->num_func_syms_removed = n;}
8881
8882/// Getter for the number of removed function symbols, not referenced
8883/// by debug info, that have been filtered out.
8884///
8885/// @return the number of removed function symbols, not referenced by
8886/// debug info, that have been filtered out.
8887size_t
8889{
8890 if (priv_->ctxt()
8891 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8892 return num_func_syms_removed();
8893 return priv_->num_removed_func_syms_filtered_out;
8894}
8895
8896/// Setter for the number of removed function symbols, not referenced
8897/// by debug info, that have been filtered out.
8898///
8899/// @param n the new the number of removed function symbols, not
8900/// referenced by debug info, that have been filtered out.
8901void
8903{priv_->num_removed_func_syms_filtered_out = n;}
8904
8905/// Getter of the net number of removed function symbols that are not
8906/// referenced by any debug info.
8907///
8908/// This is the difference between the total number of removed
8909/// function symbols and the number of removed function symbols that
8910/// have been filteted out. Both numbers are for symbols not
8911/// referenced by debug info.
8912///
8913/// return the net number of removed function symbols that are not
8914/// referenced by any debug info.
8915size_t
8917{
8918 ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8919 return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8920}
8921
8922/// Getter for the number of function symbols (not referenced by any
8923/// debug info) that got added.
8924///
8925/// @return the number of function symbols (not referenced by any
8926/// debug info) that got added.
8927size_t
8929{return priv_->num_func_syms_added;}
8930
8931/// Setter for the number of function symbols (not referenced by any
8932/// debug info) that got added.
8933///
8934/// @param n the new number of function symbols (not referenced by any
8935/// debug info) that got added.
8936void
8938{priv_->num_func_syms_added = n;}
8939
8940/// Getter for the number of added function symbols, not referenced by
8941/// any debug info, that have been filtered out.
8942///
8943/// @return the number of added function symbols, not referenced by
8944/// any debug info, that have been filtered out.
8945size_t
8947{
8948 if (priv_->ctxt()
8949 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8950 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8951 return num_func_syms_added();
8952 return priv_->num_added_func_syms_filtered_out;
8953}
8954
8955/// Setter for the number of added function symbols, not referenced by
8956/// any debug info, that have been filtered out.
8957///
8958/// @param n the new number of added function symbols, not referenced
8959/// by any debug info, that have been filtered out.
8960void
8962{priv_->num_added_func_syms_filtered_out = n;}
8963
8964/// Getter of the net number of added function symbols that are not
8965/// referenced by any debug info.
8966///
8967/// This is the difference between the total number of added
8968/// function symbols and the number of added function symbols that
8969/// have been filteted out. Both numbers are for symbols not
8970/// referenced by debug info.
8971///
8972/// return the net number of added function symbols that are not
8973/// referenced by any debug info.
8974size_t
8976{
8977 ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8978 return num_func_syms_added()- num_added_func_syms_filtered_out();
8979}
8980
8981/// Getter for the number of variable symbols (not referenced by any
8982/// debug info) that got removed.
8983///
8984/// @return the number of variable symbols (not referenced by any
8985/// debug info) that got removed.
8986size_t
8988{return priv_->num_var_syms_removed;}
8989
8990/// Setter for the number of variable symbols (not referenced by any
8991/// debug info) that got removed.
8992///
8993/// @param n the number of variable symbols (not referenced by any
8994/// debug info) that got removed.
8995void
8997{priv_->num_var_syms_removed = n;}
8998
8999/// Getter for the number of removed variable symbols, not referenced
9000/// by any debug info, that have been filtered out.
9001///
9002/// @return the number of removed variable symbols, not referenced
9003/// by any debug info, that have been filtered out.
9004size_t
9006{
9007 if (priv_->ctxt()
9008 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
9009 return num_var_syms_removed();
9010 return priv_->num_removed_var_syms_filtered_out;
9011}
9012
9013/// Setter for the number of removed variable symbols, not referenced
9014/// by any debug info, that have been filtered out.
9015///
9016/// @param n the number of removed variable symbols, not referenced by
9017/// any debug info, that have been filtered out.
9018void
9020{priv_->num_removed_var_syms_filtered_out = n;}
9021
9022/// Getter of the net number of removed variable symbols that are not
9023/// referenced by any debug info.
9024///
9025/// This is the difference between the total number of removed
9026/// variable symbols and the number of removed variable symbols that
9027/// have been filteted out. Both numbers are for symbols not
9028/// referenced by debug info.
9029///
9030/// return the net number of removed variable symbols that are not
9031/// referenced by any debug info.
9032size_t
9034{
9035 ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
9036 return num_var_syms_removed() - num_removed_var_syms_filtered_out();
9037}
9038
9039/// Getter for the number of variable symbols (not referenced by any
9040/// debug info) that got added.
9041///
9042/// @return the number of variable symbols (not referenced by any
9043/// debug info) that got added.
9044size_t
9046{return priv_->num_var_syms_added;}
9047
9048/// Setter for the number of variable symbols (not referenced by any
9049/// debug info) that got added.
9050///
9051/// @param n the new number of variable symbols (not referenced by any
9052/// debug info) that got added.
9053void
9055{priv_->num_var_syms_added = n;}
9056
9057/// Getter for the number of added variable symbols, not referenced by
9058/// any debug info, that have been filtered out.
9059///
9060/// @return the number of added variable symbols, not referenced by
9061/// any debug info, that have been filtered out.
9062size_t
9064{
9065 if (priv_->ctxt()
9066 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9067 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9068 return num_var_syms_added();
9069 return priv_->num_added_var_syms_filtered_out;
9070}
9071
9072/// Setter for the number of added variable symbols, not referenced by
9073/// any debug info, that have been filtered out.
9074///
9075/// @param n the new number of added variable symbols, not referenced
9076/// by any debug info, that have been filtered out.
9077void
9079{priv_->num_added_var_syms_filtered_out = n;}
9080
9081/// Getter of the net number of added variable symbols that are not
9082/// referenced by any debug info.
9083///
9084/// This is the difference between the total number of added
9085/// variable symbols and the number of added variable symbols that
9086/// have been filteted out. Both numbers are for symbols not
9087/// referenced by debug info.
9088///
9089/// return the net number of added variable symbols that are not
9090/// referenced by any debug info.
9091size_t
9093{
9094 ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
9095 return num_var_syms_added() - num_added_var_syms_filtered_out();
9096}
9097
9098/// Getter of the number of leaf type change diff nodes.
9099///
9100/// @return the number of leaf type change diff nodes.
9101size_t
9103{return priv_->num_leaf_changes;}
9104
9105/// Setter of the number of leaf type change diff nodes.
9106///
9107/// @param n the new number of leaf type change diff nodes.
9108void
9110{priv_->num_leaf_changes = n;}
9111
9112/// Getter of the number of leaf type change diff nodes that have been
9113/// filtered out.
9114///
9115/// @return the number of leaf type change diff nodes that have been
9116size_t
9118{return priv_->num_leaf_changes_filtered_out;}
9119
9120/// Setter of the number of leaf type change diff nodes that have been
9121/// filtered out.
9122///
9123/// @param n the new number of leaf type change diff nodes that have
9124/// been filtered out.
9125void
9127{priv_->num_leaf_changes_filtered_out = n;}
9128
9129/// Getter of the net number of leaf change diff nodes.
9130///
9131/// This is the difference between the total number of leaf change
9132/// diff nodes, and the number of the leaf change diff nodes that have
9133/// been filtered out.
9134///
9135/// A leaf change is either a type change, a function change or a
9136/// variable change.
9137size_t
9139{
9140 ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
9141 return num_leaf_changes() - num_leaf_changes_filtered_out();
9142}
9143
9144/// Getter for the number of leaf type change diff nodes.
9145///
9146/// @return the number of leaf type changes diff nodes.
9147size_t
9149{return priv_->num_leaf_type_changes;}
9150
9151/// Setter for the number of leaf type change diff nodes.
9152///
9153/// @param n the new number of leaf type change diff nodes.
9154void
9156{priv_->num_leaf_type_changes = n;}
9157
9158/// Getter for the number of filtered out leaf type change diff nodes.
9159///
9160/// @return the number of filtered out leaf type change diff nodes.
9161size_t
9163{return priv_->num_leaf_type_changes_filtered_out;}
9164
9165/// Setter for the number of filtered out leaf type change diff nodes.
9166/// @param n the new number of filtered out leaf type change diff nodes.
9167void
9169{priv_->num_leaf_type_changes_filtered_out = n;}
9170
9171/// Getter for the net number of leaf type change diff nodes.
9172///
9173/// This is the difference between the number of leaf type changes and
9174/// the number of filtered out leaf type changes.
9175///
9176/// @return the net number of leaf type change diff nodes.
9177size_t
9179{return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
9180
9181/// Getter for the number of leaf function change diff nodes.
9182///
9183/// @return the number of leaf function change diff nodes.
9184size_t
9186{return priv_->num_leaf_func_changes;}
9187
9188/// Setter for the number of leaf function change diff nodes.
9189///
9190/// @param n the new number of leaf function change diff nodes.
9191void
9193{priv_->num_leaf_func_changes = n;}
9194
9195/// Getter for the number of leaf function change diff nodes that were
9196/// filtered out.
9197///
9198/// @return the number of leaf function change diff nodes that were
9199/// filtered out.
9200size_t
9202{return priv_->num_leaf_func_changes_filtered_out;}
9203
9204/// Setter for the number of leaf function change diff nodes that were
9205/// filtered out.
9206///
9207/// @param n the new number of leaf function change diff nodes that
9208/// were filtered out.
9209void
9211{priv_->num_leaf_func_changes_filtered_out = n;}
9212
9213/// Getter for the net number of leaf function change diff nodes.
9214///
9215/// This is the difference between the number of leaf function change
9216/// diff nodes and the number of filtered out leaf function change
9217/// diff nodes.
9218///
9219/// @return the net number of leaf function change diff nodes.
9220size_t
9222{return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
9223
9224/// Getter for the number of leaf variable change diff nodes.
9225///
9226/// @return the number of leaf variable change diff nodes.
9227size_t
9229{return priv_->num_leaf_var_changes;}
9230
9231/// Setter for the number of leaf variable change diff nodes.
9232///
9233/// @param n the number of leaf variable change diff nodes.
9234void
9236{priv_->num_leaf_var_changes = n;}
9237
9238/// Getter of the number of added types that are unreachable from the
9239/// public interface of the ABI corpus.
9240///
9241/// Public interface means the set of defined and publicly exported
9242/// functions and variables of the ABI corpus.
9243///
9244/// @return the number of added types that are unreachable from the
9245/// public interface of the ABI corpus.
9246size_t
9248{return priv_->num_added_unreachable_types;}
9249
9250/// Setter of the number of added types that are unreachable from the
9251/// public interface (global functions or variables) of the ABI
9252/// corpus.
9253///
9254/// Public interface means the set of defined and publicly exported
9255/// functions and variables of the ABI corpus.
9256///
9257/// @param n the new number of added types that are unreachable from
9258/// the public interface of the ABI corpus.
9259void
9261{priv_->num_added_unreachable_types = n;}
9262
9263/// Getter of the number of added types that are unreachable from
9264/// public interfaces and that are filtered out by suppression
9265/// specifications.
9266///
9267/// @return the number of added types that are unreachable from public
9268/// interfaces and that are filtered out by suppression
9269/// specifications.
9270size_t
9272{return priv_->num_added_unreachable_types_filtered_out;}
9273
9274/// Setter of the number of added types that are unreachable from
9275/// public interfaces and that are filtered out by suppression
9276/// specifications.
9277///
9278/// @param n the new number of added types that are unreachable from
9279/// public interfaces and that are filtered out by suppression
9280/// specifications.
9281void
9283{priv_->num_added_unreachable_types_filtered_out = n;}
9284
9285/// Getter of the number of added types that are unreachable from
9286/// public interfaces and that are *NOT* filtered out by suppression
9287/// specifications.
9288///
9289/// @return the number of added types that are unreachable from public
9290/// interfaces and that are *NOT* filtered out by suppression
9291/// specifications.
9292size_t
9294{
9295 ABG_ASSERT(num_added_unreachable_types()
9296 >=
9297 num_added_unreachable_types_filtered_out());
9298
9299 return (num_added_unreachable_types()
9300 -
9301 num_added_unreachable_types_filtered_out());
9302}
9303
9304/// Getter of the number of removed types that are unreachable from
9305/// the public interface of the ABI corpus.
9306///
9307/// Public interface means the set of defined and publicly exported
9308/// functions and variables of the ABI corpus.
9309///
9310/// @return the number of removed types that are unreachable from
9311/// the public interface of the ABI corpus.
9312size_t
9314{return priv_->num_removed_unreachable_types;}
9315
9316/// Setter of the number of removed types that are unreachable from
9317/// the public interface of the ABI corpus.
9318///
9319/// Public interface means the set of defined and publicly exported
9320/// functions and variables of the ABI corpus.
9321///
9322///@param n the new number of removed types that are unreachable from
9323/// the public interface of the ABI corpus.
9324void
9326{priv_->num_removed_unreachable_types = n;}
9327
9328/// Getter of the number of removed types that are not reachable from
9329/// public interfaces and that have been filtered out by suppression
9330/// specifications.
9331///
9332/// @return the number of removed types that are not reachable from
9333/// public interfaces and that have been filtered out by suppression
9334/// specifications.
9335size_t
9337{return priv_->num_removed_unreachable_types_filtered_out;}
9338
9339/// Setter of the number of removed types that are not reachable from
9340/// public interfaces and that have been filtered out by suppression
9341/// specifications.
9342///
9343/// @param n the new number of removed types that are not reachable
9344/// from public interfaces and that have been filtered out by
9345/// suppression specifications.
9346void
9348{priv_->num_removed_unreachable_types_filtered_out = n;}
9349
9350/// Getter of the number of removed types that are not reachable from
9351/// public interfaces and that have *NOT* been filtered out by
9352/// suppression specifications.
9353///
9354/// @return the number of removed types that are not reachable from
9355/// public interfaces and that have *NOT* been filtered out by
9356/// suppression specifications.
9357size_t
9359{
9360 ABG_ASSERT(num_removed_unreachable_types()
9361 >=
9362 num_removed_unreachable_types_filtered_out());
9363
9364 return (num_removed_unreachable_types()
9365 -
9366 num_removed_unreachable_types_filtered_out());
9367}
9368
9369/// Getter of the number of changed types that are unreachable from
9370/// the public interface of the ABI corpus.
9371///
9372/// Public interface means the set of defined and publicly exported
9373/// functions and variables of the ABI corpus.
9374///
9375/// @return the number of changed types that are unreachable from the
9376/// public interface of the ABI corpus.
9377size_t
9379{return priv_->num_changed_unreachable_types;}
9380
9381/// Setter of the number of changed types that are unreachable from
9382/// the public interface of the ABI corpus.
9383///
9384/// Public interface means the set of defined and publicly exported
9385/// functions and variables of the ABI corpus.
9386///
9387///@param n the new number of changed types that are unreachable from
9388/// the public interface of the ABI corpus.
9389void
9391{priv_->num_changed_unreachable_types = n;}
9392
9393/// Getter of the number of changed types that are unreachable from
9394/// public interfaces and that have been filtered out by suppression
9395/// specifications.
9396///
9397/// @return the number of changed types that are unreachable from
9398/// public interfaces and that have been filtered out by suppression
9399/// specifications.
9400size_t
9402{return priv_->num_changed_unreachable_types_filtered_out;}
9403
9404/// Setter of the number of changed types that are unreachable from
9405/// public interfaces and that have been filtered out by suppression
9406/// specifications.
9407///
9408/// @param n the new number of changed types that are unreachable from
9409/// public interfaces and that have been filtered out by suppression
9410/// specifications.
9411void
9413{priv_->num_changed_unreachable_types_filtered_out = n;}
9414
9415/// Getter of the number of changed types that are unreachable from
9416/// public interfaces and that have *NOT* been filtered out by
9417/// suppression specifications.
9418///
9419/// @return the number of changed types that are unreachable from
9420/// public interfaces and that have *NOT* been filtered out by
9421/// suppression specifications.
9422size_t
9424{
9425 ABG_ASSERT(num_changed_unreachable_types()
9426 >=
9427 num_changed_unreachable_types_filtered_out());
9428
9429 return (num_changed_unreachable_types()
9430 -
9431 num_changed_unreachable_types_filtered_out());
9432}
9433
9434/// Getter for the number of leaf variable changes diff nodes that
9435/// have been filtered out.
9436///
9437/// @return the number of leaf variable changes diff nodes that have
9438/// been filtered out.
9439size_t
9441{return priv_->num_leaf_var_changes_filtered_out;}
9442
9443/// Setter for the number of leaf variable changes diff nodes that
9444/// have been filtered out.
9445///
9446/// @param n the number of leaf variable changes diff nodes that have
9447/// been filtered out.
9448void
9450{priv_->num_leaf_var_changes_filtered_out = n;}
9451
9452/// Getter for the net number of leaf variable change diff nodes.
9453///
9454/// This the difference between the number of leaf variable change
9455/// diff nodes and the number of filtered out leaf variable change
9456/// diff nodes.
9457///
9458/// @return the net number of leaf variable change diff nodes.
9459size_t
9461{return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9462
9463
9464// <corpus_diff stuff>
9465
9466/// Getter of the context associated with this corpus.
9467///
9468/// @return a smart pointer to the context associate with the corpus.
9471{return ctxt_.lock();}
9472
9473/// Tests if the lookup tables are empty.
9474///
9475/// @return true if the lookup tables are empty, false otherwise.
9476bool
9478{
9479 return (deleted_fns_.empty()
9480 && added_fns_.empty()
9481 && changed_fns_map_.empty()
9482 && deleted_vars_.empty()
9483 && added_vars_.empty()
9484 && changed_vars_map_.empty());
9485}
9486
9487/// Clear the lookup tables useful for reporting an enum_diff.
9488void
9490{
9491 deleted_fns_.clear();
9492 added_fns_.clear();
9493 changed_fns_map_.clear();
9494 deleted_vars_.clear();
9495 added_vars_.clear();
9496 changed_vars_map_.clear();
9497}
9498
9499/// If the lookup tables are not yet built, walk the differences and
9500/// fill the lookup tables.
9501void
9503{
9504 if (!lookup_tables_empty())
9505 return;
9506
9507 diff_context_sptr ctxt = get_context();
9508
9509 {
9510 edit_script& e = fns_edit_script_;
9511
9512 for (vector<deletion>::const_iterator it = e.deletions().begin();
9513 it != e.deletions().end();
9514 ++it)
9515 {
9516 unsigned i = it->index();
9517 ABG_ASSERT(i < first_->get_functions().size());
9518
9519 const function_decl* deleted_fn = first_->get_functions()[i];
9520 string n = get_function_id_or_pretty_representation(deleted_fn);
9521 ABG_ASSERT(!n.empty());
9522 // The below is commented out because there can be several
9523 // functions with the same ID in the corpus. So several
9524 // functions with the same ID can be deleted.
9525 // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9526 deleted_fns_[n] = deleted_fn;
9527 }
9528
9529 for (vector<insertion>::const_iterator it = e.insertions().begin();
9530 it != e.insertions().end();
9531 ++it)
9532 {
9533 for (vector<unsigned>::const_iterator iit =
9534 it->inserted_indexes().begin();
9535 iit != it->inserted_indexes().end();
9536 ++iit)
9537 {
9538 unsigned i = *iit;
9539 const function_decl* added_fn = second_->get_functions()[i];
9540 string n = get_function_id_or_pretty_representation(added_fn);
9541 ABG_ASSERT(!n.empty());
9542 // The below is commented out because there can be several
9543 // functions with the same ID in the corpus. So several
9544 // functions with the same ID can be added.
9545 // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9546 string_function_ptr_map::const_iterator j =
9547 deleted_fns_.find(n);
9548 if (j != deleted_fns_.end())
9549 {
9550 function_decl_sptr f(const_cast<function_decl*>(j->second),
9551 noop_deleter());
9552 function_decl_sptr s(const_cast<function_decl*>(added_fn),
9553 noop_deleter());
9554 function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9555 if (*j->second != *added_fn)
9556 changed_fns_map_[j->first] = d;
9557 deleted_fns_.erase(j);
9558 }
9559 else
9560 added_fns_[n] = added_fn;
9561 }
9562 }
9563 sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9564
9565 // Now walk the allegedly deleted functions; check if their
9566 // underlying symbols are deleted as well; otherwise, consider
9567 // that the function in question hasn't been deleted.
9568
9569 vector<string> to_delete;
9570 for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9571 i != deleted_fns_.end();
9572 ++i)
9573 if (second_->lookup_function_symbol(*i->second->get_symbol()))
9574 to_delete.push_back(i->first);
9575
9576 for (vector<string>::const_iterator i = to_delete.begin();
9577 i != to_delete.end();
9578 ++i)
9579 deleted_fns_.erase(*i);
9580
9581 // Do something similar for added functions.
9582
9583 to_delete.clear();
9584 for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9585 i != added_fns_.end();
9586 ++i)
9587 {
9588 if (first_->lookup_function_symbol(*i->second->get_symbol()))
9589 to_delete.push_back(i->first);
9590 else if (! i->second->get_symbol()->get_version().is_empty()
9591 && i->second->get_symbol()->get_version().is_default())
9592 // We are looking for a symbol that has a default version,
9593 // and which seems to be newly added. Let's see if the same
9594 // symbol with *no* version was already present in the
9595 // former corpus. If yes, then the symbol shouldn't be
9596 // considered as 'added'.
9597 {
9598 elf_symbol::version empty_version;
9599 if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
9600 empty_version))
9601 to_delete.push_back(i->first);
9602 }
9603 }
9604
9605 for (vector<string>::const_iterator i = to_delete.begin();
9606 i != to_delete.end();
9607 ++i)
9608 added_fns_.erase(*i);
9609 }
9610
9611 {
9612 edit_script& e = vars_edit_script_;
9613
9614 for (vector<deletion>::const_iterator it = e.deletions().begin();
9615 it != e.deletions().end();
9616 ++it)
9617 {
9618 unsigned i = it->index();
9619 ABG_ASSERT(i < first_->get_variables().size());
9620
9621 const var_decl* deleted_var = first_->get_variables()[i];
9622 string n = deleted_var->get_id();
9623 ABG_ASSERT(!n.empty());
9624 ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
9625 deleted_vars_[n] = deleted_var;
9626 }
9627
9628 for (vector<insertion>::const_iterator it = e.insertions().begin();
9629 it != e.insertions().end();
9630 ++it)
9631 {
9632 for (vector<unsigned>::const_iterator iit =
9633 it->inserted_indexes().begin();
9634 iit != it->inserted_indexes().end();
9635 ++iit)
9636 {
9637 unsigned i = *iit;
9638 const var_decl* added_var = second_->get_variables()[i];
9639 string n = added_var->get_id();
9640 ABG_ASSERT(!n.empty());
9641 {
9642 string_var_ptr_map::const_iterator k = added_vars_.find(n);
9643 if ( k != added_vars_.end())
9644 {
9645 ABG_ASSERT(is_member_decl(k->second)
9646 && get_member_is_static(k->second));
9647 continue;
9648 }
9649 }
9650 string_var_ptr_map::const_iterator j =
9651 deleted_vars_.find(n);
9652 if (j != deleted_vars_.end())
9653 {
9654 if (*j->second != *added_var)
9655 {
9656 var_decl_sptr f(const_cast<var_decl*>(j->second),
9657 noop_deleter());
9658 var_decl_sptr s(const_cast<var_decl*>(added_var),
9659 noop_deleter());
9660 changed_vars_map_[n] = compute_diff(f, s, ctxt);
9661 }
9662 deleted_vars_.erase(j);
9663 }
9664 else
9665 added_vars_[n] = added_var;
9666 }
9667 }
9668 sort_string_var_diff_sptr_map(changed_vars_map_,
9669 sorted_changed_vars_);
9670
9671 // Now walk the allegedly deleted variables; check if their
9672 // underlying symbols are deleted as well; otherwise consider
9673 // that the variable in question hasn't been deleted.
9674
9675 vector<string> to_delete;
9676 for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
9677 i != deleted_vars_.end();
9678 ++i)
9679 if (second_->lookup_variable_symbol(*i->second->get_symbol()))
9680 to_delete.push_back(i->first);
9681
9682 for (vector<string>::const_iterator i = to_delete.begin();
9683 i != to_delete.end();
9684 ++i)
9685 deleted_vars_.erase(*i);
9686
9687 // Do something similar for added variables.
9688
9689 to_delete.clear();
9690 for (string_var_ptr_map::const_iterator i = added_vars_.begin();
9691 i != added_vars_.end();
9692 ++i)
9693 if (first_->lookup_variable_symbol(*i->second->get_symbol()))
9694 to_delete.push_back(i->first);
9695 else if (! i->second->get_symbol()->get_version().is_empty()
9696 && i->second->get_symbol()->get_version().is_default())
9697 // We are looking for a symbol that has a default version,
9698 // and which seems to be newly added. Let's see if the same
9699 // symbol with *no* version was already present in the
9700 // former corpus. If yes, then the symbol shouldn't be
9701 // considered as 'added'.
9702 {
9703 elf_symbol::version empty_version;
9704 if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
9705 empty_version))
9706 to_delete.push_back(i->first);
9707 }
9708
9709 for (vector<string>::const_iterator i = to_delete.begin();
9710 i != to_delete.end();
9711 ++i)
9712 added_vars_.erase(*i);
9713 }
9714
9715 // Massage the edit script for added/removed function symbols that
9716 // were not referenced by any debug info and turn them into maps of
9717 // {symbol_name, symbol}.
9718 {
9719 edit_script& e = unrefed_fn_syms_edit_script_;
9720 for (vector<deletion>::const_iterator it = e.deletions().begin();
9721 it != e.deletions().end();
9722 ++it)
9723 {
9724 unsigned i = it->index();
9725 ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
9726 elf_symbol_sptr deleted_sym =
9727 first_->get_unreferenced_function_symbols()[i];
9728 if (!second_->lookup_function_symbol(*deleted_sym))
9729 deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
9730 }
9731
9732 for (vector<insertion>::const_iterator it = e.insertions().begin();
9733 it != e.insertions().end();
9734 ++it)
9735 {
9736 for (vector<unsigned>::const_iterator iit =
9737 it->inserted_indexes().begin();
9738 iit != it->inserted_indexes().end();
9739 ++iit)
9740 {
9741 unsigned i = *iit;
9742 ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
9743 elf_symbol_sptr added_sym =
9744 second_->get_unreferenced_function_symbols()[i];
9745 if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
9746 == deleted_unrefed_fn_syms_.end()))
9747 {
9748 if (!first_->lookup_function_symbol(*added_sym))
9749 {
9750 bool do_add = true;
9751 if (! added_sym->get_version().is_empty()
9752 && added_sym->get_version().is_default())
9753 {
9754 // So added_seem has a default version. If
9755 // the former corpus had a symbol with the
9756 // same name as added_sym but with *no*
9757 // version, then added_sym shouldn't be
9758 // considered as a newly added symbol.
9759 elf_symbol::version empty_version;
9760 if (first_->lookup_function_symbol(added_sym->get_name(),
9761 empty_version))
9762 do_add = false;
9763 }
9764
9765 if (do_add)
9766 added_unrefed_fn_syms_[added_sym->get_id_string()] =
9767 added_sym;
9768 }
9769 }
9770 else
9771 deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
9772 }
9773 }
9774 }
9775
9776 // Massage the edit script for added/removed variable symbols that
9777 // were not referenced by any debug info and turn them into maps of
9778 // {symbol_name, symbol}.
9779 {
9780 edit_script& e = unrefed_var_syms_edit_script_;
9781 for (vector<deletion>::const_iterator it = e.deletions().begin();
9782 it != e.deletions().end();
9783 ++it)
9784 {
9785 unsigned i = it->index();
9786 ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9787 elf_symbol_sptr deleted_sym =
9788 first_->get_unreferenced_variable_symbols()[i];
9789 if (!second_->lookup_variable_symbol(*deleted_sym))
9790 deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9791 }
9792
9793 for (vector<insertion>::const_iterator it = e.insertions().begin();
9794 it != e.insertions().end();
9795 ++it)
9796 {
9797 for (vector<unsigned>::const_iterator iit =
9798 it->inserted_indexes().begin();
9799 iit != it->inserted_indexes().end();
9800 ++iit)
9801 {
9802 unsigned i = *iit;
9803 ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9804 elf_symbol_sptr added_sym =
9805 second_->get_unreferenced_variable_symbols()[i];
9806 if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9807 == deleted_unrefed_var_syms_.end())
9808 {
9809 if (!first_->lookup_variable_symbol(*added_sym))
9810 {
9811 bool do_add = true;
9812 if (! added_sym->get_version().is_empty()
9813 && added_sym->get_version().is_default())
9814 {
9815 // So added_seem has a default version. If
9816 // the former corpus had a symbol with the
9817 // same name as added_sym but with *no*
9818 // version, then added_sym shouldn't be
9819 // considered as a newly added symbol.
9820 elf_symbol::version empty_version;
9821 if (first_->lookup_variable_symbol(added_sym->get_name(),
9822 empty_version))
9823 do_add = false;
9824 }
9825
9826 if (do_add)
9827 added_unrefed_var_syms_[added_sym->get_id_string()] =
9828 added_sym;
9829 }
9830 }
9831 else
9832 deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9833 }
9834 }
9835 }
9836
9837 // Handle the unreachable_types_edit_script_
9838 {
9839 edit_script& e = unreachable_types_edit_script_;
9840
9841 // Populate the map of deleted unreachable types from the
9842 // deletions of the edit script.
9843 for (vector<deletion>::const_iterator it = e.deletions().begin();
9844 it != e.deletions().end();
9845 ++it)
9846 {
9847 unsigned i = it->index();
9848 type_base_sptr t
9849 (first_->get_types_not_reachable_from_public_interfaces()[i]);
9850
9851 if (!is_user_defined_type(t))
9852 continue;
9853
9854 string repr =
9855 abigail::ir::get_pretty_representation(t, /*internal=*/false);
9856 deleted_unreachable_types_[repr] = t;
9857 }
9858
9859 // Populate the map of added and change unreachable types from the
9860 // insertions of the edit script.
9861 for (vector<insertion>::const_iterator it = e.insertions().begin();
9862 it != e.insertions().end();
9863 ++it)
9864 {
9865 for (vector<unsigned>::const_iterator iit =
9866 it->inserted_indexes().begin();
9867 iit != it->inserted_indexes().end();
9868 ++iit)
9869 {
9870 unsigned i = *iit;
9871 type_base_sptr t
9872 (second_->get_types_not_reachable_from_public_interfaces()[i]);
9873
9874 if (!is_user_defined_type(t))
9875 continue;
9876
9877 string repr =
9878 abigail::ir::get_pretty_representation(t, /*internal=*/false);
9879
9880 // Let's see if the inserted type we are looking at was
9881 // reported as deleted as well.
9882 //
9883 // If it's been deleted and a different version of it has
9884 // now been added, it means it's been *changed*. In that
9885 // case we'll compute the diff of that change and store it
9886 // in the map of changed unreachable types.
9887 //
9888 // Otherwise, it means the type's been added so we'll add
9889 // it to the set of added unreachable types.
9890
9891 string_type_base_sptr_map::const_iterator j =
9892 deleted_unreachable_types_.find(repr);
9893 if (j != deleted_unreachable_types_.end())
9894 {
9895 // So there was another type of the same pretty
9896 // representation which was reported as deleted.
9897 // Let's see if they are different or not ...
9898 decl_base_sptr old_type = is_decl(j->second);
9899 decl_base_sptr new_type = is_decl(t);
9900 if (old_type != new_type)
9901 {
9902 // The previously added type is different from this
9903 // one that is added. That means the initial type
9904 // was changed. Let's compute its diff and store it
9905 // as a changed type.
9906 diff_sptr d = compute_diff(old_type, new_type, ctxt);
9907 ABG_ASSERT(d->has_changes());
9908 changed_unreachable_types_[repr]= d;
9909 }
9910
9911 // In any case, the type was both deleted and added,
9912 // so we cannot have it marked as being deleted. So
9913 // let's remove it from the deleted types.
9914 deleted_unreachable_types_.erase(j);
9915 }
9916 else
9917 // The type wasn't previously reported as deleted, so
9918 // it's really added.
9919 added_unreachable_types_[repr] = t;
9920 }
9921 }
9922
9923 // Handle anonymous enums that got changed. An anonymous enum is
9924 // designated by its flat textual representation. So a change to
9925 // any of its enumerators results in a different enum. That is
9926 // represented by a deletion of the previous anonymous enum, and
9927 // the addition of a new one. For the user however, it's the same
9928 // enum that changed. Let's massage this "added/removed" pattern
9929 // to show what the user expects, namely, a changed anonymous
9930 // enum.
9931 {
9932 std::set<type_base_sptr> deleted_anon_types;
9933 std::set<type_base_sptr> added_anon_types;
9934
9935 for (auto entry : deleted_unreachable_types_)
9936 {
9937 if ((is_enum_type(entry.second)
9938 && is_enum_type(entry.second)->get_is_anonymous())
9939 || (is_class_or_union_type(entry.second)
9940 && is_class_or_union_type(entry.second)->get_is_anonymous()))
9941 deleted_anon_types.insert(entry.second);
9942 }
9943
9944
9945 for (auto entry : added_unreachable_types_)
9946 if ((is_enum_type(entry.second)
9947 && is_enum_type(entry.second)->get_is_anonymous())
9948 || (is_class_or_union_type(entry.second)
9949 && is_class_or_union_type(entry.second)->get_is_anonymous()))
9950 added_anon_types.insert(entry.second);
9951
9952 string_type_base_sptr_map added_anon_types_to_erase;
9953 string_type_base_sptr_map removed_anon_types_to_erase;
9954 enum_type_decl_sptr deleted_enum;
9955 class_or_union_sptr deleted_class;
9956
9957 // Look for deleted anonymous types (enums, unions, structs &
9958 // classes) which have enumerators or data members present in an
9959 // added anonymous type ...
9960 for (auto deleted: deleted_anon_types)
9961 {
9962 deleted_enum = is_enum_type(deleted);
9963 deleted_class = is_class_or_union_type(deleted);
9964
9965 // For enums, look for any enumerator of 'deleted_enum' that
9966 // is also present in an added anonymous enum.
9967 if (deleted_enum)
9968 {
9969 for (auto enr : deleted_enum->get_enumerators())
9970 {
9971 bool this_enum_got_changed = false;
9972 for (auto t : added_anon_types)
9973 {
9974 if (enum_type_decl_sptr added_enum = is_enum_type(t))
9975 if (is_enumerator_present_in_enum(enr, *added_enum))
9976 {
9977 // So the enumerator 'enr' from the
9978 // 'deleted_enum' enum is also present in the
9979 // 'added_enum' enum so we assume that
9980 // 'deleted_enum' and 'added_enum' are the same
9981 // enum that got changed. Let's represent it
9982 // using a diff node.
9983 diff_sptr d = compute_diff(deleted_enum,
9984 added_enum, ctxt);
9985 ABG_ASSERT(d->has_changes());
9986 string repr =
9988 /*internal=*/false);
9989 changed_unreachable_types_[repr]= d;
9990 this_enum_got_changed = true;
9991 string r1 =
9993 /*internal=*/false);
9994 string r2 =
9996 /*internal=*/false);
9997 removed_anon_types_to_erase[r1] = deleted_enum;
9998 added_anon_types_to_erase[r2] = added_enum;
9999 break;
10000 }
10001 }
10002 if (this_enum_got_changed)
10003 break;
10004 }
10005 }
10006 else if (deleted_class)
10007 {
10008 // For unions, structs & classes, look for any data
10009 // member of 'deleted_class' that is also present in an
10010 // added anonymous class.
10011 for (auto dm : deleted_class->get_data_members())
10012 {
10013 bool this_class_got_changed = false;
10014 for (auto klass : added_anon_types)
10015 {
10016 if (class_or_union_sptr added_class =
10018 if (class_or_union_types_of_same_kind(deleted_class,
10019 added_class)
10020 && lookup_data_member(added_class, dm))
10021 {
10022 // So the data member 'dm' from the
10023 // 'deleted_class' class is also present in
10024 // the 'added_class' class so we assume that
10025 // 'deleted_class' and 'added_class' are the
10026 // same anonymous class that got changed.
10027 // Let's represent it using a diff node.
10028 diff_sptr d = compute_diff(is_type(deleted_class),
10029 is_type(added_class),
10030 ctxt);
10031 ABG_ASSERT(d->has_changes());
10032 string repr =
10034 /*internal=*/false);
10035 changed_unreachable_types_[repr]= d;
10036 this_class_got_changed = true;
10037 string r1 =
10039 /*internal=*/false);
10040 string r2 =
10042 /*internal=*/false);
10043 removed_anon_types_to_erase[r1] = deleted_class;
10044 added_anon_types_to_erase[r2] = added_class;
10045 break;
10046 }
10047 }
10048 if (this_class_got_changed)
10049 break;
10050 }
10051 }
10052 }
10053
10054 // Now remove the added/removed anonymous types from their maps,
10055 // as they are now represented as a changed type, not an added
10056 // and removed anonymous type.
10057 for (auto entry : added_anon_types_to_erase)
10058 added_unreachable_types_.erase(entry.first);
10059
10060 for (auto entry : removed_anon_types_to_erase)
10061 deleted_unreachable_types_.erase(entry.first);
10062 }
10063 }
10064}
10065
10066/// Test if a change reports about a given @ref function_decl that is
10067/// changed in a certain way is suppressed by a given suppression
10068/// specifiation
10069///
10070/// @param fn the @ref function_decl to consider.
10071///
10072/// @param suppr the suppression specification to consider.
10073///
10074/// @param k the kind of change that happened to @p fn.
10075///
10076/// @param ctxt the context of the current diff.
10077///
10078/// @return true iff the suppression specification @p suppr suppresses
10079/// change reports about function @p fn, if that function changes in
10080/// the way expressed by @p k.
10081static bool
10082function_is_suppressed(const function_decl* fn,
10083 const suppression_sptr suppr,
10085 const diff_context_sptr ctxt)
10086{
10088 if (!fn_suppr)
10089 return false;
10090 return fn_suppr->suppresses_function(fn, k, ctxt);
10091}
10092
10093/// Test if a change reports about a given @ref var_decl that is
10094/// changed in a certain way is suppressed by a given suppression
10095/// specifiation
10096///
10097/// @param fn the @ref var_decl to consider.
10098///
10099/// @param suppr the suppression specification to consider.
10100///
10101/// @param k the kind of change that happened to @p fn.
10102///
10103/// @param ctxt the context of the current diff.
10104///
10105/// @return true iff the suppression specification @p suppr suppresses
10106/// change reports about variable @p fn, if that variable changes in
10107/// the way expressed by @p k.
10108static bool
10109variable_is_suppressed(const var_decl* var,
10110 const suppression_sptr suppr,
10112 const diff_context_sptr ctxt)
10113{
10115 if (!var_suppr)
10116 return false;
10117 return var_suppr->suppresses_variable(var, k, ctxt);
10118}
10119
10120/// Apply suppression specifications for this corpus diff to the set
10121/// of added/removed functions/variables, as well as to types not
10122/// reachable from global functions/variables.
10123void
10125{
10126 diff_context_sptr ctxt = get_context();
10127
10128 const suppressions_type& suppressions = ctxt->suppressions();
10129 for (suppressions_type::const_iterator i = suppressions.begin();
10130 i != suppressions.end();
10131 ++i)
10132 {
10133 // Added/Deleted functions.
10135 {
10136 // Added functions
10137 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10138 e != added_fns_.end();
10139 ++e)
10140 if (function_is_suppressed(e->second, fn_suppr,
10142 ctxt))
10143 suppressed_added_fns_[e->first] = e->second;
10144
10145 // Deleted functions.
10146 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10147 e != deleted_fns_.end();
10148 ++e)
10149 if (function_is_suppressed(e->second, fn_suppr,
10151 ctxt))
10152 suppressed_deleted_fns_[e->first] = e->second;
10153
10154 // Added function symbols not referenced by any debug info
10155 for (string_elf_symbol_map::const_iterator e =
10156 added_unrefed_fn_syms_.begin();
10157 e != added_unrefed_fn_syms_.end();
10158 ++e)
10159 if (fn_suppr->suppresses_function_symbol(e->second,
10161 ctxt))
10162 suppressed_added_unrefed_fn_syms_[e->first] = e->second;
10163
10164 // Removed function symbols not referenced by any debug info
10165 for (string_elf_symbol_map::const_iterator e =
10166 deleted_unrefed_fn_syms_.begin();
10167 e != deleted_unrefed_fn_syms_.end();
10168 ++e)
10169 if (fn_suppr->suppresses_function_symbol(e->second,
10171 ctxt))
10172 suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
10173 }
10174 // Added/Delete virtual member functions changes that might be
10175 // suppressed by a type_suppression that matches the enclosing
10176 // class of the virtual member function.
10177 else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
10178 {
10179 // Added virtual functions
10180 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10181 e != added_fns_.end();
10182 ++e)
10183 if (is_member_function(e->second)
10184 && get_member_function_is_virtual(e->second))
10185 {
10186 const function_decl *f = e->second;
10187 class_decl_sptr c =
10188 is_class_type(is_method_type(f->get_type())->get_class_type());
10189 ABG_ASSERT(c);
10190 if (type_suppr->suppresses_type(c, ctxt))
10191 suppressed_added_fns_[e->first] = e->second;
10192 }
10193 // Deleted virtual functions
10194 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10195 e != deleted_fns_.end();
10196 ++e)
10197 if (is_member_function(e->second)
10198 && get_member_function_is_virtual(e->second))
10199 {
10200 const function_decl *f = e->second;
10201 class_decl_sptr c =
10202 is_class_type(is_method_type(f->get_type())->get_class_type());
10203 ABG_ASSERT(c);
10204 if (type_suppr->suppresses_type(c, ctxt))
10205 suppressed_deleted_fns_[e->first] = e->second;
10206 }
10207
10208 // Apply this type suppression to deleted types
10209 // non-reachable from a public interface.
10210 for (string_type_base_sptr_map::const_iterator e =
10211 deleted_unreachable_types_.begin();
10212 e != deleted_unreachable_types_.end();
10213 ++e)
10214 if (type_suppr->suppresses_type(e->second, ctxt))
10215 suppressed_deleted_unreachable_types_[e->first] = e->second;
10216
10217 // Apply this type suppression to added types
10218 // non-reachable from a public interface.
10219 for (string_type_base_sptr_map::const_iterator e =
10220 added_unreachable_types_.begin();
10221 e != added_unreachable_types_.end();
10222 ++e)
10223 if (type_suppr->suppresses_type(e->second, ctxt))
10224 suppressed_added_unreachable_types_[e->first] = e->second;
10225 }
10226 // Added/Deleted variables
10227 else if (variable_suppression_sptr var_suppr =
10229 {
10230 // Added variables
10231 for (string_var_ptr_map::const_iterator e = added_vars_.begin();
10232 e != added_vars_.end();
10233 ++e)
10234 if (variable_is_suppressed(e->second, var_suppr,
10236 ctxt))
10237 suppressed_added_vars_[e->first] = e->second;
10238
10239 //Deleted variables
10240 for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
10241 e != deleted_vars_.end();
10242 ++e)
10243 if (variable_is_suppressed(e->second, var_suppr,
10245 ctxt))
10246 suppressed_deleted_vars_[e->first] = e->second;
10247
10248 // Added variable symbols not referenced by any debug info
10249 for (string_elf_symbol_map::const_iterator e =
10250 added_unrefed_var_syms_.begin();
10251 e != added_unrefed_var_syms_.end();
10252 ++e)
10253 if (var_suppr->suppresses_variable_symbol(e->second,
10255 ctxt))
10256 suppressed_added_unrefed_var_syms_[e->first] = e->second;
10257
10258 // Removed variable symbols not referenced by any debug info
10259 for (string_elf_symbol_map::const_iterator e =
10260 deleted_unrefed_var_syms_.begin();
10261 e != deleted_unrefed_var_syms_.end();
10262 ++e)
10263 if (var_suppr->suppresses_variable_symbol(e->second,
10265 ctxt))
10266 suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
10267 }
10268 }
10269}
10270
10271/// Test if the change reports for a given deleted function have
10272/// been deleted.
10273///
10274/// @param fn the function to consider.
10275///
10276/// @return true iff the change reports for a give given deleted
10277/// function have been deleted.
10278bool
10280{
10281 if (!fn)
10282 return false;
10283
10284 string_function_ptr_map::const_iterator i =
10285 suppressed_deleted_fns_.find(fn->get_id());
10286
10287 return (i != suppressed_deleted_fns_.end());
10288}
10289
10290/// Test if an added type that is unreachable from public interface
10291/// has been suppressed by a suppression specification.
10292///
10293/// @param t the added unreachable type to be considered.
10294///
10295/// @return true iff @p t has been suppressed by a suppression
10296/// specification.
10297bool
10299{
10300 if (!t)
10301 return false;
10302
10303 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10304 string_type_base_sptr_map::const_iterator i =
10305 suppressed_added_unreachable_types_.find(repr);
10306 if (i == suppressed_added_unreachable_types_.end())
10307 return false;
10308
10309 return true;
10310}
10311
10312/// Test if a deleted type that is unreachable from public interface
10313/// has been suppressed by a suppression specification.
10314///
10315/// @param t the deleted unreachable type to be considered.
10316///
10317/// @return true iff @p t has been suppressed by a suppression
10318/// specification.
10319bool
10321{
10322 if (!t)
10323 return false;
10324
10325 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10326 string_type_base_sptr_map::const_iterator i =
10327 suppressed_deleted_unreachable_types_.find(repr);
10328 if (i == suppressed_deleted_unreachable_types_.end())
10329 return false;
10330
10331 return true;
10332}
10333
10334/// Test if the change reports for a give given added function has
10335/// been deleted.
10336///
10337/// @param fn the function to consider.
10338///
10339/// @return true iff the change reports for a give given added
10340/// function has been deleted.
10341bool
10343{
10344 if (!fn)
10345 return false;
10346
10347 string_function_ptr_map::const_iterator i =
10348 suppressed_added_fns_.find(fn->get_id());
10349
10350 return (i != suppressed_added_fns_.end());
10351}
10352
10353/// Test if the change reports for a give given deleted variable has
10354/// been deleted.
10355///
10356/// @param var the variable to consider.
10357///
10358/// @return true iff the change reports for a give given deleted
10359/// variable has been deleted.
10360bool
10362{
10363 if (!var)
10364 return false;
10365
10366 string_var_ptr_map::const_iterator i =
10367 suppressed_deleted_vars_.find(var->get_id());
10368
10369 return (i != suppressed_deleted_vars_.end());
10370}
10371
10372/// Test if the change reports for a given added variable have been
10373/// suppressed.
10374///
10375/// @param var the variable to consider.
10376///
10377/// @return true iff the change reports for a given deleted
10378/// variable has been deleted.
10379bool
10381{
10382 if (!var)
10383 return false;
10384
10385 string_var_ptr_map::const_iterator i =
10386 suppressed_added_vars_.find(var->get_id());
10387
10388 return (i != suppressed_added_vars_.end());
10389}
10390
10391/// Test if the change reports for a given deleted function symbol
10392/// (that is not referenced by any debug info) has been suppressed.
10393///
10394/// @param var the function to consider.
10395///
10396/// @return true iff the change reports for a given deleted function
10397/// symbol has been suppressed.
10398bool
10400{
10401 if (!s)
10402 return false;
10403
10404 string_elf_symbol_map::const_iterator i =
10405 suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10406
10407 return (i != suppressed_deleted_unrefed_fn_syms_.end());
10408}
10409
10410/// Test if the change reports for a given added function symbol
10411/// (that is not referenced by any debug info) has been suppressed.
10412///
10413/// @param var the function to consider.
10414///
10415/// @return true iff the change reports for a given added function
10416/// symbol has been suppressed.
10417bool
10419{
10420 if (!s)
10421 return false;
10422
10423 string_elf_symbol_map::const_iterator i =
10424 suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10425
10426 return (i != suppressed_added_unrefed_fn_syms_.end());
10427}
10428
10429/// Test if the change reports for a given deleted variable symbol
10430/// (that is not referenced by any debug info) has been suppressed.
10431///
10432/// @param var the variable to consider.
10433///
10434/// @return true iff the change reports for a given deleted variable
10435/// symbol has been suppressed.
10436bool
10438{
10439 if (!s)
10440 return false;
10441
10442 string_elf_symbol_map::const_iterator i =
10443 suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10444
10445 return (i != suppressed_deleted_unrefed_var_syms_.end());
10446}
10447
10448/// Test if the change reports for a given added variable symbol
10449/// (that is not referenced by any debug info) has been suppressed.
10450///
10451/// @param var the variable to consider.
10452///
10453/// @return true iff the change reports for a given added variable
10454/// symbol has been suppressed.
10455bool
10457{
10458 if (!s)
10459 return false;
10460
10461 string_elf_symbol_map::const_iterator i =
10462 suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10463
10464 return (i != suppressed_added_unrefed_var_syms_.end());
10465}
10466
10467#ifdef do_count_diff_map_changes
10468#undef do_count_diff_map_changes
10469#endif
10470#define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10471 { \
10472 string_diff_ptr_map::const_iterator i; \
10473 for (i = diff_map.begin(); \
10474 i != diff_map.end(); \
10475 ++i) \
10476 { \
10477 if (const var_diff* d = is_var_diff(i->second)) \
10478 if (is_data_member(d->first_var())) \
10479 continue; \
10480 \
10481 if (i->second->has_local_changes()) \
10482 ++n_changes; \
10483 if (!i->second->get_canonical_diff()->to_be_reported()) \
10484 ++n_filtered; \
10485 } \
10486 }
10487
10488/// Count the number of leaf changes as well as the number of the
10489/// changes that have been filtered out.
10490///
10491/// @param num_changes out parameter. This is set to the total number
10492/// of leaf changes.
10493///
10494/// @param num_filtered out parameter. This is set to the number of
10495/// leaf changes that have been filtered out.
10496void
10497corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10498{
10499 count_leaf_type_changes(num_changes, num_filtered);
10500
10501 // Now count the non-type changes.
10502 do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10503 num_changes, num_filtered);
10504 do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10505 num_changes, num_filtered);
10506}
10507
10508/// Count the number of leaf *type* changes as well as the number of
10509/// the leaf type changes that have been filtered out.
10510///
10511/// @param num_changes out parameter. This is set to the total number
10512/// of leaf type changes.
10513///
10514/// @param num_filtered out parameter. This is set to the number of
10515/// leaf type changes that have been filtered out.
10516void
10518 size_t &num_filtered)
10519{
10520 do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10521 num_changes, num_filtered);
10522 do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10523 num_changes, num_filtered);
10524 do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10525 num_changes, num_filtered);
10526 do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10527 num_changes, num_filtered);
10528 do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10529 num_changes, num_filtered);
10530 do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10531 num_changes, num_filtered);
10532 do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10533 num_changes, num_filtered);
10534 do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10535 num_changes, num_filtered);
10536 do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10537 num_changes, num_filtered);
10538}
10539
10540/// Count the number of types not reachable from the interface (i.e,
10541/// not reachable from global functions or variables).
10542///
10543/// @param num_added this is set to the number of added types not
10544/// reachable from the interface.
10545///
10546/// @param num_deleted this is set to the number of deleted types not
10547/// reachable from the interface.
10548///
10549/// @param num_changed this is set to the number of changed types not
10550/// reachable from the interface.
10551///
10552/// @param num_filtered_added this is set to the number of added types
10553/// not reachable from the interface and that have been filtered out
10554/// by suppression specifications.
10555///
10556/// @param num_filtered_deleted this is set to the number of deleted
10557/// types not reachable from the interface and that have been filtered
10558/// out by suppression specifications.
10559///
10560/// @param num_filtered_changed this is set to the number of changed
10561/// types not reachable from the interface and that have been filtered
10562/// out by suppression specifications.
10563void
10565 size_t &num_deleted,
10566 size_t &num_changed,
10567 size_t &num_filtered_added,
10568 size_t &num_filtered_deleted,
10569 size_t &num_filtered_changed)
10570{
10571 num_added = added_unreachable_types_.size();
10572 num_deleted = deleted_unreachable_types_.size();
10573 num_changed = changed_unreachable_types_.size();
10574 num_filtered_added = suppressed_added_unreachable_types_.size();
10575 num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10576
10577 for (vector<diff_sptr>::const_iterator i =
10580 ++i)
10581 if (!(*i)->to_be_reported())
10582 ++num_filtered_changed;
10583}
10584
10585/// Get the map of diff nodes representing changed unreachable types.
10586///
10587/// @return the map of diff nodes representing changed unreachable
10588/// types.
10591{return changed_unreachable_types_;}
10592
10593/// Get the sorted vector of diff nodes representing changed
10594/// unreachable types.
10595///
10596/// Upon the first invocation of this method, if the vector is empty,
10597/// this function gets the diff nodes representing changed
10598/// unreachable, sort them, and return the sorted vector.
10599///
10600/// @return the sorted vector of diff nodes representing changed
10601/// unreachable types.
10602const vector<diff_sptr>&
10604{
10605if (changed_unreachable_types_sorted_.empty())
10606 if (!changed_unreachable_types_.empty())
10607 sort_string_diff_sptr_map(changed_unreachable_types_,
10608 changed_unreachable_types_sorted_);
10609
10610 return changed_unreachable_types_sorted_;
10611}
10612
10613/// Compute the diff stats.
10614///
10615/// To know the number of functions that got filtered out, this
10616/// function applies the categorizing filters to the diff sub-trees of
10617/// each function changes diff, prior to calculating the stats.
10618///
10619/// @param num_removed the number of removed functions.
10620///
10621/// @param num_added the number of added functions.
10622///
10623/// @param num_changed the number of changed functions.
10624///
10625/// @param num_filtered_out the number of changed functions that are
10626/// got filtered out from the report
10627void
10629{
10630 stat.num_func_removed(deleted_fns_.size());
10631 stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
10632 stat.num_func_added(added_fns_.size());
10633 stat.num_added_func_filtered_out(suppressed_added_fns_.size());
10634 stat.num_func_changed(changed_fns_map_.size());
10635
10636 stat.num_vars_removed(deleted_vars_.size());
10637 stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
10638 stat.num_vars_added(added_vars_.size());
10639 stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
10640 stat.num_vars_changed(changed_vars_map_.size());
10641
10642 diff_context_sptr ctxt = get_context();
10643
10645 if (ctxt->perform_change_categorization())
10646 {
10647 if (get_context()->do_log())
10648 {
10649 std::cerr << "in apply_filters_and_compute_diff_stats:"
10650 << "applying filters to "
10651 << changed_fns_.size()
10652 << " changed fns ...\n";
10653 t.start();
10654 }
10655 // Walk the changed function diff nodes to apply the categorization
10656 // filters.
10658 for (function_decl_diff_sptrs_type::const_iterator i =
10659 changed_fns_.begin();
10660 i != changed_fns_.end();
10661 ++i)
10662 {
10663 diff_sptr diff = *i;
10664 ctxt->maybe_apply_filters(diff);
10665 }
10666
10667 if (get_context()->do_log())
10668 {
10669 t.stop();
10670 std::cerr << "in apply_filters_and_compute_diff_stats:"
10671 << "filters to changed fn applied!:" << t << "\n";
10672
10673 std::cerr << "in apply_filters_and_compute_diff_stats:"
10674 << "applying filters to "
10675 << sorted_changed_vars_.size()
10676 << " changed vars ...\n";
10677 t.start();
10678 }
10679
10680 // Walk the changed variable diff nodes to apply the categorization
10681 // filters.
10682 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10683 i != sorted_changed_vars_.end();
10684 ++i)
10685 {
10686 diff_sptr diff = *i;
10687 ctxt->maybe_apply_filters(diff);
10688 }
10689
10690 if (get_context()->do_log())
10691 {
10692 t.stop();
10693 std::cerr << "in apply_filters_and_compute_diff_stats:"
10694 << "filters to changed vars applied!:" << t << "\n";
10695
10696 std::cerr << "in apply_filters_and_compute_diff_stats:"
10697 << "applying filters to unreachable types ...\n";
10698 t.start();
10699 }
10700
10701 // walk the changed unreachable types to apply categorization
10702 // filters
10704 ctxt->maybe_apply_filters(diff);
10705
10706 for (auto& entry : changed_unreachable_types())
10707 ctxt->maybe_apply_filters(entry.second);
10708
10709 if (get_context()->do_log())
10710 {
10711 t.stop();
10712 std::cerr << "in apply_filters_and_compute_diff_stats:"
10713 << "filters to unreachable types applied!:" << t << "\n";
10714
10715 std::cerr << "in apply_filters_and_compute_diff_stats:"
10716 << "categorizing redundant changed sub nodes ...\n";
10717 t.start();
10718 }
10719
10720 categorize_redundant_changed_sub_nodes();
10721
10722 if (get_context()->do_log())
10723 {
10724 t.stop();
10725 std::cerr << "in apply_filters_and_compute_diff_stats:"
10726 << "redundant changed sub nodes categorized!:" << t << "\n";
10727
10728 std::cerr << "in apply_filters_and_compute_diff_stats:"
10729 << "count changed fns ...\n";
10730 t.start();
10731 }
10732 }
10733
10734 // Walk the changed function diff nodes to count the number of
10735 // filtered-out functions and the number of functions with virtual
10736 // offset changes.
10737 for (function_decl_diff_sptrs_type::const_iterator i =
10738 changed_fns_.begin();
10739 i != changed_fns_.end();
10740 ++i)
10741 {
10742 if ((*i)->is_filtered_out())
10743 {
10745 (stat.num_changed_func_filtered_out() + 1);
10746
10747 if ((*i)->has_local_changes())
10750 }
10751 else
10752 {
10753 if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
10756 }
10757
10758 if ((*i)->has_local_changes())
10760 (stat.num_leaf_func_changes() + 1);
10761 }
10762
10763 if (get_context()->do_log())
10764 {
10765 t.stop();
10766 std::cerr << "in apply_filters_and_compute_diff_stats:"
10767 << "changed fn counted!:" << t << "\n";
10768
10769 std::cerr << "in apply_filters_and_compute_diff_stats:"
10770 << "count changed vars ...\n";
10771 t.start();
10772 }
10773
10774 // Walk the changed variables diff nodes to count the number of
10775 // filtered-out variables.
10776 for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
10777 i != sorted_changed_vars_.end();
10778 ++i)
10779 {
10780 if ((*i)->is_filtered_out())
10781 {
10783 (stat.num_changed_vars_filtered_out() + 1);
10784
10785 if ((*i)->has_local_changes())
10788 }
10789 if ((*i)->has_local_changes())
10791 (stat.num_leaf_var_changes() + 1);
10792 }
10793
10794 if (get_context()->do_log())
10795 {
10796 t.stop();
10797 std::cerr << "in apply_filters_and_compute_diff_stats:"
10798 << "changed vars counted!:" << t << "\n";
10799
10800 std::cerr << "in apply_filters_and_compute_diff_stats:"
10801 << "count leaf changed types ...\n";
10802 t.start();
10803 }
10804
10805 stat.num_func_syms_added(added_unrefed_fn_syms_.size());
10806 stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
10807 stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
10808 stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
10809 stat.num_var_syms_added(added_unrefed_var_syms_.size());
10810 stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
10811 stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
10812 stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
10813
10814 // Walk the general leaf type diff nodes to count them
10815 {
10816 size_t num_type_changes = 0, num_type_filtered = 0;
10817 count_leaf_type_changes(num_type_changes, num_type_filtered);
10818
10819 stat.num_leaf_type_changes(num_type_changes);
10820 stat.num_leaf_type_changes_filtered_out(num_type_filtered);
10821 }
10822
10823 if (get_context()->do_log())
10824 {
10825 t.stop();
10826 std::cerr << "in apply_filters_and_compute_diff_stats:"
10827 << "changed leaf types counted!:" << t << "\n";
10828
10829 std::cerr << "in apply_filters_and_compute_diff_stats:"
10830 << "count leaf changed artefacts ...\n";
10831 t.start();
10832 }
10833
10834 // Walk the general leaf artefacts diff nodes to count them
10835 {
10836 size_t num_changes = 0, num_filtered = 0;
10837 count_leaf_changes(num_changes, num_filtered);
10838
10839 stat.num_leaf_changes(num_changes);
10840 stat.num_leaf_changes_filtered_out(num_filtered);
10841 }
10842
10843 if (get_context()->do_log())
10844 {
10845 t.stop();
10846 std::cerr << "in apply_filters_and_compute_diff_stats:"
10847 << "changed leaf artefacts counted!:" << t << "\n";
10848
10849 std::cerr << "in apply_filters_and_compute_diff_stats:"
10850 << "count unreachable types ...\n";
10851 t.start();
10852 }
10853
10854 // Walk the unreachable types to count them
10855 {
10856 size_t num_added_unreachable_types = 0,
10857 num_changed_unreachable_types = 0,
10858 num_deleted_unreachable_types = 0,
10859 num_added_unreachable_types_filtered = 0,
10860 num_changed_unreachable_types_filtered = 0,
10861 num_deleted_unreachable_types_filtered = 0;
10862
10863 count_unreachable_types(num_added_unreachable_types,
10864 num_deleted_unreachable_types,
10865 num_changed_unreachable_types,
10866 num_added_unreachable_types_filtered,
10867 num_deleted_unreachable_types_filtered,
10868 num_changed_unreachable_types_filtered);
10869
10870 if (get_context()->do_log())
10871 {
10872 t.stop();
10873 std::cerr << "in apply_filters_and_compute_diff_stats:"
10874 << "unreachable types counted!:" << t << "\n";
10875 }
10876
10877 stat.num_added_unreachable_types(num_added_unreachable_types);
10878 stat.num_removed_unreachable_types(num_deleted_unreachable_types);
10879 stat.num_changed_unreachable_types(num_changed_unreachable_types);
10881 (num_added_unreachable_types_filtered);
10883 (num_deleted_unreachable_types_filtered);
10885 (num_changed_unreachable_types_filtered);
10886 }
10887}
10888
10889/// Emit the summary of the functions & variables that got
10890/// removed/changed/added.
10891///
10892/// TODO: This should be handled by the reporters, just like what is
10893/// done for reporter_base::diff_to_be_reported.
10894///
10895/// @param out the output stream to emit the stats to.
10896///
10897/// @param indent the indentation string to use in the summary.
10898void
10900 ostream& out,
10901 const string& indent)
10902{
10903 /// Report added/removed/changed functions.
10904 size_t net_num_leaf_changes =
10906 s.net_num_func_added() +
10909 s.net_num_vars_added() +
10916
10917 if (!sonames_equal_)
10918 out << indent << "ELF SONAME changed\n";
10919
10920 if (!architectures_equal_)
10921 out << indent << "ELF architecture changed\n";
10922
10923 diff_context_sptr ctxt = get_context();
10924
10925 if (ctxt->show_leaf_changes_only())
10926 {
10927 out << "Leaf changes summary: ";
10928 out << net_num_leaf_changes << " artifact";
10929 if (net_num_leaf_changes > 1)
10930 out << "s";
10931 out << " changed";
10932
10933 if (size_t num_filtered = s.num_leaf_changes_filtered_out())
10934 out << " (" << num_filtered << " filtered out)";
10935 out << "\n";
10936
10937 out << indent << "Changed leaf types summary: "
10940 out << " (" << s.num_leaf_type_changes_filtered_out()
10941 << " filtered out)";
10942 out << " leaf type";
10943 if (s.num_leaf_type_changes() > 1)
10944 out << "s";
10945 out << " changed\n";
10946
10947 // function changes summary
10948 out << indent << "Removed/Changed/Added functions summary: ";
10949 out << s.net_num_func_removed() << " Removed";
10951 out << " ("
10953 << " filtered out)";
10954 out << ", ";
10955
10956 out << s.net_num_leaf_func_changes() << " Changed";
10958 out << " ("
10960 << " filtered out)";
10961 out << ", ";
10962
10963 out << s.net_num_func_added()<< " Added ";
10964 if (s.net_num_func_added() <= 1)
10965 out << "function";
10966 else
10967 out << "functions";
10969 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10970 out << "\n";
10971
10972 // variables changes summary
10973 out << indent << "Removed/Changed/Added variables summary: ";
10974 out << s.net_num_vars_removed() << " Removed";
10976 out << " (" << s.num_removed_vars_filtered_out()
10977 << " filtered out)";
10978 out << ", ";
10979
10980 out << s.net_num_leaf_var_changes() << " Changed";
10982 out << " ("
10984 << " filtered out)";
10985 out << ", ";
10986
10987 out << s.net_num_vars_added() << " Added ";
10988 if (s.net_num_vars_added() <= 1)
10989 out << "variable";
10990 else
10991 out << "variables";
10993 out << " (" << s.num_added_vars_filtered_out()
10994 << " filtered out)";
10995 out << "\n";
10996 }
10997 else // if (ctxt->show_leaf_changes_only())
10998 {
10999 size_t total_nb_function_changes = s.num_func_removed()
11000 + s.num_func_changed() + s.num_func_added();
11001
11002 // function changes summary
11003 out << indent << "Functions changes summary: ";
11004 out << s.net_num_func_removed() << " Removed";
11006 out << " ("
11008 << " filtered out)";
11009 out << ", ";
11010
11011 out << s.net_num_func_changed() << " Changed";
11013 out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
11014 out << ", ";
11015
11016 out << s.net_num_func_added() << " Added";
11018 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11019 if (total_nb_function_changes <= 1)
11020 out << " function";
11021 else
11022 out << " functions";
11023 out << "\n";
11024
11025 // variables changes summary
11026 size_t total_nb_variable_changes = s.num_vars_removed()
11027 + s.num_vars_changed() + s.num_vars_added();
11028
11029 out << indent << "Variables changes summary: ";
11030 out << s.net_num_vars_removed() << " Removed";
11032 out << " (" << s.num_removed_vars_filtered_out()
11033 << " filtered out)";
11034 out << ", ";
11035
11036 out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
11038 out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
11039 out << ", ";
11040
11041 out << s.net_num_vars_added() << " Added";
11043 out << " (" << s.num_added_vars_filtered_out()
11044 << " filtered out)";
11045 if (total_nb_variable_changes <= 1)
11046 out << " variable";
11047 else
11048 out << " variables";
11049 out << "\n";
11050 }
11051
11052 // Show statistics about types not reachable from global
11053 // functions/variables.
11054 if (ctxt->show_unreachable_types())
11055 {
11056 size_t total_nb_unreachable_type_changes =
11060
11061 // Show summary of unreachable types
11062 out << indent << "Unreachable types summary: "
11064 << " removed";
11067 << " filtered out)";
11068 out << ", ";
11069
11071 << " changed";
11074 << " filtered out)";
11075 out << ", ";
11076
11078 << " added";
11081 << " filtered out)";
11082 if (total_nb_unreachable_type_changes <= 1)
11083 out << " type";
11084 else
11085 out << " types";
11086 out << "\n";
11087 }
11088
11089 if (ctxt->show_symbols_unreferenced_by_debug_info()
11090 && (s.num_func_syms_removed()
11091 || s.num_func_syms_added()
11093 || s.num_var_syms_added()))
11094 {
11095 // function symbols changes summary.
11096
11097 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11098 && s.num_func_syms_removed() == 0
11099 && s.num_func_syms_added() != 0)
11100 // If the only unreferenced function symbol change is function
11101 // syms that got added, but we were forbidden to show function
11102 // syms being added, do nothing.
11103 ;
11104 else
11105 {
11106 out << indent
11107 << "Function symbols changes summary: "
11108 << s.net_num_removed_func_syms() << " Removed";
11110 out << " (" << s.num_removed_func_syms_filtered_out()
11111 << " filtered out)";
11112 out << ", ";
11113 out << s.net_num_added_func_syms() << " Added";
11115 out << " (" << s.num_added_func_syms_filtered_out()
11116 << " filtered out)";
11117 out << " function symbol";
11119 out << "s";
11120 out << " not referenced by debug info\n";
11121 }
11122
11123 // variable symbol changes summary.
11124
11125 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11126 && s.num_var_syms_removed() == 0
11127 && s.num_var_syms_added() != 0)
11128 // If the only unreferenced variable symbol change is variable
11129 // syms that got added, but we were forbidden to show variable
11130 // syms being added, do nothing.
11131 ;
11132 else
11133 {
11134 out << indent
11135 << "Variable symbols changes summary: "
11136 << s.net_num_removed_var_syms() << " Removed";
11138 out << " (" << s.num_removed_var_syms_filtered_out()
11139 << " filtered out)";
11140 out << ", ";
11141 out << s.net_num_added_var_syms() << " Added";
11143 out << " (" << s.num_added_var_syms_filtered_out()
11144 << " filtered out)";
11145 out << " variable symbol";
11146 if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
11147 out << "s";
11148 out << " not referenced by debug info\n";
11149 }
11150 }
11151}
11152
11153/// Walk the changed functions and variables diff nodes to categorize
11154/// redundant nodes.
11155void
11157{
11159
11160 diff_context_sptr ctxt = get_context();
11161
11162 ctxt->forget_visited_diffs();
11163 for (function_decl_diff_sptrs_type::const_iterator i =
11164 changed_fns_.begin();
11165 i!= changed_fns_.end();
11166 ++i)
11167 {
11168 diff = *i;
11170 }
11171
11172 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11173 i!= sorted_changed_vars_.end();
11174 ++i)
11175 {
11176 diff_sptr diff = *i;
11178 }
11179
11180 for (diff_sptrs_type::const_iterator i =
11183 ++i)
11184 {
11185 diff_sptr diff = *i;
11187 }
11188}
11189
11190/// Walk the changed functions and variables diff nodes and clear the
11191/// redundancy categorization they might carry.
11192void
11194{
11196 for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
11197 i!= changed_fns_.end();
11198 ++i)
11199 {
11200 diff = *i;
11202 }
11203
11204 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11205 i!= sorted_changed_vars_.end();
11206 ++i)
11207 {
11208 diff = *i;
11210 }
11211}
11212
11213/// If the user asked to dump the diff tree node (for changed
11214/// variables and functions) on the error output stream, then just do
11215/// that.
11216///
11217/// This function is used for debugging purposes.
11218void
11220{
11221 diff_context_sptr ctxt = get_context();
11222
11223 if (!ctxt->dump_diff_tree()
11224 || ctxt->error_output_stream() == 0)
11225 return;
11226
11227 if (!changed_fns_.empty())
11228 {
11229 *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
11230 for (function_decl_diff_sptrs_type::const_iterator i =
11231 changed_fns_.begin();
11232 i != changed_fns_.end();
11233 ++i)
11234 {
11235 diff_sptr d = *i;
11236 print_diff_tree(d, *ctxt->error_output_stream());
11237 }
11238 }
11239
11240 if (!sorted_changed_vars_.empty())
11241 {
11242 *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
11243 for (var_diff_sptrs_type::const_iterator i =
11244 sorted_changed_vars_.begin();
11245 i != sorted_changed_vars_.end();
11246 ++i)
11247 {
11248 diff_sptr d = *i;
11249 print_diff_tree(d, *ctxt->error_output_stream());
11250 }
11251 }
11252
11253 if (!changed_unreachable_types_sorted().empty())
11254 {
11255 *ctxt->error_output_stream() << "\nchanged unreachable "
11256 "types diff tree: \n\n";
11257 for (vector<diff_sptr>::const_iterator i =
11260 ++i)
11261 {
11262 diff_sptr d = *i;
11263 print_diff_tree(d, *ctxt->error_output_stream());
11264 }
11265 }
11266}
11267
11268/// Populate the vector of children node of the @ref corpus_diff type.
11269///
11270/// The children node can then later be retrieved using
11271/// corpus_diff::children_node().
11272void
11274{
11275 for (function_decl_diff_sptrs_type::const_iterator i =
11276 changed_functions_sorted().begin();
11277 i != changed_functions_sorted().end();
11278 ++i)
11279 if (diff_sptr d = *i)
11281}
11282
11283/// Constructor for @ref corpus_diff.
11284///
11285/// @param first the first corpus of the diff.
11286///
11287/// @param second the second corpus of the diff.
11288///
11289/// @param ctxt the diff context to use. Note that this context
11290/// object must stay alive at least during the life time of the
11291/// current instance of @ref corpus_diff. Otherwise memory corruption
11292/// issues occur.
11294 corpus_sptr second,
11295 diff_context_sptr ctxt)
11296 : priv_(new priv(first, second, ctxt))
11297{}
11298
11299corpus_diff::~corpus_diff() = default;
11300
11301/// Finish building the current instance of @ref corpus_diff.
11302void
11304{
11305 if (priv_->finished_)
11306 return;
11308 priv_->finished_ = true;
11309}
11310
11311/// Test if logging was requested.
11312///
11313/// @return true iff logging was requested.
11314bool
11316{return context()->do_log();}
11317
11318/// Request logging, or not.
11319///
11320/// @param f true iff logging is requested.
11321void
11323{context()->do_log(f);}
11324
11325/// @return the first corpus of the diff.
11326corpus_sptr
11328{return priv_->first_;}
11329
11330/// @return the second corpus of the diff.
11331corpus_sptr
11333{return priv_->second_;}
11334
11335/// @return the children nodes of the current instance of corpus_diff.
11336const vector<diff*>&
11338{return priv_->children_;}
11339
11340/// Append a new child node to the vector of children nodes for the
11341/// current instance of @ref corpus_diff node.
11342///
11343/// Note that the vector of children nodes for the current instance of
11344/// @ref corpus_diff node must remain sorted, using
11345/// diff_less_than_functor.
11346///
11347/// @param d the new child node. Note that the life time of the
11348/// object held by @p d will thus equal the life time of the current
11349/// instance of @ref corpus_diff.
11350void
11352{
11353 ABG_ASSERT(d);
11354
11356 bool inserted = false;
11357 for (vector<diff*>::iterator i = priv_->children_.begin();
11358 i != priv_->children_.end();
11359 ++i)
11360 // Look for the point where to insert the diff child node.
11361 if (!is_less_than(d.get(), *i))
11362 {
11363 context()->keep_diff_alive(d);
11364 priv_->children_.insert(i, d.get());
11365 // As we have just inserted 'd' into the vector, the iterator
11366 // 'i' is invalidated. We must *NOT* use it anymore.
11367 inserted = true;
11368 break;
11369 }
11370
11371 if (!inserted)
11372 {
11373 context()->keep_diff_alive(d);
11374 // We didn't insert anything to the vector, presumably b/c it was
11375 // empty or had one element that was "less than" 'd'. We can thus
11376 // just append 'd' to the end of the vector.
11377 priv_->children_.push_back(d.get());
11378 }
11379}
11380
11381/// @return the bare edit script of the functions changed as recorded
11382/// by the diff.
11385{return priv_->fns_edit_script_;}
11386
11387/// @return the bare edit script of the variables changed as recorded
11388/// by the diff.
11391{return priv_->vars_edit_script_;}
11392
11393/// Test if the soname of the underlying corpus has changed.
11394///
11395/// @return true iff the soname has changed.
11396bool
11398{return !priv_->sonames_equal_;}
11399
11400/// Test if the architecture of the underlying corpus has changed.
11401///
11402/// @return true iff the architecture has changed.
11403bool
11405{return !priv_->architectures_equal_;}
11406
11407/// Getter for the deleted functions of the diff.
11408///
11409/// @return the the deleted functions of the diff.
11412{return priv_->deleted_fns_;}
11413
11414/// Getter for the added functions of the diff.
11415///
11416/// @return the added functions of the diff.
11419{return priv_->added_fns_;}
11420
11421/// Getter for the functions which signature didn't change, but which
11422/// do have some indirect changes in their parms.
11423///
11424/// @return a non-sorted map of functions which signature didn't
11425/// change, but which do have some indirect changes in their parms.
11426/// The key of the map is a unique identifier for the function; it's
11427/// usually made of the name and version of the underlying ELF symbol
11428/// of the function for corpora that were built from ELF files.
11431{return priv_->changed_fns_map_;}
11432
11433/// Getter for a sorted vector of functions which signature didn't
11434/// change, but which do have some indirect changes in their parms.
11435///
11436/// @return a sorted vector of functions which signature didn't
11437/// change, but which do have some indirect changes in their parms.
11440{return priv_->changed_fns_;}
11441
11442/// Getter for the variables that got deleted from the first subject
11443/// of the diff.
11444///
11445/// @return the map of deleted variable.
11446const string_var_ptr_map&
11448{return priv_->deleted_vars_;}
11449
11450/// Getter for the added variables of the diff.
11451///
11452/// @return the map of added variable.
11453const string_var_ptr_map&
11455{return priv_->added_vars_;}
11456
11457/// Getter for the non-sorted map of variables which signature didn't
11458/// change but which do have some indirect changes in some sub-types.
11459///
11460/// @return the non-sorted map of changed variables.
11463{return priv_->changed_vars_map_;}
11464
11465/// Getter for the sorted vector of variables which signature didn't
11466/// change but which do have some indirect changes in some sub-types.
11467///
11468/// @return a sorted vector of changed variables.
11471{return priv_->sorted_changed_vars_;}
11472
11473/// Getter for function symbols not referenced by any debug info and
11474/// that got deleted.
11475///
11476/// @return a map of elf function symbols not referenced by any debug
11477/// info and that got deleted.
11480{return priv_->deleted_unrefed_fn_syms_;}
11481
11482/// Getter for function symbols not referenced by any debug info and
11483/// that got added.
11484///
11485/// @return a map of elf function symbols not referenced by any debug
11486/// info and that got added.
11489{return priv_->added_unrefed_fn_syms_;}
11490
11491/// Getter for variable symbols not referenced by any debug info and
11492/// that got deleted.
11493///
11494/// @return a map of elf variable symbols not referenced by any debug
11495/// info and that got deleted.
11498{return priv_->deleted_unrefed_var_syms_;}
11499
11500/// Getter for variable symbols not referenced by any debug info and
11501/// that got added.
11502///
11503/// @return a map of elf variable symbols not referenced by any debug
11504/// info and that got added.
11507{return priv_->added_unrefed_var_syms_;}
11508
11509/// Getter for a map of deleted types that are not reachable from
11510/// global functions/variables.
11511///
11512/// @return a map that associates pretty representation of deleted
11513/// unreachable types and said types.
11516{return priv_->deleted_unreachable_types_;}
11517
11518/// Getter of a sorted vector of deleted types that are not reachable
11519/// from global functions/variables.
11520///
11521/// @return a sorted vector of deleted types that are not reachable
11522/// from global functions/variables. The types are lexicographically
11523/// sorted by considering their pretty representation.
11524const vector<type_base_sptr>&
11526{
11527 if (priv_->deleted_unreachable_types_sorted_.empty())
11528 if (!priv_->deleted_unreachable_types_.empty())
11529 sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
11530 priv_->deleted_unreachable_types_sorted_);
11531
11532 return priv_->deleted_unreachable_types_sorted_;
11533}
11534
11535/// Getter for a map of added types that are not reachable from global
11536/// functions/variables.
11537///
11538/// @return a map that associates pretty representation of added
11539/// unreachable types and said types.
11542{return priv_->added_unreachable_types_;}
11543
11544/// Getter of a sorted vector of added types that are not reachable
11545/// from global functions/variables.
11546///
11547/// @return a sorted vector of added types that are not reachable from
11548/// global functions/variables. The types are lexicographically
11549/// sorted by considering their pretty representation.
11550const vector<type_base_sptr>&
11552{
11553 if (priv_->added_unreachable_types_sorted_.empty())
11554 if (!priv_->added_unreachable_types_.empty())
11555 sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
11556 priv_->added_unreachable_types_sorted_);
11557
11558 return priv_->added_unreachable_types_sorted_;
11559}
11560
11561/// Getter for a map of changed types that are not reachable from
11562/// global functions/variables.
11563///
11564/// @return a map that associates pretty representation of changed
11565/// unreachable types and said types.
11568{return priv_->changed_unreachable_types_;}
11569
11570/// Getter of a sorted vector of changed types that are not reachable
11571/// from global functions/variables.
11572///
11573/// @return a sorted vector of changed types that are not reachable
11574/// from global functions/variables. The diffs are lexicographically
11575/// sorted by considering their pretty representation.
11576const vector<diff_sptr>&
11578{return priv_->changed_unreachable_types_sorted();}
11579
11580/// Getter of the diff context of this diff
11581///
11582/// @return the diff context for this diff.
11585{return priv_->get_context();}
11586
11587/// @return the pretty representation for the current instance of @ref
11588/// corpus_diff
11589const string&
11591{
11592 if (priv_->pretty_representation_.empty())
11593 {
11594 std::ostringstream o;
11595 o << "corpus_diff["
11596 << first_corpus()->get_path()
11597 << ", "
11598 << second_corpus()->get_path()
11599 << "]";
11600 priv_->pretty_representation_ = o.str();
11601 }
11602 return priv_->pretty_representation_;
11603}
11604/// Return true iff the current @ref corpus_diff node carries a
11605/// change.
11606///
11607/// @return true iff the current diff node carries a change.
11608bool
11610{
11611 return (soname_changed()
11613 || !(priv_->deleted_fns_.empty()
11614 && priv_->added_fns_.empty()
11615 && priv_->changed_fns_map_.empty()
11616 && priv_->deleted_vars_.empty()
11617 && priv_->added_vars_.empty()
11618 && priv_->changed_vars_map_.empty()
11619 && priv_->added_unrefed_fn_syms_.empty()
11620 && priv_->deleted_unrefed_fn_syms_.empty()
11621 && priv_->added_unrefed_var_syms_.empty()
11622 && priv_->deleted_unrefed_var_syms_.empty()
11623 && priv_->deleted_unreachable_types_.empty()
11624 && priv_->added_unreachable_types_.empty()
11625 && priv_->changed_unreachable_types_.empty()));
11626}
11627
11628/// Test if the current instance of @ref corpus_diff carries changes
11629/// that we are sure are incompatible. By incompatible change we mean
11630/// a change that "breaks" the ABI of the corpus we are looking at.
11631///
11632/// In concrete terms, this function considers the following changes
11633/// as being ABI incompatible for sure:
11634///
11635/// - a soname change
11636/// - if exported functions or variables got removed
11637///
11638/// Note that subtype changes *can* represent changes that break ABI
11639/// too. But they also can be changes that are OK, ABI-wise.
11640///
11641/// It's up to the user to provide suppression specifications to say
11642/// explicitely which subtype change is OK. The remaining sub-type
11643/// changes are then considered to be ABI incompatible. But to test
11644/// if such ABI incompatible subtype changes are present you need to
11645/// use the function @ref corpus_diff::has_net_subtype_changes()
11646///
11647/// @return true iff the current instance of @ref corpus_diff carries
11648/// changes that we are sure are ABI incompatible.
11649bool
11651{
11652 const diff_stats& stats = const_cast<corpus_diff*>(this)->
11654
11657 || stats.net_num_func_removed() != 0
11659 // If all reports about functions with sub-type changes
11660 // have been suppressed, then even those about functions
11661 // that are virtual don't matter anymore because the
11662 // user willingly requested to shut them down
11663 && stats.net_num_func_changed() != 0)
11664 || stats.net_num_vars_removed() != 0
11665 || stats.net_num_removed_func_syms() != 0
11666 || stats.net_num_removed_var_syms() != 0
11667 || stats.net_num_removed_unreachable_types() != 0);
11668
11669 // If stats.net_num_changed_unreachable_types() != 0 then walk the
11670 // corpus_diff::priv::changed_unreachable_types_, and see if there
11671 // is one that is harmful by bitwise and-ing their category with
11672 // abigail::comparison::get_default_harmful_categories_bitmap().
11675 {
11676 // The changed unreachable types can carry harmful changes.
11677 // Let's figure if they actually do.
11678
11679 diff_context_sptr ctxt = context();
11680 for (auto &entry : priv_->changed_unreachable_types())
11681 {
11682 diff_sptr dif = entry.second;
11683
11684 // Let's see if any of the categories of this diff node
11685 // belong to the "harmful" ones.
11686 if (dif->get_category() & get_default_harmful_categories_bitmap())
11687 {
11689 break;
11690 }
11691 }
11692 }
11693
11695}
11696
11697/// Test if the current instance of @ref corpus_diff carries subtype
11698/// changes whose reports are not suppressed by any suppression
11699/// specification. In effect, these are deemed incompatible ABI
11700/// changes.
11701///
11702/// @return true iff the the current instance of @ref corpus_diff
11703/// carries subtype changes that are deemed incompatible ABI changes.
11704bool
11706{
11707 const diff_stats& stats = const_cast<corpus_diff*>(this)->
11709
11710 return (stats.net_num_func_changed() != 0
11711 || stats.net_num_vars_changed() != 0
11712 || stats.net_num_removed_unreachable_types() != 0
11713 || stats.net_num_changed_unreachable_types() != 0);
11714}
11715
11716/// Test if the current instance of @ref corpus_diff carries changes
11717/// whose reports are not suppressed by any suppression specification.
11718/// In effect, these are deemed incompatible ABI changes.
11719///
11720/// @return true iff the the current instance of @ref corpus_diff
11721/// carries subtype changes that are deemed incompatible ABI changes.
11722bool
11724{return context()->get_reporter()->diff_has_net_changes(this);}
11725
11726/// Apply the different filters that are registered to be applied to
11727/// the diff tree; that includes the categorization filters. Also,
11728/// apply the suppression interpretation filters.
11729///
11730/// After the filters are applied, this function calculates some
11731/// statistics about the changes carried by the current instance of
11732/// @ref corpus_diff. These statistics are represented by an instance
11733/// of @ref corpus_diff::diff_stats.
11734///
11735/// This member function is called by the reporting function
11736/// corpus_diff::report().
11737///
11738/// Note that for a given instance of corpus_diff, this function
11739/// applies the filters and suppressions only the first time it is
11740/// invoked. Subsequent invocations just return the instance of
11741/// corpus_diff::diff_stats that was cached after the first
11742/// invocation.
11743///
11744/// @return a reference to the statistics about the changes carried by
11745/// the current instance of @ref corpus_diff.
11748{
11749 if (priv_->diff_stats_)
11750 return *priv_->diff_stats_;
11751
11753 if (do_log())
11754 {
11755 std::cerr << "Applying suppressions ...\n";
11756 t.start();
11757 }
11758
11759 apply_suppressions(this);
11760
11761 if (do_log())
11762 {
11763 t.stop();
11764 std::cerr << "suppressions applied!:" << t << "\n";
11765 }
11766
11767 priv_->diff_stats_.reset(new diff_stats(context()));
11768
11769 if (do_log())
11770 {
11771 std::cerr << "Marking leaf nodes ...\n";
11772 t.start();
11773 }
11774
11776
11777 if (do_log())
11778 {
11779 t.stop();
11780 std::cerr << "leaf nodes marked!:" << t << "\n";
11781 std::cerr << "Applying filters and computing diff stats ...\n";
11782 t.start();
11783 }
11784
11785 priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
11786
11787 if (do_log())
11788 {
11789 t.stop();
11790 std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
11791 }
11792
11793 return *priv_->diff_stats_;
11794}
11795
11796/// A visitor that marks leaf diff nodes by storing them in the
11797/// instance of @ref diff_maps returned by
11798/// corpus_diff::get_leaf_diffs() invoked on the current instance of
11799/// corpus_diff.
11800struct leaf_diff_node_marker_visitor : public diff_node_visitor
11801{
11802 /// This is called when the visitor visits a diff node.
11803 ///
11804 /// It basically tests if the diff node being visited is a leaf diff
11805 /// node - that is, it contains local changes. If it does, then the
11806 /// node is added to the set of maps that hold leaf diffs in the
11807 /// current corpus_diff.
11808 ///
11809 /// Note that only leaf nodes that are reachable from public
11810 /// interfaces (global functions or variables) are collected by this
11811 /// visitor.
11812 ///
11813 /// @param d the diff node being visited.
11814 virtual void
11815 visit_begin(diff *d)
11816 {
11817 if (d->has_local_changes()
11818 // A leaf basic (or class/union) type name change makes no
11819 // sense when showing just leaf changes. It only makes sense
11820 // when it can explain the details about a non-leaf change.
11821 // In other words, it doesn't make sense to say that an "int"
11822 // became "unsigned int". But it does make sense to say that
11823 // a typedef changed because its underlying type was 'int' and
11824 // is now an "unsigned int".
11826 // Similarly, a *local* change describing a type that changed
11827 // its nature doesn't make sense.
11828 && !is_distinct_diff(d)
11829 // Similarly, a pointer (or reference or array), a typedef or
11830 // qualified type change in itself doesn't make sense. It
11831 // would rather make sense to show that pointer change as part
11832 // of the variable change whose pointer type changed, for
11833 // instance.
11834 && !is_pointer_diff(d)
11835 && !is_reference_diff(d)
11837 && !is_typedef_diff(d)
11838 && !is_array_diff(d)
11839 // Similarly a parameter change in itself doesn't make sense.
11840 // It should have already been reported as part of the change
11841 // of the function it belongs to.
11842 && !is_fn_parm_diff(d)
11843 // An anonymous class or union diff doesn't make sense on its
11844 // own. It must have been described already by the diff of
11845 // the enclosing struct or union if 'd' is from an anonymous
11846 // data member, or from a typedef change if 'd' is from a
11847 // typedef change which underlying type is an anonymous
11848 // struct/union.
11850 // Don't show decl-only-ness changes either.
11852 // Sometime, we can encounter artifacts of bogus DWARF that
11853 // yield a diff node for a decl-only class (and empty class
11854 // with the is_declaration flag set) that carries a non-zero
11855 // size! And of course at some point that non-zero size
11856 // changes. We need to be able to detect that.
11858 {
11859 diff_context_sptr ctxt = d->context();
11860 const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
11861 ABG_ASSERT(corpus_diff_node);
11862
11863 if (diff *iface_diff = get_current_topmost_iface_diff())
11864 {
11865 type_or_decl_base_sptr iface = iface_diff->first_subject();
11866 // So, this diff node that is reachable from a global
11867 // function or variable carries a leaf change. Let's add
11868 // it to the set of of leaf diffs of corpus_diff_node.
11869 const_cast<corpus_diff*>(corpus_diff_node)->
11870 get_leaf_diffs().insert_diff_node(d, iface);
11871 }
11872 }
11873 }
11874}; // end struct leaf_diff_node_marker_visitor
11875
11876/// Walks the diff nodes associated to the current corpus diff and
11877/// mark those that carry local changes. They are said to be leaf
11878/// diff nodes.
11879///
11880/// The marked nodes are available from the
11881/// corpus_diff::get_leaf_diffs() function.
11882void
11884{
11885 if (!has_changes())
11886 return;
11887
11888 if (!context()->show_leaf_changes_only())
11889 return;
11890
11891 leaf_diff_node_marker_visitor v;
11892 context()->forget_visited_diffs();
11893 bool s = context()->visiting_a_node_twice_is_forbidden();
11894 context()->forbid_visiting_a_node_twice(true);
11895 if (context()->show_impacted_interfaces())
11896 context()->forbid_visiting_a_node_twice_per_interface(true);
11897 traverse(v);
11898 context()->forbid_visiting_a_node_twice(s);
11899 context()->forbid_visiting_a_node_twice_per_interface(false);
11900}
11901
11902/// Get the set of maps that contain leaf nodes. A leaf node being a
11903/// node with a local change.
11904///
11905/// @return the set of maps that contain leaf nodes. A leaf node
11906/// being a node with a local change.
11907diff_maps&
11909{return priv_->leaf_diffs_;}
11910
11911/// Get the set of maps that contain leaf nodes. A leaf node being a
11912/// node with a local change.
11913///
11914/// @return the set of maps that contain leaf nodes. A leaf node
11915/// being a node with a local change.
11916const diff_maps&
11918{return priv_->leaf_diffs_;}
11919
11920/// Report the diff in a serialized form.
11921///
11922/// @param out the stream to serialize the diff to.
11923///
11924/// @param indent the prefix to use for the indentation of this
11925/// serialization.
11926void
11927corpus_diff::report(ostream& out, const string& indent) const
11928{
11929 context()->get_reporter()->report(*this, out, indent);
11930}
11931
11932/// Traverse the diff sub-tree under the current instance corpus_diff.
11933///
11934/// @param v the visitor to invoke on each diff node of the sub-tree.
11935///
11936/// @return true if the traversing has to keep going on, false otherwise.
11937bool
11939{
11941
11942 v.visit_begin(this);
11943
11944 if (!v.visit(this, true))
11945 {
11946 v.visit_end(this);
11947 return false;
11948 }
11949
11950 for (function_decl_diff_sptrs_type::const_iterator i =
11951 changed_functions_sorted().begin();
11952 i != changed_functions_sorted().end();
11953 ++i)
11954 {
11955 if (diff_sptr d = *i)
11956 {
11957 const diff_context_sptr &ctxt = context();
11958 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11959 ctxt->forget_visited_diffs();
11960
11962
11963 if (!d->traverse(v))
11964 {
11965 v.visit_end(this);
11967 return false;
11968 }
11969 }
11970 }
11971
11972 for (var_diff_sptrs_type::const_iterator i =
11973 changed_variables_sorted().begin();
11974 i != changed_variables_sorted().end();
11975 ++i)
11976 {
11977 if (diff_sptr d = *i)
11978 {
11979 const diff_context_sptr &ctxt = context();
11980 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11981 ctxt->forget_visited_diffs();
11982
11984
11985 if (!d->traverse(v))
11986 {
11987 v.visit_end(this);
11989 return false;
11990 }
11991 }
11992 }
11993
11995
11996 // Traverse the changed unreachable type diffs. These diffs are on
11997 // types that are not reachable from global functions or variables.
11998 for (vector<diff_sptr>::const_iterator i =
12001 ++i)
12002 {
12003 if (diff_sptr d = *i)
12004 {
12005 const diff_context_sptr &ctxt = context();
12006 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12007 ctxt->forget_visited_diffs();
12008
12009 if (!d->traverse(v))
12010 {
12011 v.visit_end(this);
12012 return false;
12013 }
12014 }
12015 }
12016
12017 v.visit_end(this);
12018 return true;
12019}
12020
12021/// Compute the diff between two instances of @ref corpus.
12022///
12023/// Note that the two corpora must have been created in the same @ref
12024/// environment, otherwise, this function aborts.
12025///
12026/// @param f the first @ref corpus to consider for the diff.
12027///
12028/// @param s the second @ref corpus to consider for the diff.
12029///
12030/// @param ctxt the diff context to use.
12031///
12032/// @return the resulting diff between the two @ref corpus.
12034compute_diff(const corpus_sptr f,
12035 const corpus_sptr s,
12036 diff_context_sptr ctxt)
12037{
12038 typedef corpus::functions::const_iterator fns_it_type;
12039 typedef corpus::variables::const_iterator vars_it_type;
12040 typedef elf_symbols::const_iterator symbols_it_type;
12041 typedef diff_utils::deep_ptr_eq_functor eq_type;
12042 typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
12043
12044 ABG_ASSERT(f && s);
12045
12046 if (!ctxt)
12047 ctxt.reset(new diff_context);
12048
12049 corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
12050
12051 ctxt->set_corpus_diff(r);
12052
12053 if(ctxt->show_soname_change())
12054 r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
12055 else
12056 r->priv_->sonames_equal_ = true;
12057
12058 r->priv_->architectures_equal_ =
12059 f->get_architecture_name() == s->get_architecture_name();
12060
12061 // Compute the diff of publicly defined and exported functions
12062 diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
12063 f->get_functions().end(),
12064 s->get_functions().begin(),
12065 s->get_functions().end(),
12066 r->priv_->fns_edit_script_);
12067
12068 // Compute the diff of publicly defined and exported variables.
12069 diff_utils::compute_diff<vars_it_type, eq_type>
12070 (f->get_variables().begin(), f->get_variables().end(),
12071 s->get_variables().begin(), s->get_variables().end(),
12072 r->priv_->vars_edit_script_);
12073
12074 // Compute the diff of function elf symbols not referenced by debug
12075 // info.
12076 diff_utils::compute_diff<symbols_it_type, eq_type>
12077 (f->get_unreferenced_function_symbols().begin(),
12078 f->get_unreferenced_function_symbols().end(),
12079 s->get_unreferenced_function_symbols().begin(),
12080 s->get_unreferenced_function_symbols().end(),
12081 r->priv_->unrefed_fn_syms_edit_script_);
12082
12083 // Compute the diff of variable elf symbols not referenced by debug
12084 // info.
12085 diff_utils::compute_diff<symbols_it_type, eq_type>
12086 (f->get_unreferenced_variable_symbols().begin(),
12087 f->get_unreferenced_variable_symbols().end(),
12088 s->get_unreferenced_variable_symbols().begin(),
12089 s->get_unreferenced_variable_symbols().end(),
12090 r->priv_->unrefed_var_syms_edit_script_);
12091
12092 if (ctxt->show_unreachable_types())
12093 // Compute the diff of types not reachable from public functions
12094 // or global variables that are exported.
12095 diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
12096 (f->get_types_not_reachable_from_public_interfaces().begin(),
12097 f->get_types_not_reachable_from_public_interfaces().end(),
12098 s->get_types_not_reachable_from_public_interfaces().begin(),
12099 s->get_types_not_reachable_from_public_interfaces().end(),
12100 r->priv_->unreachable_types_edit_script_);
12101
12102 r->priv_->ensure_lookup_tables_populated();
12103
12104 return r;
12105}
12106
12107// </corpus stuff>
12108
12109/// Compute the diff between two instances of @ref corpus_group.
12110///
12111/// Note that the two corpus_diff must have been created in the same
12112/// @ref environment, otherwise, this function aborts.
12113///
12114/// @param f the first @ref corpus_group to consider for the diff.
12115///
12116/// @param s the second @ref corpus_group to consider for the diff.
12117///
12118/// @param ctxt the diff context to use.
12119///
12120/// @return the resulting diff between the two @ref corpus_group.
12122compute_diff(const corpus_group_sptr& f,
12123 const corpus_group_sptr& s,
12124 diff_context_sptr ctxt)
12125{
12126
12127 corpus_sptr c1 = f;
12128 corpus_sptr c2 = s;
12129
12130 return compute_diff(c1, c2, ctxt);
12131}
12132
12133// <corpus_group stuff>
12134
12135// </corpus_group stuff>
12136// <diff_node_visitor stuff>
12137
12138/// The private data of the @diff_node_visitor type.
12139struct diff_node_visitor::priv
12140{
12141 diff* topmost_interface_diff;
12142 visiting_kind kind;
12143
12144 priv()
12145 : topmost_interface_diff(),
12146 kind()
12147 {}
12148
12149 priv(visiting_kind k)
12150 : topmost_interface_diff(),
12151 kind(k)
12152 {}
12153}; // end struct diff_node_visitor
12154
12155/// Default constructor of the @ref diff_node_visitor type.
12157 : priv_(new priv)
12158{}
12159
12160diff_node_visitor::~diff_node_visitor() = default;
12161
12162/// Constructor of the @ref diff_node_visitor type.
12163///
12164/// @param k how the visiting has to be performed.
12166 : priv_(new priv(k))
12167{}
12168
12169/// Getter for the visiting policy of the traversing code while
12170/// invoking this visitor.
12171///
12172/// @return the visiting policy used by the traversing code when
12173/// invoking this visitor.
12176{return priv_->kind;}
12177
12178/// Setter for the visiting policy of the traversing code while
12179/// invoking this visitor.
12180///
12181/// @param v a bit map representing the new visiting policy used by
12182/// the traversing code when invoking this visitor.
12183void
12185{priv_->kind = v;}
12186
12187/// Setter for the visiting policy of the traversing code while
12188/// invoking this visitor. This one makes a logical or between the
12189/// current policy and the bitmap given in argument and assigns the
12190/// current policy to the result.
12191///
12192/// @param v a bitmap representing the visiting policy to or with
12193/// the current policy.
12194void
12196{priv_->kind = priv_->kind | v;}
12197
12198/// Setter of the diff current topmost interface which is impacted by
12199/// the current diff node being visited.
12200///
12201/// @param d the current topmost interface diff impacted.
12202void
12204{priv_->topmost_interface_diff = d;}
12205
12206/// Getter of the diff current topmost interface which is impacted by
12207/// the current diff node being visited.
12208///
12209/// @return the current topmost interface diff impacted.
12210diff*
12212{return priv_->topmost_interface_diff;}
12213
12214/// This is called by the traversing code on a @ref diff node just
12215/// before visiting it. That is, before visiting it and its children
12216/// node.
12217///
12218/// @param d the diff node to visit.
12219void
12221{}
12222
12223/// This is called by the traversing code on a @ref diff node just
12224/// after visiting it. That is after visiting it and its children
12225/// nodes.
12226///
12227/// @param d the diff node that got visited.
12228void
12230{}
12231
12232/// This is called by the traversing code on a @ref corpus_diff node
12233/// just before visiting it. That is, before visiting it and its
12234/// children node.
12235///
12236/// @param p the corpus_diff node to visit.
12237///
12238void
12240{}
12241
12242/// This is called by the traversing code on a @ref corpus_diff node
12243/// just after visiting it. That is after visiting it and its children
12244/// nodes.
12245///
12246/// @param d the diff node that got visited.
12247void
12249{}
12250
12251/// Default visitor implementation
12252///
12253/// @return true
12254bool
12256{return true;}
12257
12258/// Default visitor implementation.
12259///
12260/// @return true
12261bool
12263{
12264 diff* d = dif;
12265 visit(d, pre);
12266
12267 return true;
12268}
12269
12270/// Default visitor implementation.
12271///
12272/// @return true
12273bool
12275{
12276 diff* d = dif;
12277 visit(d, pre);
12278
12279 return true;
12280}
12281
12282/// Default visitor implementation.
12283///
12284/// @return true
12285bool
12287{
12288 diff* d = dif;
12289 visit(d, pre);
12290
12291 return true;
12292}
12293
12294/// Default visitor implementation.
12295///
12296/// @return true
12297bool
12299{
12300 diff* d = dif;
12301 visit(d, pre);
12302
12303 return true;
12304}
12305
12306/// Default visitor implementation.
12307///
12308/// @return true
12309bool
12311{
12312 diff* d = dif;
12313 visit(d, pre);
12314
12315 return true;
12316}
12317
12318/// Default visitor implementation.
12319///
12320/// @return true
12321bool
12323{
12324 diff* d = dif;
12325 visit(d, pre);
12326
12327 return true;
12328}
12329
12330/// Default visitor implementation.
12331///
12332/// @return true
12333bool
12335{
12336 diff* d = dif;
12337 visit(d, pre);
12338
12339 return true;
12340}
12341
12342/// Default visitor implementation.
12343///
12344/// @return true
12345bool
12347{
12348 diff* d = dif;
12349 visit(d, pre);
12350
12351 return true;
12352}
12353
12354/// Default visitor implementation.
12355///
12356/// @return true
12357bool
12359{
12360 diff* d = dif;
12361 visit(d, pre);
12362
12363 return true;
12364}
12365
12366/// Default visitor implementation.
12367///
12368/// @return true
12369bool
12371{
12372 diff* d = dif;
12373 visit(d, pre);
12374
12375 return true;
12376}
12377
12378/// Default visitor implementation.
12379///
12380/// @return true
12381bool
12383{
12384 diff* d = dif;
12385 visit(d, pre);
12386
12387 return true;
12388}
12389
12390/// Default visitor implementation.
12391///
12392/// @return true
12393bool
12395{
12396 diff* d = dif;
12397 visit(d, pre);
12398
12399 return true;
12400}
12401
12402/// Default visitor implementation.
12403///
12404/// @return true
12405bool
12407{
12408 diff* d = dif;
12409 visit(d, pre);
12410
12411 return true;
12412}
12413
12414/// Default visitor implementation.
12415///
12416/// @return true
12417bool
12419{return true;}
12420
12421// </diff_node_visitor stuff>
12422
12423// <redundant diff node marking>
12424
12425// </redundant diff node marking>
12426
12427// <diff tree category propagation>
12428
12429/// A visitor to propagate the category of a node up to its parent
12430/// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
12431/// SUPPRESSED_CATEGORY because those are propagated using other
12432/// specific visitors.
12433struct category_propagation_visitor : public diff_node_visitor
12434{
12435 virtual void
12436 visit_end(diff* d)
12437 {
12438 // Has this diff node 'd' been already visited ?
12439 bool already_visited = d->context()->diff_has_been_visited(d);
12440
12441 // The canonical diff node of the class of equivalence of the diff
12442 // node 'd'.
12443 diff* canonical = d->get_canonical_diff();
12444
12445 // If this class of equivalence of diff node is being visited for
12446 // the first time, then update its canonical node's category too.
12447 bool update_canonical = !already_visited && canonical;
12448
12449 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12450 i != d->children_nodes().end();
12451 ++i)
12452 {
12453 // If we are visiting the class of equivalence of 'd' for the
12454 // first time, then let's look at the children of 'd' and
12455 // propagate their categories to 'd'.
12456 //
12457 // If the class of equivalence of 'd' has already been
12458 // visited, then let's look at the canonical diff nodes of the
12459 // children of 'd' and propagate their categories to 'd'.
12460 diff* diff = already_visited
12461 ? (*i)->get_canonical_diff()
12462 : *i;
12463
12465
12467 // Do not propagate redundant and suppressed categories. Those
12468 // are propagated in a specific pass elsewhere.
12469 c &= ~(REDUNDANT_CATEGORY
12475 // Also, if a (class) type has got a harmful name change, do not
12476 // propagate harmless name changes coming from its sub-types
12477 // (i.e, data members) to the class itself.
12480
12481 d->add_to_category(c);
12482 if (!already_visited && canonical)
12483 if (update_canonical)
12484 canonical->add_to_category(c);
12485 }
12486 }
12487};// end struct category_propagation_visitor
12488
12489/// Visit all the nodes of a given sub-tree. For each node that has a
12490/// particular category set, propagate that category set up to its
12491/// parent nodes.
12492///
12493/// @param diff_tree the diff sub-tree to walk for categorization
12494/// purpose;
12495void
12497{
12498 category_propagation_visitor v;
12499 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12500 diff_tree->context()->forbid_visiting_a_node_twice(true);
12501 diff_tree->context()->forget_visited_diffs();
12502 diff_tree->traverse(v);
12503 diff_tree->context()->forbid_visiting_a_node_twice(s);
12504}
12505
12506/// Visit all the nodes of a given sub-tree. For each node that has a
12507/// particular category set, propagate that category set up to its
12508/// parent nodes.
12509///
12510/// @param diff_tree the diff sub-tree to walk for categorization
12511/// purpose;
12512void
12514{propagate_categories(diff_tree.get());}
12515
12516/// Visit all the nodes of a given corpus tree. For each node that
12517/// has a particular category set, propagate that category set up to
12518/// its parent nodes.
12519///
12520/// @param diff_tree the corpus_diff tree to walk for categorization
12521/// purpose;
12522void
12524{
12525 category_propagation_visitor v;
12526 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12527 diff_tree->context()->forbid_visiting_a_node_twice(false);
12528 diff_tree->traverse(v);
12529 diff_tree->context()->forbid_visiting_a_node_twice(s);
12530}
12531
12532/// Visit all the nodes of a given corpus tree. For each node that
12533/// has a particular category set, propagate that category set up to
12534/// its parent nodes.
12535///
12536/// @param diff_tree the corpus_diff tree to walk for categorization
12537/// purpose;
12538void
12540{propagate_categories(diff_tree.get());}
12541
12542/// A tree node visitor that knows how to categorizes a given diff
12543/// node in the SUPPRESSED_CATEGORY category and how to propagate that
12544/// categorization.
12545struct suppression_categorization_visitor : public diff_node_visitor
12546{
12547
12548 /// Before visiting the children of the diff node, check if the node
12549 /// is suppressed by a suppression specification. If it is, mark
12550 /// the node as belonging to the SUPPRESSED_CATEGORY category.
12551 ///
12552 /// @param p the diff node to visit.
12553 virtual void
12554 visit_begin(diff* d)
12555 {
12556 bool is_private_type = false;
12557 if (d->is_suppressed(is_private_type))
12558 {
12559 diff_category c = is_private_type
12563
12564 // If a node was suppressed, all the other nodes of its class
12565 // of equivalence are suppressed too.
12566 diff *canonical_diff = d->get_canonical_diff();
12567 if (canonical_diff != d)
12568 canonical_diff->add_to_category(c);
12569 }
12571 {
12572 // This diff node is specifically allowed by a
12573 // negated_suppression, then mark it as being in the
12574 // HAS_ALLOWED_CHANGE_CATEGORY.
12577 diff *canonical_diff = d->get_canonical_diff();
12578 canonical_diff->add_to_category(c);
12579
12580 // Note that some complementary code later down below does
12581 // categorize the descendants and parents nodes of this node
12582 // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
12583 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
12584 }
12585
12586 // If a parent node has been allowed by a negated suppression
12587 // specification, then categorize the current node as
12588 // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
12589 if (d->parent_node())
12590 {
12595 else
12596 {
12597 c = d->parent_node()->get_category();
12601 }
12602 }
12603
12604 }
12605
12606 /// After visiting the children nodes of a given diff node,
12607 /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
12608 /// diff node, if need be.
12609 ///
12610 /// That is, if all children nodes carry a suppressed change the
12611 /// current node should be marked as suppressed as well.
12612 ///
12613 /// In practice, this might be too strong of a condition. If the
12614 /// current node carries a local change (i.e, a change not carried
12615 /// by any of its children node) and if that change is not
12616 /// suppressed, then the current node should *NOT* be suppressed.
12617 ///
12618 /// But right now, the IR doesn't let us know about local vs
12619 /// children-carried changes. So we cannot be that precise yet.
12620 virtual void
12621 visit_end(diff* d)
12622 {
12623 bool has_non_suppressed_child = false;
12624 bool has_non_empty_child = false;
12625 bool has_suppressed_child = false;
12626 bool has_non_private_child = false;
12627 bool has_private_child = false;
12628 bool has_descendant_with_allowed_change = false;
12629
12630 if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
12631 // (or the PRIVATE_TYPE_CATEGORY for the same matter)
12632 // category from its children is a node which:
12633 //
12634 // 1/ hasn't been suppressed already
12635 //
12636 // 2/ and has no local change (unless it's a pointer,
12637 // reference or qualified diff node).
12638 //
12639 // Note that qualified type and typedef diff nodes are a bit
12640 // special. The local changes of the underlying type are
12641 // considered local for the qualified/typedef type, just like
12642 // for pointer/reference types. But then the qualified or
12643 // typedef type itself can have local changes of its own, and
12644 // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
12645 // So a qualified type which have local changes that are
12646 // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
12647 // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
12648 // or SUPPRESSED_CATEGORY can see these categories be
12649 // propagated.
12650 //
12651 // Note that all pointer/reference diff node changes are
12652 // potentially considered local, i.e, local changes of the
12653 // pointed-to-type are considered local to the pointer itself.
12654 //
12655 // Similarly, changes local to the type of function parameters,
12656 // variables (and data members) and classes (that are not of
12657 // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
12658 // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
12659 // those kinds of diff node.
12660 !(d->get_category() & SUPPRESSED_CATEGORY)
12661 && (!d->has_local_changes()
12662 || is_pointer_diff(d)
12663 || is_reference_diff(d)
12665 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12666 || (is_typedef_diff(d)
12667 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12669 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12670 || (is_fn_parm_diff(d)
12671 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12673 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12674 || (is_var_diff(d)
12675 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12676 || (is_class_diff(d)
12677 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
12678 {
12679 // Note that we handle private diff nodes differently from
12680 // generally suppressed diff nodes. E.g, it's not because a
12681 // type is private (and suppressed because of that; i.e, in
12682 // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
12683 // type should also be private and so suppressed. Private
12684 // diff nodes thus have different propagation rules than
12685 // generally suppressed rules.
12686 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12687 i != d->children_nodes().end();
12688 ++i)
12689 {
12690 diff* child = *i;
12691 if (child->has_changes())
12692 {
12693 has_non_empty_child = true;
12694 if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
12695 has_suppressed_child = true;
12696 else if (child->get_class_of_equiv_category()
12698 // Propagation of the PRIVATE_TYPE_CATEGORY is going
12699 // to be handled later below.
12700 ;
12701 else
12702 has_non_suppressed_child = true;
12703
12704 if (child->get_class_of_equiv_category()
12706 has_private_child = true;
12707 else if (child->get_class_of_equiv_category()
12709 // Propagation of the SUPPRESSED_CATEGORY has been
12710 // handled above already.
12711 ;
12712 else
12713 has_non_private_child = true;
12714 }
12715 }
12716
12717 if (has_non_empty_child
12718 && has_suppressed_child
12719 && !has_non_suppressed_child)
12720 {
12722 // If a node was suppressed, all the other nodes of its class
12723 // of equivalence are suppressed too.
12724 diff *canonical_diff = d->get_canonical_diff();
12725 if (canonical_diff != d)
12726 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12727 }
12728
12729 // Note that the private-ness of a an underlying type won't be
12730 // propagated to its parent typedef, by virtue of the big "if"
12731 // clause at the beginning of this function. So we don't have
12732 // to handle that case here. So the idiom of defining
12733 // typedefs of private (opaque) types will be respected;
12734 // meaning that changes to opaque underlying type will be
12735 // flagged as private and the typedef will be flagged private
12736 // as well, unless the typedef itself has local non-type
12737 // changes. In the later case, changes to the typedef will be
12738 // emitted because the typedef won't inherit the privateness
12739 // of its underlying type. So in practise, the typedef
12740 // remains public for the purpose of change reporting.
12741 if (has_non_empty_child
12742 && has_private_child
12743 && !has_non_private_child)
12744 {
12745 d->add_to_category(PRIVATE_TYPE_CATEGORY);
12746 // If a node was suppressed, all the other nodes of its class
12747 // of equivalence are suppressed too.
12748 diff *canonical_diff = d->get_canonical_diff();
12749 if (canonical_diff != d)
12750 canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
12751 }
12752
12753 // If the underlying type of a typedef is private and carries
12754 // changes (that are implicitely suppressed because it's
12755 // private) then the typedef must be suppressed too, so that
12756 // those changes to the underlying type are not seen.
12757 if (is_typedef_diff(d)
12758 && !d->has_local_changes()
12759 && has_private_child
12760 && has_non_empty_child)
12761 {
12762 d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
12763 // If a node was suppressed, all the other nodes of its class
12764 // of equivalence are suppressed too.
12765 diff *canonical_diff = d->get_canonical_diff();
12766 if (canonical_diff != d)
12767 canonical_diff->add_to_category
12769 }
12770
12771 if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
12772 if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
12773 {
12774 // d is a function diff that carries a local *type*
12775 // change (that means it's a change to the function
12776 // type). Let's see if the child function type diff
12777 // node is suppressed. That would mean that we are
12778 // instructed to show details of a diff that is deemed
12779 // suppressed; this means the suppression conflicts with
12780 // a local type change. In that case, let's follow what
12781 // the user asked and suppress the function altogether,
12782 if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
12783 if (fn_type_diff->is_suppressed())
12784 {
12785 d->add_to_category(SUPPRESSED_CATEGORY);
12786 // If a node was suppressed, all the other nodes
12787 // of its class of equivalence are suppressed too.
12788 diff *canonical_diff = d->get_canonical_diff();
12789 if (canonical_diff != d)
12790 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12791 }
12792 }
12793 }
12794
12795 // If any descendant node was selected by a negated suppression
12796 // specification then categorize the current one as
12797 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
12798 for (auto child_node : d->children_nodes())
12799 {
12800 diff *canonical_diff = child_node->get_canonical_diff();
12801 diff_category c = canonical_diff->get_category();
12804 has_descendant_with_allowed_change = true;
12805 }
12806 if (has_descendant_with_allowed_change)
12807 {
12809 d->add_to_category(c);
12810 d->get_canonical_diff()->add_to_category(c);
12811 }
12812 }
12813}; //end struct suppression_categorization_visitor
12814
12815/// Walk a given diff-sub tree and appply the suppressions carried by
12816/// the context. If the suppression applies to a given node than
12817/// categorize the node into the SUPPRESSED_CATEGORY category and
12818/// propagate that categorization.
12819///
12820/// @param diff_tree the diff-sub tree to apply the suppressions to.
12821void
12823{
12824 if (diff_tree && !diff_tree->context()->suppressions().empty())
12825 {
12826 // Apply suppressions to functions and variables that have
12827 // changed sub-types.
12828 suppression_categorization_visitor v;
12829 diff_tree->context()->forget_visited_diffs();
12830 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12831 diff_tree->context()->forbid_visiting_a_node_twice(true);
12832 diff_tree->traverse(v);
12833 diff_tree->context()->forbid_visiting_a_node_twice(s);
12834 }
12835}
12836
12837/// Walk a given diff-sub tree and appply the suppressions carried by
12838/// the context. If the suppression applies to a given node than
12839/// categorize the node into the SUPPRESSED_CATEGORY category and
12840/// propagate that categorization.
12841///
12842/// @param diff_tree the diff-sub tree to apply the suppressions to.
12843void
12845{apply_suppressions(diff_tree.get());}
12846
12847/// Walk a @ref corpus_diff tree and appply the suppressions carried
12848/// by the context. If the suppression applies to a given node then
12849/// categorize the node into the SUPPRESSED_CATEGORY category and
12850/// propagate that categorization.
12851///
12852/// @param diff_tree the diff tree to apply the suppressions to.
12853void
12855{
12856 if (diff_tree && !diff_tree->context()->suppressions().empty())
12857 {
12858 // First, visit the children trees of changed constructs:
12859 // changed functions, variables, as well as sub-types of these,
12860 // and apply suppression specifications to these ...
12861 suppression_categorization_visitor v;
12862 diff_tree->context()->forget_visited_diffs();
12863 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12864 diff_tree->context()->forbid_visiting_a_node_twice(true);
12865 const_cast<corpus_diff*>(diff_tree)->traverse(v);
12866 diff_tree->context()->forbid_visiting_a_node_twice(s);
12867
12868 // ... then also visit the set of added and removed functions,
12869 // variables, symbols, and types not reachable from global
12870 // functions and variables.
12871 diff_tree->priv_->
12872 apply_supprs_to_added_removed_fns_vars_unreachable_types();
12873 }
12874}
12875
12876/// Walk a diff tree and appply the suppressions carried by the
12877/// context. If the suppression applies to a given node than
12878/// categorize the node into the SUPPRESSED_CATEGORY category and
12879/// propagate that categorization.
12880///
12881/// @param diff_tree the diff tree to apply the suppressions to.
12882void
12884{apply_suppressions(diff_tree.get());}
12885
12886// </diff tree category propagation>
12887
12888// <diff tree printing stuff>
12889
12890/// A visitor to print (to an output stream) a pretty representation
12891/// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
12892struct diff_node_printer : public diff_node_visitor
12893{
12894 ostream& out_;
12895 unsigned level_;
12896
12897 /// Emit a certain number of spaces to the output stream associated
12898 /// to this diff_node_printer.
12899 ///
12900 /// @param level half of the numver of spaces to emit.
12901 void
12902 do_indent(unsigned level)
12903 {
12904 for (unsigned i = 0; i < level; ++i)
12905 out_ << " ";
12906 }
12907
12908 diff_node_printer(ostream& out)
12909 : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
12910 out_(out),
12911 level_(0)
12912 {}
12913
12914 virtual void
12915 visit_begin(diff*)
12916 {
12917 ++level_;
12918 }
12919
12920 virtual void
12921 visit_end(diff*)
12922 {
12923 --level_;
12924 }
12925
12926 virtual void
12927 visit_begin(corpus_diff*)
12928 {
12929 ++level_;
12930 }
12931
12932 virtual void
12933 visit_end(corpus_diff*)
12934 {
12935 --level_;
12936 }
12937
12938 virtual bool
12939 visit(diff* d, bool pre)
12940 {
12941 if (!pre)
12942 // We are post-visiting the diff node D. Which means, we have
12943 // printed a pretty representation for it already. So do
12944 // nothing now.
12945 return true;
12946
12947 do_indent(level_);
12948 out_ << d->get_pretty_representation();
12949 out_ << "\n";
12950 do_indent(level_);
12951 out_ << "{\n";
12952 do_indent(level_ + 1);
12953 out_ << "category: "<< d->get_category() << "\n";
12954 do_indent(level_ + 1);
12955 out_ << "@: " << std::hex << d << std::dec << "\n";
12956 do_indent(level_ + 1);
12957 out_ << "@-canonical: " << std::hex
12958 << d->get_canonical_diff()
12959 << std::dec << "\n";
12960 do_indent(level_);
12961 out_ << "}\n";
12962
12963 return true;
12964 }
12965
12966 virtual bool
12967 visit(corpus_diff* d, bool pre)
12968 {
12969 if (!pre)
12970 // We are post-visiting the diff node D. Which means, we have
12971 // printed a pretty representation for it already. So do
12972 // nothing now.
12973 return true;
12974
12975 // indent
12976 for (unsigned i = 0; i < level_; ++i)
12977 out_ << ' ';
12978 out_ << d->get_pretty_representation();
12979 out_ << '\n';
12980 return true;
12981 }
12982}; // end struct diff_printer_visitor
12983
12984// </ diff tree printing stuff>
12985
12986/// Emit a textual representation of a @ref diff sub-tree to an
12987/// output stream.
12988///
12989/// @param diff_tree the sub-tree to emit the textual representation
12990/// for.
12991///
12992/// @param out the output stream to emit the textual representation
12993/// for @p diff_tree to.
12994void
12995print_diff_tree(diff* diff_tree, ostream& out)
12996{
12997 diff_node_printer p(out);
12998 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12999 diff_tree->context()->forbid_visiting_a_node_twice(false);
13000 diff_tree->traverse(p);
13001 diff_tree->context()->forbid_visiting_a_node_twice(s);
13002}
13003
13004/// Emit a textual representation of a @ref corpus_diff tree to an
13005/// output stream.
13006///
13007/// @param diff_tree the @ref corpus_diff tree to emit the textual
13008/// representation for.
13009///
13010/// @param out the output stream to emit the textual representation
13011/// for @p diff_tree to.
13012void
13013print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
13014{
13015 diff_node_printer p(out);
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(p);
13019 diff_tree->context()->forbid_visiting_a_node_twice(s);
13020}
13021
13022/// Emit a textual representation of a @ref diff sub-tree to an
13023/// output stream.
13024///
13025/// @param diff_tree the sub-tree to emit the textual representation
13026/// for.
13027///
13028/// @param out the output stream to emit the textual representation
13029/// for @p diff_tree to.
13030void
13032 std::ostream& o)
13033{print_diff_tree(diff_tree.get(), o);}
13034
13035/// Emit a textual representation of a @ref corpus_diff tree to an
13036/// output stream.
13037///
13038/// @param diff_tree the @ref corpus_diff tree to emit the textual
13039/// representation for.
13040///
13041/// @param out the output stream to emit the textual representation
13042/// for @p diff_tree to.
13043void
13045 std::ostream& o)
13046{print_diff_tree(diff_tree.get(), o);}
13047
13048// <redundancy_marking_visitor>
13049
13050/// A tree visitor to categorize nodes with respect to the
13051/// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
13052/// present on several spots of the tree) and mark such nodes
13053/// appropriatly. This visitor also takes care of propagating the
13054/// REDUNDANT_CATEGORY of a given node to its parent nodes as
13055/// appropriate.
13056struct redundancy_marking_visitor : public diff_node_visitor
13057{
13058 bool skip_children_nodes_;
13059
13060 redundancy_marking_visitor()
13061 : skip_children_nodes_()
13062 {}
13063
13064 virtual void
13065 visit_begin(diff* d)
13066 {
13067 if (d->to_be_reported())
13068 {
13069 // A diff node that carries a change and that has been already
13070 // traversed elsewhere is considered redundant. So let's mark
13071 // it as such and let's not traverse it; that is, let's not
13072 // visit its children.
13073 if ((d->context()->diff_has_been_visited(d)
13074 || d->get_canonical_diff()->is_traversing())
13075 && d->has_changes())
13076 {
13077 // But if two diff nodes are redundant sibbling that carry
13078 // changes of base types, do not mark them as being
13079 // redundant. This is to avoid marking nodes as redundant
13080 // in this case:
13081 //
13082 // int foo(int a, int b);
13083 // compared with:
13084 // float foo(float a, float b); (in C).
13085 //
13086 // In this case, we want to report all the occurences of
13087 // the int->float change because logically, they are at
13088 // the same level in the diff tree.
13089
13090 bool redundant_with_sibling_node = false;
13091 const diff* p = d->parent_node();
13092
13093 // If this is a child node of a fn_parm_diff, look through
13094 // the fn_parm_diff node to get the function diff node.
13095 if (p && dynamic_cast<const fn_parm_diff*>(p))
13096 p = p->parent_node();
13097
13098 if (p)
13099 for (vector<diff*>::const_iterator s =
13100 p->children_nodes().begin();
13101 s != p->children_nodes().end();
13102 ++s)
13103 {
13104 if (*s == d)
13105 continue;
13106 diff* sib = *s;
13107 // If this is a fn_parm_diff, look through the
13108 // fn_parm_diff node to get at the real type node.
13109 if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
13110 sib = f->type_diff().get();
13111 if (sib == d)
13112 continue;
13113 if (sib->get_canonical_diff() == d->get_canonical_diff()
13114 // Sibbling diff nodes that carry base type
13115 // changes ar to be marked as redundant.
13116 && (is_base_diff(sib) || is_distinct_diff(sib)))
13117 {
13118 redundant_with_sibling_node = true;
13119 break;
13120 }
13121 }
13122 if (!redundant_with_sibling_node
13123 // Changes to basic types should never be considered
13124 // redundant. For instance, if a member of integer
13125 // type is changed into a char type in both a struct A
13126 // and a struct B, we want to see both changes.
13128 // The same goes for distinct type changes
13130 // Functions with similar *local* changes are never marked
13131 // redundant because otherwise one could miss important
13132 // similar local changes that are applied to different
13133 // functions.
13135 // Changes involving variadic parameters of functions
13136 // should never be marked redundant because we want to see
13137 // them all.
13140 // If the canonical diff itself has been filtered out,
13141 // then this one is not marked redundant, unless the
13142 // canonical diff was already redundant.
13143 && (!d->get_canonical_diff()->is_filtered_out()
13144 || (d->get_canonical_diff()->get_category()
13146 // If the *same* diff node (not one that is merely
13147 // equivalent to this one) has already been visited
13148 // the do not mark it as beind redundant. It's only
13149 // the other nodes that are equivalent to this one
13150 // that must be marked redundant.
13151 && d->context()->diff_has_been_visited(d) != d
13152 // If the diff node is a function parameter and is not
13153 // a reference/pointer (to a non basic or a non
13154 // distinct type diff) then do not mark it as
13155 // redundant.
13156 //
13157 // Children nodes of base class diff nodes are never
13158 // redundant either, we want to see them all.
13162 {
13164 // As we said in preamble, as this node is marked as
13165 // being redundant, let's not visit its children.
13166 // This is not an optimization; it's needed for
13167 // correctness. In the case of a diff node involving
13168 // a class type that refers to himself, visiting the
13169 // children nodes might cause them to be wrongly
13170 // marked as redundant.
13173 skip_children_nodes_ = true;
13174 }
13175 }
13176 }
13177 else
13178 {
13179 // If the node is not to be reported, do not look at it children.
13181 skip_children_nodes_ = true;
13182 }
13183 }
13184
13185 virtual void
13186 visit_begin(corpus_diff*)
13187 {
13188 }
13189
13190 virtual void
13191 visit_end(diff* d)
13192 {
13193 if (skip_children_nodes_)
13194 // When visiting this node, we decided to skip its children
13195 // node. Now that we are done visiting the node, lets stop
13196 // avoiding the children nodes visiting for the other tree
13197 // nodes.
13198 {
13200 skip_children_nodes_ = false;
13201 }
13202 else
13203 {
13204 // Propagate the redundancy categorization of the children nodes
13205 // to this node. But if this node has local changes, then it
13206 // doesn't inherit redundancy from its children nodes.
13207 if (!(d->get_category() & REDUNDANT_CATEGORY)
13208 && (!d->has_local_changes_to_be_reported()
13209 // By default, pointer, reference and qualified types
13210 // consider that a local changes to their underlying
13211 // type is always a local change for themselves.
13212 //
13213 // This is as if those types don't have local changes
13214 // in the same sense as other types. So we always
13215 // propagate redundancy to them, regardless of if they
13216 // have local changes or not.
13217 //
13218 // We also propagate redundancy to typedef types if
13219 // these /only/ carry changes to their underlying
13220 // type.
13221 //
13222 // Note that changes to the underlying type of a
13223 // typedef is considered local of
13224 // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
13225 // typedef itself are considered local of
13226 // LOCAL_NON_TYPE_CHANGE_KIND kind.
13227 || is_pointer_diff(d)
13229 // A typedef with local non-type changes should not
13230 // see redundancy propagation from its underlying
13231 // type, otherwise, the non-type change might be
13232 // "suppressed" away.
13233 || (is_typedef_diff(d)
13234 && (!(d->has_local_changes()
13236 // A (member) variable with non-type local changes
13237 // should not see redundacy propagation from its type.
13238 // If redundant local-type changes are carried by its
13239 // type however, then that redundancy is propagated to
13240 // the variable. This is key to keep the redundancy
13241 // consistency in the system; otherwise, a type change
13242 // would be rightfully considered redundant at some
13243 // places but not at others.
13244 || (is_var_diff(d)
13245 && (!(d->has_local_changes()
13247 // A function parameter with non-type local changes
13248 // should not see redundancy propagation either. But
13249 // a function parameter with local type changes can
13250 // definitely be redundant.
13251 || (is_fn_parm_diff(d)
13252 && (!(d->has_local_changes()
13254 ))
13255 {
13256 bool has_non_redundant_child = false;
13257 bool has_non_empty_child = false;
13258 for (vector<diff*>::const_iterator i =
13259 d->children_nodes().begin();
13260 i != d->children_nodes().end();
13261 ++i)
13262 {
13263 if ((*i)->has_changes())
13264 {
13265 has_non_empty_child = true;
13266 // Let's see if the current child node '*i' is
13267 // "non-redundant".
13268 //
13269 // A non-redundant node would be a node that
13270 // carries a change to be reported and has not
13271 // been marked as being redundant.
13272 if ((*i)->to_be_reported()
13273 && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
13274 has_non_redundant_child = true;
13275 }
13276 if (has_non_redundant_child)
13277 break;
13278 }
13279
13280 // A diff node for which at least a child node carries a
13281 // change, and for which all the children are redundant is
13282 // deemed redundant too, unless it has local changes.
13283 if (has_non_empty_child
13284 && !has_non_redundant_child)
13285 d->add_to_category(REDUNDANT_CATEGORY);
13286 }
13287 }
13288 }
13289
13290 virtual void
13291 visit_end(corpus_diff*)
13292 {
13293 }
13294
13295 virtual bool
13296 visit(diff*, bool)
13297 {return true;}
13298
13299 virtual bool
13300 visit(corpus_diff*, bool)
13301 {
13302 return true;
13303 }
13304};// end struct redundancy_marking_visitor
13305
13306/// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13307/// category out of the nodes.
13308struct redundancy_clearing_visitor : public diff_node_visitor
13309{
13310 bool
13311 visit(corpus_diff*, bool)
13312 {return true;}
13313
13314 bool
13315 visit(diff* d, bool)
13316 {
13317 // clear the REDUNDANT_CATEGORY out of the current node.
13318 diff_category c = d->get_category();
13319 c &= ~REDUNDANT_CATEGORY;
13320 d->set_category(c);
13321 return true;
13322 }
13323}; // end struct redundancy_clearing_visitor
13324
13325/// Walk a given @ref diff sub-tree to categorize each of the nodes
13326/// with respect to the REDUNDANT_CATEGORY.
13327///
13328/// @param diff_tree the @ref diff sub-tree to walk.
13329void
13331{
13332 if (diff_tree->context()->show_redundant_changes())
13333 return;
13334 redundancy_marking_visitor v;
13335 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13336 diff_tree->context()->forbid_visiting_a_node_twice(false);
13337 diff_tree->traverse(v);
13338 diff_tree->context()->forbid_visiting_a_node_twice(s);
13339}
13340
13341/// Walk a given @ref diff sub-tree to categorize each of the nodes
13342/// with respect to the REDUNDANT_CATEGORY.
13343///
13344/// @param diff_tree the @ref diff sub-tree to walk.
13345void
13347{categorize_redundancy(diff_tree.get());}
13348
13349/// Walk a given @ref corpus_diff tree to categorize each of the nodes
13350/// with respect to the REDUNDANT_CATEGORY.
13351///
13352/// @param diff_tree the @ref corpus_diff tree to walk.
13353void
13355{
13356 redundancy_marking_visitor v;
13357 diff_tree->context()->forget_visited_diffs();
13358 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13359 diff_tree->context()->forbid_visiting_a_node_twice(false);
13360 diff_tree->traverse(v);
13361 diff_tree->context()->forbid_visiting_a_node_twice(s);
13362}
13363
13364/// Walk a given @ref corpus_diff tree to categorize each of the nodes
13365/// with respect to the REDUNDANT_CATEGORY.
13366///
13367/// @param diff_tree the @ref corpus_diff tree to walk.
13368void
13370{categorize_redundancy(diff_tree.get());}
13371
13372// </redundancy_marking_visitor>
13373
13374/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13375/// out of the category of the nodes.
13376///
13377/// @param diff_tree the @ref diff sub-tree to walk.
13378void
13380{
13381 redundancy_clearing_visitor v;
13382 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13383 diff_tree->context()->forbid_visiting_a_node_twice(false);
13384 diff_tree->traverse(v);
13385 diff_tree->context()->forbid_visiting_a_node_twice(s);
13386 diff_tree->context()->forget_visited_diffs();
13387}
13388
13389/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13390/// out of the category of the nodes.
13391///
13392/// @param diff_tree the @ref diff sub-tree to walk.
13393void
13395{clear_redundancy_categorization(diff_tree.get());}
13396
13397/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13398/// out of the category of the nodes.
13399///
13400/// @param diff_tree the @ref corpus_diff tree to walk.
13401void
13403{
13404 redundancy_clearing_visitor v;
13405 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13406 diff_tree->context()->forbid_visiting_a_node_twice(false);
13407 diff_tree->traverse(v);
13408 diff_tree->context()->forbid_visiting_a_node_twice(s);
13409 diff_tree->context()->forget_visited_diffs();
13410}
13411
13412/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13413/// out of the category of the nodes.
13414///
13415/// @param diff_tree the @ref corpus_diff tree to walk.
13416void
13418{clear_redundancy_categorization(diff_tree.get());}
13419
13420/// Apply the @ref diff tree filters that have been associated to the
13421/// context of the a given @ref corpus_diff tree. As a result, the
13422/// nodes of the @diff tree are going to be categorized into one of
13423/// several of the categories of @ref diff_category.
13424///
13425/// @param diff_tree the @ref corpus_diff instance which @ref diff are
13426/// to be categorized.
13427void
13429{
13430 diff_tree->context()->maybe_apply_filters(diff_tree);
13431 propagate_categories(diff_tree);
13432}
13433
13434/// Test if a diff node represents the difference between a variadic
13435/// parameter type and something else.
13436///
13437/// @param d the diff node to consider.
13438///
13439/// @return true iff @p d is a diff node that represents the
13440/// difference between a variadic parameter type and something else.
13441bool
13443{
13444 if (!d)
13445 return false;
13446
13447 type_base_sptr t = is_type(d->first_subject());
13448 if (t && t->get_environment().is_variadic_parameter_type(t))
13449 return true;
13450
13451 t = is_type(d->second_subject());
13452 if (t && t->get_environment().is_variadic_parameter_type(t))
13453 return true;
13454
13455 return false;
13456}
13457
13458/// Test if a diff node represents the difference between a variadic
13459/// parameter type and something else.
13460///
13461/// @param d the diff node to consider.
13462///
13463/// @return true iff @p d is a diff node that represents the
13464/// difference between a variadic parameter type and something else.
13465bool
13467{return is_diff_of_variadic_parameter_type(d.get());}
13468
13469/// Test if a diff node represents the difference between a variadic
13470/// parameter and something else.
13471///
13472/// @param d the diff node to consider.
13473///
13474/// @return true iff @p d is a diff node that represents the
13475/// difference between a variadic parameter and something else.
13476bool
13478{
13480 dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
13481 return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
13482}
13483
13484/// Test if a diff node represents the difference between a variadic
13485/// parameter and something else.
13486///
13487/// @param d the diff node to consider.
13488///
13489/// @return true iff @p d is a diff node that represents the
13490/// difference between a variadic parameter and something else.
13491bool
13493{return is_diff_of_variadic_parameter(d.get());}
13494
13495/// Test if a diff node represents a diff between two basic types.
13496///
13497/// @param d the diff node to consider.
13498///
13499/// @return true iff @p d is a diff between two basic types.
13500const type_decl_diff*
13502{return dynamic_cast<const type_decl_diff*>(d);}
13503
13504/// Test if a diff node represents a diff between two basic types, or
13505/// between pointers, references or qualified type to basic types.
13506///
13507/// @param diff the diff node to consider.
13508///
13509/// @param allow_indirect_type if true, then this function looks into
13510/// pointer, reference or qualified diff types to see if they "point
13511/// to" basic types.
13512///
13513/// @return true iff @p d is a diff between two basic types.
13514const type_decl_diff*
13515is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
13516{
13517 if (allow_indirect_type)
13520}
13521
13522/// If a diff node is about changes between two typedef types, get the
13523/// diff node about changes between the underlying types.
13524///
13525/// Note that this function walks the tree of underlying diff nodes
13526/// returns the first diff node about types that are not typedefs.
13527///
13528/// @param dif the dif node to consider.
13529///
13530/// @return the underlying diff node of @p dif, or just return @p dif
13531/// if it's not a typedef diff node.
13532const diff*
13534{
13535 const typedef_diff *d = 0;
13536 while ((d = is_typedef_diff(dif)))
13537 dif = d->underlying_type_diff().get();
13538 return dif;
13539}
13540
13541/// If a diff node is about changes between two pointer types, get the
13542/// diff node about changes between the underlying (pointed-to) types.
13543///
13544/// Note that this function walks the tree of underlying diff nodes
13545/// returns the first diff node about types that are not pointers.
13546///
13547/// @param dif the dif node to consider.
13548///
13549/// @return the underlying diff node of @p dif, or just return @p dif
13550/// if it's not a pointer diff node.
13551const diff*
13553{
13554 const pointer_diff *d = 0;
13555 while ((d = is_pointer_diff(dif)))
13556 dif = d->underlying_type_diff().get();
13557 return dif;
13558}
13559
13560/// If a diff node is about changes between two reference types, get
13561/// the diff node about changes between the underlying (pointed-to)
13562/// types.
13563///
13564/// Note that this function walks the tree of underlying diff nodes
13565/// returns the first diff node about types that are not references.
13566///
13567/// @param dif the dif node to consider.
13568///
13569/// @return the underlying diff node of @p dif, or just return @p dif
13570/// if it's not a reference diff node.
13571const diff*
13573{
13574 const reference_diff *d = 0;
13575 while ((d = is_reference_diff(dif)))
13576 dif = d->underlying_type_diff().get();
13577 return dif;
13578}
13579
13580/// If a diff node is about changes between two qualified types, get
13581/// the diff node about changes between the underlying (non-qualified)
13582/// types.
13583///
13584/// Note that this function walks the tree of underlying diff nodes
13585/// returns the first diff node about types that are not qualified.
13586///
13587/// @param dif the dif node to consider.
13588///
13589/// @return the underlying diff node of @p dif, or just return @p dif
13590/// if it's not a qualified diff node.
13591const diff*
13593{
13594 const qualified_type_diff *d = 0;
13595 while ((d = is_qualified_type_diff(dif)))
13596 dif = d->underlying_type_diff().get();
13597 return dif;
13598}
13599
13600/// If a diff node is about changes between two function parameters
13601/// get the diff node about changes between the types of the parameters.
13602///
13603/// @param dif the dif node to consider.
13604///
13605/// @return the diff of the types of the parameters.
13606const diff*
13608{
13609 const fn_parm_diff *d = 0;
13610 while ((d = is_fn_parm_diff(dif)))
13611 dif = d->type_diff().get();
13612 return dif;
13613}
13614
13615/// If a diff node is about changes between two pointer, reference or
13616/// qualified types, get the diff node about changes between the
13617/// underlying types.
13618///
13619/// Note that this function walks the tree of underlying diff nodes
13620/// returns the first diff node about types that are not pointer,
13621/// reference or qualified.
13622///
13623/// @param dif the dif node to consider.
13624///
13625/// @return the underlying diff node of @p dif, or just return @p dif
13626/// if it's not a pointer, reference or qualified diff node.
13627const diff*
13629{
13630 while (true)
13631 {
13632 if (const pointer_diff *d = is_pointer_diff(dif))
13633 dif = peel_pointer_diff(d);
13634 else if (const reference_diff *d = is_reference_diff(dif))
13635 dif = peel_reference_diff(d);
13636 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13637 dif = peel_qualified_diff(d);
13638 else
13639 break;
13640 }
13641 return dif;
13642}
13643
13644/// If a diff node is about changes between two typedefs or qualified
13645/// types, get the diff node about changes between the underlying
13646/// types.
13647///
13648/// Note that this function walks the tree of underlying diff nodes
13649/// returns the first diff node about types that are not typedef or
13650/// qualified types.
13651///
13652/// @param dif the dif node to consider.
13653///
13654/// @return the underlying diff node of @p dif, or just return @p dif
13655/// if it's not typedef or qualified diff node.
13656const diff*
13658{
13659 while (true)
13660 {
13661 if (const typedef_diff *d = is_typedef_diff(dif))
13662 dif = peel_typedef_diff(d);
13663 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13664 dif = peel_qualified_diff(d);
13665 else
13666 break;
13667 }
13668 return dif;
13669}
13670
13671/// If a diff node is about changes between two typedefs or qualified
13672/// types, get the diff node about changes between the underlying
13673/// types.
13674///
13675/// Note that this function walks the tree of underlying diff nodes
13676/// returns the first diff node about types that are neither typedef,
13677/// qualified type nor parameters.
13678///
13679/// @param dif the dif node to consider.
13680///
13681/// @return the diff node about changes between the underlying types.
13682const diff*
13684{
13685 while (true)
13686 {
13687 if (const typedef_diff *d = is_typedef_diff(dif))
13688 dif = peel_typedef_diff(d);
13689 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13690 dif = peel_qualified_diff(d);
13691 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
13692 dif = peel_fn_parm_diff(d);
13693 else
13694 break;
13695 }
13696 return dif;
13697}
13698
13699/// Test if a diff node represents a diff between two class or union
13700/// types.
13701///
13702/// @param d the diff node to consider.
13703///
13704/// @return iff @p is a diff between two class or union types then
13705/// return the instance of @ref class_or_union_diff that @p derives
13706/// from. Otherwise, return nil.
13709{return dynamic_cast<const class_or_union_diff*>(d);}
13710
13711/// Test if a given diff node carries *only* a local type change.
13712///
13713/// @param d the diff node to consider.
13714///
13715/// @return true iff @p has a change and that change is a local type
13716/// change.
13717static bool
13718has_local_type_change_only(const diff *d)
13719{
13720 if (enum change_kind k = d->has_local_changes())
13721 if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
13722 && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
13723 return true;
13724
13725 return false;
13726}
13727
13728/// Test if a diff node is a decl diff that only carries a basic type
13729/// change on its type diff sub-node.
13730///
13731///Note that that pointers/references/qualified types diffs to basic
13732/// type diffs are considered as having basic type change only.
13733///
13734/// @param d the diff node to consider.
13735///
13736/// @return true iff @p d is a decl diff that only carries a basic
13737/// type change on its type diff sub-node.
13738bool
13740{
13742
13743 if (is_diff_of_basic_type(d, true) && d->has_changes())
13744 return true;
13745 else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
13746 return (has_local_type_change_only(v)
13747 && is_diff_of_basic_type(v->type_diff().get(), true));
13748 else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
13749 return (has_local_type_change_only(p)
13750 && is_diff_of_basic_type(p->type_diff().get(), true));
13751 else if (const function_decl_diff* f =
13752 dynamic_cast<const function_decl_diff*>(d))
13753 return (has_local_type_change_only(f)
13754 && f->type_diff()
13755 && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
13756 true));
13757 return false;
13758}
13759}// end namespace comparison
13760} // 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:1714
#define ABG_ASSERT_NOT_REACHED
A macro that expands to aborting the program when executed.
The abstraction of a diff between two arrays.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of array_diff.
const diff_sptr & element_type_diff() const
Getter for the diff between the two types of array elements.
array_diff(const array_type_def_sptr first, const array_type_def_sptr second, diff_sptr element_type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for array_diff.
const array_type_def_sptr second_array() const
Getter for the second array of the diff.
const array_type_def_sptr first_array() const
Getter for the first array of the diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
An abstraction of a diff between two instances of class_decl::base_spec.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of base_diff.
void set_underlying_class_diff(class_diff_sptr d)
Setter for the diff object for the diff of the underlyng base classes.
class_decl::base_spec_sptr second_base() const
Getter for the second base spec of the diff object.
base_diff(class_decl::base_spec_sptr first, class_decl::base_spec_sptr second, class_diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
const class_diff_sptr get_underlying_class_diff() const
Getter for the diff object for the diff of the underlying base classes.
class_decl::base_spec_sptr first_base() const
Getter for the first base spec of the diff object.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Generates a report for the current instance of base_diff.
This type abstracts changes for a class_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_diff.
class_decl_sptr first_class_decl() const
const base_diff_sptrs_type & changed_bases()
Getter for the changed base classes of the diff.
const vector< class_decl::base_spec_sptr > & moved_bases() const
Getter for the vector of bases that "moved". That is, the vector of base types which position changed...
const string_base_sptr_map & inserted_bases() const
Getter for the inserted base classes of the diff.
const string_base_sptr_map & deleted_bases() const
Getter for the deleted base classes of the diff.
virtual enum change_kind has_local_changes() const
const edit_script & base_changes() const
virtual const string & get_pretty_representation() const
class_diff(class_decl_sptr first_scope, class_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor of class_diff.
friend class_diff_sptr compute_diff(const class_decl_sptr first, const class_decl_sptr second, diff_context_sptr ctxt)
Compute the set of changes between two instances of class_decl.
class_decl_sptr second_class_decl() const
Getter of the second class involved in the diff.
virtual void report(ostream &, const string &indent="") const
Produce a basic report about the changes between two class_decl.
This is the base class of class_diff and union_diff.
virtual bool has_changes() const
Test if the current diff node carries a change.
const edit_script & member_fn_tmpls_changes() const
size_t count_filtered_subtype_changed_data_members(bool local_only=false) const
Count the number of /filtered/ data members with a sub-type change.
const class_or_union_diff::priv_ptr & get_priv() const
Getter of the private data of the class_or_union_diff type.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_or_un...
const edit_script & member_class_tmpls_changes() const
void allocate_priv_data()
Allocate the memory for the priv_ pimpl data member of the class_or_union_diff class.
class_or_union_diff(class_or_union_sptr first_scope, class_or_union_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the class_or_union_diff class.
const 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 net_num_leaf_var_changes() const
Getter for the net number of leaf variable change diff nodes.
size_t num_vars_added() const
Getter for the number of variables added.
size_t num_removed_unreachable_types() const
Getter of the number of removed types that are unreachable from the public interface of the ABI corpu...
size_t num_changed_vars_filtered_out() const
Getter for the number of variables that have a change in one of their sub-types, and that have been f...
size_t num_changed_func_filtered_out() const
Getter for the number of functions that have a change in one of their sub-types, and that have been f...
size_t num_removed_vars_filtered_out() const
Getter for the number removed variables that have been filtered out.
size_t net_num_func_changed() const
Getter for the number of functions that have a change in their sub-types, minus the number of these f...
size_t net_num_vars_removed() const
Getter for the net number of removed variables.
size_t net_num_added_unreachable_types() const
Getter of the number of added types that are unreachable from public interfaces and that are *NOT* fi...
size_t num_removed_var_syms_filtered_out() const
Getter for the number of removed variable symbols, not referenced by any debug info,...
size_t net_num_added_func_syms() const
Getter of the net number of added function symbols that are not referenced by any debug info.
size_t num_added_var_syms_filtered_out() const
Getter for the number of added variable symbols, not referenced by any debug info,...
size_t num_added_unreachable_types() const
Getter of the number of added types that are unreachable from the public interface of the ABI corpus.
size_t net_num_removed_func_syms() const
Getter of the net number of removed function symbols that are not referenced by any debug info.
size_t num_var_syms_added() const
Getter for the number of variable symbols (not referenced by any debug info) that got added.
size_t num_leaf_var_changes() const
Getter for the number of leaf variable change diff nodes.
size_t net_num_removed_var_syms() const
Getter of the net number of removed variable symbols that are not referenced by any debug info.
size_t net_num_func_removed() const
Getter for the net number of function removed.
size_t net_num_func_added() const
Getter for the net number of added functions.
size_t net_num_removed_unreachable_types() const
Getter of the number of removed types that are not reachable from public interfaces and that have *NO...
size_t net_num_leaf_changes() const
Getter of the net number of leaf change diff nodes.
size_t num_removed_func_syms_filtered_out() const
Getter for the number of removed function symbols, not referenced by debug info, that have been filte...
size_t num_added_unreachable_types_filtered_out() const
Getter of the number of added types that are unreachable from public interfaces and that are filtered...
size_t num_added_func_filtered_out() const
Getter for the number of added function that have been filtered out.
size_t num_func_syms_added() const
Getter for the number of function symbols (not referenced by any debug info) that got added.
size_t net_num_leaf_type_changes() const
Getter for the net number of leaf type change diff nodes.
size_t num_func_added() const
Getter for the number of functions added.
size_t net_num_added_var_syms() const
Getter of the net number of added variable symbols that are not referenced by any debug info.
size_t num_leaf_type_changes() const
Getter for the number of leaf type change diff nodes.
size_t num_leaf_var_changes_filtered_out() const
Getter for the number of leaf variable changes diff nodes that have been filtered out.
size_t num_added_vars_filtered_out() const
Getter for the number of added variables that have been filtered out.
size_t num_func_with_virtual_offset_changes() const
Getter for the number of functions that carry virtual member offset changes.
size_t num_func_changed() const
Getter for the number of functions that have a change in one of their sub-types.
size_t num_removed_func_filtered_out() const
Getter for the number of removed functions that have been filtered out.
size_t net_num_vars_added() const
Getter for the net number of added variables.
size_t num_leaf_changes() const
Getter of the number of leaf type change diff nodes.
size_t num_leaf_func_changes_filtered_out() const
Getter for the number of leaf function change diff nodes that were filtered out.
size_t num_added_func_syms_filtered_out() const
Getter for the number of added function symbols, not referenced by any debug info,...
size_t num_leaf_type_changes_filtered_out() const
Getter for the number of filtered out leaf type change diff nodes.
size_t num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from the public interface of the ABI corpu...
size_t net_num_leaf_func_changes() const
Getter for the net number of leaf function change diff nodes.
size_t num_leaf_func_changes() const
Getter for the number of leaf function change diff nodes.
size_t net_num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from public interfaces and that have *NOT*...
size_t num_func_syms_removed() const
Getter for the number of function symbols (not referenced by any debug info) that got removed.
size_t num_leaf_changes_filtered_out() const
Getter of the number of leaf type change diff nodes that have been filtered out.
size_t num_vars_removed() const
Getter for the number of variables removed.
size_t num_var_syms_removed() const
Getter for the number of variable symbols (not referenced by any debug info) that got removed.
size_t net_num_vars_changed() const
Getter for the number of variables that have a change in their sub-types, minus the number of these v...
An abstraction of a diff between between two abi corpus.
bool has_incompatible_changes() const
Test if the current instance of corpus_diff carries changes that we are sure are incompatible....
bool has_changes() const
Return true iff the current corpus_diff node carries a change.
void finish_diff_type()
Finish building the current instance of corpus_diff.
virtual void chain_into_hierarchy()
Populate the vector of children node of the corpus_diff type.
const string_var_ptr_map & deleted_variables() const
Getter for the variables that got deleted from the first subject of the diff.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Getter of a sorted vector of changed types that are not reachable from global functions/variables.
bool soname_changed() const
Test if the soname of the underlying corpus has changed.
friend corpus_diff_sptr compute_diff(const corpus_sptr f, const corpus_sptr s, diff_context_sptr ctxt)
Compute the diff between two instances of corpus.
const vector< type_base_sptr > & deleted_unreachable_types_sorted() const
Getter of a sorted vector of deleted types that are not reachable from global functions/variables.
edit_script & function_changes() const
edit_script & variable_changes() const
const vector< diff * > & children_nodes() const
const string_diff_sptr_map & changed_unreachable_types() const
Getter for a map of changed types that are not reachable from global functions/variables.
const var_diff_sptrs_type & changed_variables_sorted()
Getter for the sorted vector of variables which signature didn't change but which do have some indire...
const string_elf_symbol_map & deleted_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got deleted.
const string_elf_symbol_map & deleted_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got deleted.
corpus_diff(corpus_sptr first, corpus_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for corpus_diff.
bool do_log() const
Test if logging was requested.
const string_elf_symbol_map & added_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got added.
bool has_net_subtype_changes() const
Test if the current instance of corpus_diff carries subtype changes whose reports are not suppressed ...
const string_var_ptr_map & added_variables() const
Getter for the added variables of the diff.
diff_maps & get_leaf_diffs()
Get the set of maps that contain leaf nodes. A leaf node being a node with a local change.
const diff_context_sptr context() const
Getter of the diff context of this diff.
bool has_net_changes() const
Test if the current instance of corpus_diff carries changes whose reports are not suppressed by any s...
virtual bool traverse(diff_node_visitor &v)
Traverse the diff sub-tree under the current instance corpus_diff.
const diff_stats & apply_filters_and_suppressions_before_reporting()
Apply the different filters that are registered to be applied to the diff tree; that includes the cat...
const string_var_diff_sptr_map & changed_variables()
Getter for the non-sorted map of variables which signature didn't change but which do have some indir...
const string_function_ptr_map & added_functions()
Getter for the added functions of the diff.
void mark_leaf_diff_nodes()
Walks the diff nodes associated to the current corpus diff and mark those that carry local changes....
const string_type_base_sptr_map & deleted_unreachable_types() const
Getter for a map of deleted types that are not reachable from global functions/variables.
const vector< type_base_sptr > & added_unreachable_types_sorted() const
Getter of a sorted vector of added types that are not reachable from global functions/variables.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
const string_elf_symbol_map & added_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got added.
const function_decl_diff_sptrs_type & changed_functions_sorted()
Getter for a sorted vector of functions which signature didn't change, but which do have some indirec...
const string & get_pretty_representation() const
const string_function_ptr_map & deleted_functions() const
Getter for the deleted functions of the diff.
void append_child_node(diff_sptr)
Append a new child node to the vector of children nodes for the current instance of corpus_diff node.
friend void apply_suppressions(const corpus_diff *diff_tree)
Walk a corpus_diff tree and appply the suppressions carried by the context. If the suppression applie...
const string_type_base_sptr_map & added_unreachable_types() const
Getter for a map of added types that are not reachable from global functions/variables.
const string_function_decl_diff_sptr_map & changed_functions()
Getter for the functions which signature didn't change, but which do have some indirect changes in th...
bool architecture_changed() const
Test if the architecture of the underlying corpus has changed.
The base class of diff between decls.
decl_diff_base(decl_base_sptr first_subject, decl_base_sptr second_subject, diff_context_sptr ctxt)
Constructor of decl_diff_base.
The default, initial, reporter of the libabigail comparison engine.
Definition: abg-reporter.h:159
The context of the diff. This type holds various bits of information that is going to be used through...
void add_suppressions(const suppr::suppressions_type &supprs)
Add new suppression specifications that specify which diff node reports should be dropped on the floo...
diff_category get_allowed_category() const
Getter for the bitmap that represents the set of categories that the user wants to see reported.
void forget_visited_diffs()
Unmark all the diff nodes that were marked as being traversed.
corpus_sptr get_first_corpus() const
Getter for the first corpus of the corpus diff of the current context.
bool show_architecture_change() const
Getter for the property that says if the comparison module should show the architecture changes in it...
bool show_offsets_sizes_in_bits() const
Get the flag that indicates if diff reports using this context should show sizes and offsets in bits,...
void forbid_visiting_a_node_twice(bool f)
This sets a flag that, if it's true, then during the traversing of a diff nodes tree each node is vis...
void initialize_canonical_diff(const diff_sptr diff)
Set the canonical diff node property of a given diff node appropriately.
bool show_redundant_changes() const
A getter for the flag that says if we should report about functions or variables diff nodes that have...
void forbid_visiting_a_node_twice_per_interface(bool)
This function sets a flag os that if forbid_visiting_a_node_twice() returns true, then each time the ...
void keep_diff_alive(diff_sptr &)
Add a diff node to the set of diff nodes that are kept alive for the life time of the current instanc...
diff * diff_has_been_visited(const diff *) const
Test if a diff node has been traversed.
bool visiting_a_node_twice_is_forbidden_per_interface() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
void set_corpus_diff(const corpus_diff_sptr &)
Set the corpus diff relevant to this context.
bool show_leaf_changes_only() const
Get the flag that indicates if the diff using this context should show only leaf changes or not.
bool perform_change_categorization() const
Test if it's requested to perform diff node categorization.
bool show_impacted_interfaces() const
Getter of the flag that indicates if the leaf reporter should display a summary of the interfaces imp...
bool show_soname_change() const
Getter for the property that says if the comparison module should show the soname changes in its repo...
reporter_base_sptr get_reporter() const
Getter of the reporter to be used in this context.
void add_diff_filter(filtering::filter_base_sptr)
Setter for the diff filters to apply to a given diff sub-tree.
bool do_log() const
Test if logging was requested.
const suppr::suppressions_type & direct_suppressions() const
Getter of the direct suppression specification (those that are not negated) comprised in the general ...
void maybe_apply_filters(diff_sptr diff)
Apply the diff filters to a given diff sub-tree.
const suppr::suppressions_type & suppressions() const
Getter for the vector of suppressions that specify which diff node reports should be dropped on the f...
bool show_relative_offset_changes(void)
Get the flag saying if offset changes should be reported in a relative way. That is,...
bool visiting_a_node_twice_is_forbidden() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
void do_dump_diff_tree(const diff_sptr) const
Emit a textual representation of a diff tree to the error output stream of the current context,...
const suppr::suppressions_type & negated_suppressions() const
Getter of the negated suppression specifications that are comprised in the general vector of suppress...
void add_suppression(const suppr::suppression_sptr suppr)
Add a new suppression specification that specifies which diff node reports should be dropped on the f...
bool show_hex_values() const
Get the flag that indicates if the diff reports using this context should show sizes and offsets in a...
void switch_categories_off(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
bool show_stats_only() const
Test if the comparison module should only show the diff stats.
const filtering::filters & diff_filters() const
Getter for the diff tree nodes filters to apply to diff sub-trees.
bool show_unreachable_types()
Getter for the flag that indicates if changes on types unreachable from global functions and variable...
const corpus_diff_sptr & get_corpus_diff() const
Get the corpus diff for the current context.
void mark_diff_as_visited(const diff *)
Mark a diff node as traversed by a traversing algorithm.
diff_sptr get_canonical_diff_for(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second) const
Getter for the canonical diff node for the diff represented by their two subjects.
void switch_categories_on(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
ostream * default_output_stream()
Getter for the default output stream used by code of the comparison engine. By default the default ou...
bool dump_diff_tree() const
Test if the comparison engine should dump the diff tree for the changed functions and variables it ha...
bool show_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info are to be compared and...
bool show_added_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info and that got added are...
corpus_sptr get_second_corpus() const
Getter for the second corpus of the corpus diff of the current context.
void set_allowed_category(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
void set_reporter(reporter_base_sptr &)
Setter of the reporter to be used in this context.
ostream * error_output_stream() const
Getter for the errror output stream used by code of the comparison engine. By default the error outpu...
This type contains maps. Each map associates a type name to a diff of that type. Not all kinds of dif...
const string_diff_ptr_map & get_function_decl_diff_map() const
Getter of the map that contains function decl diffs.
const string_diff_ptr_map & get_var_decl_diff_map() const
Getter of the map that contains var decl diffs.
const string_diff_ptr_map & get_enum_diff_map() const
Getter of the map that contains enum type diffs.
bool insert_diff_node(const diff *d, const type_or_decl_base_sptr &impacted_iface)
Insert a new diff node into the current instance of diff_maps.
diff_maps()
Default constructor of the diff_maps type.
const string_diff_ptr_map & get_union_diff_map() const
Getter of the map that contains union type diffs.
artifact_sptr_set_type * lookup_impacted_interfaces(const diff *d) const
Lookup the interfaces that are impacted by a given leaf diff node.
const string_diff_ptr_map & get_function_type_diff_map() const
Getter of the map that contains function type diffs.
const string_diff_ptr_map & get_typedef_diff_map() const
Getter of the map that contains typedef type diffs.
const string_diff_ptr_map & get_distinct_diff_map() const
Getter of the map that contains distinct diffs.
const string_diff_ptr_map & get_subrange_diff_map() const
Getter of the map that contains subrange type diffs.
const string_diff_ptr_map & get_reference_diff_map() const
Getter of the map that contains reference type diffs.
const string_diff_ptr_map & get_array_diff_map() const
Getter of the map that contains array type diffs.
const string_diff_ptr_map & get_type_decl_diff_map() const
Getter of the map that contains basic type diffs.
const string_diff_ptr_map & get_fn_parm_diff_map() const
Getter of the map that contains function parameter diffs.
const string_diff_ptr_map & get_class_diff_map() const
Getter of the map that contains class type diffs.
The base class for the node visitors. These are the types used to visit each node traversed by the di...
void or_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor....
virtual bool visit(diff *, bool)
Default visitor implementation.
virtual bool visit(distinct_diff *, bool)
Default visitor implementation.
virtual void visit_end(corpus_diff *)
This is called by the traversing code on a corpus_diff node just after visiting it....
void set_current_topmost_iface_diff(diff *)
Setter of the diff current topmost interface which is impacted by the current diff node being visited...
virtual void visit_begin(diff *)
This is called by the traversing code on a diff node just before visiting it. That is,...
visiting_kind get_visiting_kind() const
Getter for the visiting policy of the traversing code while invoking this visitor.
virtual void visit_end(diff *)
This is called by the traversing code on a diff node just after visiting it. That is after visiting i...
diff_node_visitor()
Default constructor of the diff_node_visitor type.
void set_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor.
diff * get_current_topmost_iface_diff() const
Getter of the diff current topmost interface which is impacted by the current diff node being visited...
virtual bool traverse(diff_node_visitor &v)
The default traverse function.
The abstraction of a change between two ABI artifacts, a.k.a an artifact change.
void begin_traversing()
Flag a given diff node as being traversed.
void set_category(diff_category c)
Set the category of the current diff node. This category includes the categories inherited from the c...
virtual void finish_diff_type()
Finish the insertion of a diff tree node into the diff graph.
virtual void chain_into_hierarchy()
This constructs the relation between this diff node and its detail diff nodes, in the generic view of...
diff_category remove_from_category(diff_category c)
Remove the current diff tree node from an a existing sef of categories. The categories include those ...
type_or_decl_base_sptr second_subject() const
Getter of the second subject of the diff.
bool is_traversing() const
Tell if a given node is being traversed or not.
type_or_decl_base_sptr first_subject() const
Getter of the first subject of the diff.
bool is_suppressed() const
Test if the current diff node has been suppressed by a user-provided suppression specification.
bool is_filtered_out_without_looking_at_allowed_changes() const
Test if this diff tree node is to be filtered out for reporting purposes, but without considering the...
diff * get_canonical_diff() const
Getter for the canonical diff of the current instance of diff.
bool has_parent_allowed_by_specific_negated_suppression() const
Test if the current diff node has a parent node which is specifically allowed by a negated suppressio...
bool has_local_changes_to_be_reported() const
Test if this diff tree node should be reported when considering the categories that were *NOT* inheri...
const vector< diff * > & children_nodes() const
Getter for the children nodes of the current diff node.
diff_category get_category() const
Getter for the category of the current diff tree node.
bool is_allowed_by_specific_negated_suppression() const
Test if this diff node is allowed (prevented from being suppressed) by at least one negated suppressi...
diff_category remove_from_local_category(diff_category c)
Remove the current diff tree node from the categories resulting from the local changes.
void add_to_local_and_inherited_categories(diff_category c)
Adds the current diff tree node to the categories resulting from the local and inherited changes of t...
bool do_log() const
Test if logging was requested.
diff_category get_local_category() const
Getter for the local category of the current diff tree node.
diff_category add_to_category(diff_category c)
Adds the current diff tree node to an additional set of categories. Note that the categories include ...
const diff_context_sptr context() const
Getter of the context of the current diff.
virtual enum change_kind has_local_changes() const =0
Pure interface to know if the current instance of @diff carries a local change. A local change is a c...
virtual bool traverse(diff_node_visitor &v)
The generic traversing code that walks a given diff sub-tree.
bool currently_reporting() const
Tests if we are currently in the middle of emitting a report for this diff.
virtual bool has_changes() const =0
Pure interface to get the length of the changes encapsulated by this diff. A length of zero means tha...
bool has_descendant_allowed_by_specific_negated_suppression() const
Test if the current diff node has a descendant node which is specifically allowed by a negated suppre...
bool to_be_reported() const
Test if this diff tree node should be reported.
const diff * parent_node() const
Getter for the parent node of the current diff node.
diff_category get_class_of_equiv_category() const
Getter of the category of the class of equivalence of the current diff tree node.
void set_canonical_diff(diff *)
Setter for the canonical diff of the current instance of diff.
bool is_filtered_out_wrt_non_inherited_categories() const
Test if this diff tree node is to be filtered out for reporting purposes, but by considering only the...
diff_category add_to_local_category(diff_category c)
Adds the current diff tree node to the categories resulting from the local changes of the current dif...
void set_local_category(diff_category c)
Set the local category of the current diff node.
virtual const string & get_pretty_representation() const
Get a pretty representation of the current diff node.
void append_child_node(diff_sptr)
Add a new child node to the vector of children nodes for the current diff node.
bool is_filtered_out() const
Test if this diff tree node is to be filtered out for reporting purposes.
void end_traversing()
Flag a given diff node as not being traversed anymore.
bool reported_once() const
Tests if a report has already been emitted for the current diff.
An abstraction of a diff between entities that are of a different kind (disctinct).
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of @distinct_d...
const diff_sptr compatible_child_diff() const
Getter for the child diff of this distinct_diff instance.
distinct_diff(type_or_decl_base_sptr first, type_or_decl_base_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for distinct_diff.
static bool entities_are_of_distinct_kinds(type_or_decl_base_sptr first, type_or_decl_base_sptr second)
Test if the two arguments are of different kind, or that are both NULL.
virtual void report(ostream &out, const string &indent="") const
Emit a report about the current diff instance.
const type_or_decl_base_sptr first() const
Getter for the first subject of the diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const type_or_decl_base_sptr second() const
Getter for the second subject of the diff.
Abstraction of a diff between two enums.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of enum_diff.
enum_diff(const enum_type_decl_sptr, const enum_type_decl_sptr, const diff_sptr, diff_context_sptr ctxt=diff_context_sptr())
Constructor for enum_diff.
diff_sptr underlying_type_diff() const
const string_changed_enumerator_map & changed_enumerators() const
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const enum_type_decl_sptr first_enum() const
const string_enumerator_map & deleted_enumerators() const
const enum_type_decl_sptr second_enum() const
const string_enumerator_map & inserted_enumerators() const
virtual void report(ostream &, const string &indent="") const
Report the differences between the two enums.
A filter that walks the diff nodes tree and tags relevant diff nodes into categories considered to re...
Abstraction of a diff between two function parameters.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children nodes of the diff base type sub-object of this instance of fn_parm_di...
const function_decl::parameter_sptr first_parameter() const
Getter for the first subject of this diff node.
virtual enum change_kind has_local_changes() const
Check if the current diff node carries a local change.
virtual const string & get_pretty_representation() const
Build and return a textual representation of the current instance of fn_parm_diff.
const function_decl::parameter_sptr second_parameter() const
Getter for the second subject of this diff node.
diff_sptr type_diff() const
Getter for the diff representing the changes on the type of the function parameter involved in the cu...
virtual void report(ostream &, const string &indent="") const
Emit a textual report about the current fn_parm_diff instance.
Abstraction of a diff between two function_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_de...
const function_decl_sptr second_function_decl() const
function_decl_diff(const function_decl_sptr first, const function_decl_sptr second, diff_context_sptr ctxt)
Constructor for function_decl_diff.
virtual enum change_kind has_local_changes() const
const function_decl_sptr first_function_decl() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Serialize a report of the changes encapsulated in the current instance of function_decl_diff over to ...
Abstraction of a diff between two function types.
virtual bool has_changes() const
Test if the current diff node carries changes.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_ty...
const string_fn_parm_diff_sptr_map & subtype_changed_parms() const
Getter for the map of function parameter changes of the current diff.
const diff_sptr return_type_diff() const
Getter for the diff of the return types of the two function types of the current diff.
const string_parm_map & removed_parms() const
Getter for the map of parameters that got removed.
const string_parm_map & added_parms() const
Getter for the map of parameters that got added.
friend function_type_diff_sptr compute_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of function_type.
const vector< function_decl::parameter_sptr > & sorted_added_parms() const
Getter for the sorted vector of added parameters .
const function_type_sptr first_function_type() const
Getter for the first subject of the diff.
const function_type_sptr second_function_type() const
Getter for the second subject of the diff.
function_type_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Consutrctor of the function_type type.
virtual enum change_kind has_local_changes() const
Test if the current diff node carries local changes.
virtual const string & get_pretty_representation() const
Build and return a copy of a pretty representation of the current instance of function_type_diff.
const vector< function_decl::parameter_sptr > & sorted_deleted_parms() const
Getter for the sorted vector of deleted parameters.
virtual void report(ostream &, const string &indent="") const
Build and emit a textual report about the current function_type_diff instance.
A reporter that only reports leaf changes.
Definition: abg-reporter.h:281
The abstraction of a diff between two pointers.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const pointer_type_def_sptr first_pointer() const
Getter for the first subject of a pointer diff.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of pointer_dif...
const pointer_type_def_sptr second_pointer() const
Getter for the second subject of a pointer diff.
diff_sptr underlying_type_diff() const
Getter for the diff between the pointed-to types of the pointers of this diff.
pointer_diff(pointer_type_def_sptr first, pointer_type_def_sptr second, diff_sptr underlying_type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for a pointer_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
The abstraction of a diff between two ptr_to_mbr_type.
virtual bool has_changes() const
Test whether the current diff node carries any change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of ptr_to_mbr_...
virtual ~ptr_to_mbr_diff()
Destructor of ptr_to_mbr_diff.
ptr_to_mbr_type_sptr first_ptr_to_mbr_type() const
Getter of the first pointer-to-member subject of the current diff node.
const diff_sptr containing_type_diff() const
Getter of the diff node carrying changes to the containing type of first subject of the current diff ...
const diff_sptr member_type_diff() const
Getter of the diff node carrying changes to the member type of first subject of the current diff node...
ptr_to_mbr_type_sptr second_ptr_to_mbr_type() const
Getter of the second pointer-to-member subject of the current diff node.
virtual enum change_kind has_local_changes() const
Test whether the current diff node carries any local change.
virtual const string & get_pretty_representation() const
Get the pretty representation of the current ptr_to_mbr_diff node.
virtual void report(ostream &, const string &indent="") const
Pure interface to report the diff in a serialized form that is legible for the user.
Abstraction of a diff between two qualified types.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of qualified_t...
diff_sptr leaf_underlying_type_diff() const
Getter for the diff between the most underlying non-qualified types of two qualified types.
diff_sptr underlying_type_diff() const
Getter for the diff between the underlying types of the two qualified types.
qualified_type_diff(qualified_type_def_sptr first, qualified_type_def_sptr second, diff_sptr underling, diff_context_sptr ctxt=diff_context_sptr())
Constructor for qualified_type_diff.
const qualified_type_def_sptr second_qualified_type() const
Getter for the second qualified type of the diff.
virtual enum change_kind has_local_changes() const
const qualified_type_def_sptr first_qualified_type() const
Getter for the first qualified type of the diff.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
The abstraction of a diff between two references.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of reference_d...
reference_type_def_sptr first_reference() const
Getter for the first reference of the diff.
reference_type_def_sptr second_reference() const
Getter for the second reference of the diff.
reference_diff(const reference_type_def_sptr first, const reference_type_def_sptr second, diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
Constructor for reference_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const diff_sptr & underlying_type_diff() const
Getter for the diff between the two referred-to types.
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
An abstractions of the changes between two scopes.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of scope_diff.
const diff_sptrs_type & changed_types() const
const scope_decl_sptr second_scope() const
Getter for the second scope of the diff.
const scope_decl_sptr first_scope() const
Getter for the first scope of the diff.
const decl_base_sptr deleted_member_at(unsigned index) const
Accessor that eases the manipulation of the edit script associated to this instance....
const diff_sptrs_type & changed_decls() const
scope_diff(scope_decl_sptr first_scope, scope_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for scope_diff.
friend scope_diff_sptr compute_diff(const scope_decl_sptr first, const scope_decl_sptr second, scope_diff_sptr d, diff_context_sptr ctxt)
Compute the diff between two scopes.
const decl_base_sptr inserted_member_at(unsigned i)
Accessor that eases the manipulation of the edit script associated to this instance....
virtual void report(ostream &out, const string &indent="") const
Report the changes of one scope against another.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const edit_script & member_changes() const
Accessor of the edit script of the members of a scope.
The abstraction of the diff between two subrange types.
virtual bool has_changes() const
Test if the current subrange_diff node carries any change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of subrange_di...
const array_type_def::subrange_sptr second_subrange() const
Getter of the second subrange of the current instance subrange_diff.
subrange_diff(const array_type_def::subrange_sptr &first, const array_type_def::subrange_sptr &second, const diff_sptr &underlying_type_diff, const diff_context_sptr ctxt=diff_context_sptr())
Constructor of the subrange_diff diff node type.
const array_type_def::subrange_sptr first_subrange() const
Getter of the first subrange of the current instance subrange_diff.
const diff_sptr underlying_type_diff() const
Getter of the diff node of the underlying types of the current subrange_diff diff node.
virtual enum change_kind has_local_changes() const
Test if the current subrange_diff node carries any local change.
virtual const string & get_pretty_representation() const
Getter the pretty representation of the subrange_diff diff node.
virtual void report(ostream &, const string &indent="") const
Report about the changes carried by this node.
An abstraction of a diff between two translation units.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const translation_unit_sptr second_translation_unit() const
Getter for the second translation unit of this diff.
translation_unit_diff(translation_unit_sptr first, translation_unit_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for translation_unit_diff.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
virtual enum change_kind has_local_changes() const
const translation_unit_sptr first_translation_unit() const
Getter for the first translation unit of this diff.
Abstraction of a diff between two basic type declarations.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const type_decl_sptr first_type_decl() const
Getter for the first subject of the type_decl_diff.
const type_decl_sptr second_type_decl() const
Getter for the second subject of the type_decl_diff.
virtual void report(ostream &out, const string &indent="") const
Ouputs a report of the differences between of the two type_decl involved in the type_decl_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
The base class of diff between types.
Abstraction of a diff between two typedef_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of typedef_dif...
const typedef_decl_sptr second_typedef_decl() const
Getter for the second typedef_decl involved in the diff.
const typedef_decl_sptr first_typedef_decl() const
Getter for the firt typedef_decl involved in the diff.
const diff_sptr underlying_type_diff() const
Getter for the diff between the two underlying types of the typedefs.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Reports the difference between the two subjects of the diff in a serialized form.
union_diff(union_decl_sptr first_union, union_decl_sptr second_union, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the union_diff type.
union_decl_sptr first_union_decl() const
union_decl_sptr second_union_decl() const
virtual ~union_diff()
Destructor of the union_diff node.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current union_diff node in a textual format.
Abstracts a diff between two instances of var_decl.
virtual bool has_changes() const
Return true iff the diff node has a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of var_diff.
var_diff(var_decl_sptr first, var_decl_sptr second, diff_sptr type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for var_diff.
var_decl_sptr first_var() const
Getter for the first var_decl of the diff.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
virtual enum change_kind has_local_changes() const
friend var_diff_sptr compute_diff(const var_decl_sptr first, const var_decl_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of var_decl.
virtual const string & get_pretty_representation() const
diff_sptr type_diff() const
Getter for the diff of the types of the instances of var_decl.
var_decl_sptr second_var() const
Getter for the second var_decl of the diff.
The abstraction of an edit script for transforming a sequence A into a sequence B.
shared_ptr< subrange_type > subrange_sptr
Convenience typedef for a shared pointer on a function_decl::subrange.
Definition: abg-ir.h:2537
shared_ptr< base_spec > base_spec_sptr
Convenience typedef.
Definition: abg-ir.h:4251
vector< base_spec_sptr > base_specs
Convenience typedef.
Definition: abg-ir.h:4252
vector< method_decl_sptr > member_functions
Convenience typedef.
Definition: abg-ir.h:4062
bool get_is_anonymous() const
Test if the current declaration is anonymous.
Definition: abg-ir.cc:4653
The abstraction of the version of an ELF symbol.
Definition: abg-ir.h:1194
Abstraction of an elf symbol.
Definition: abg-ir.h:923
const string & get_id_string() const
Get a string that is representative of a given elf_symbol.
Definition: abg-ir.cc:2527
std::vector< enumerator > enumerators
Convenience typedef for a list of enumerator.
Definition: abg-ir.h:2766
Abstraction for a function declaration.
Definition: abg-ir.h:3111
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3135
const function_type_sptr get_type() const
Return the type of the current instance of function_decl.
Definition: abg-ir.cc:22049
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:22397
An abstraction helper for type declarations.
Definition: abg-ir.h:1973
The base class of both types and declarations.
Definition: abg-ir.h:1368
Abstracts a variable declaration.
Definition: abg-ir.h:3008
interned_string get_id() const
Return an ID that tries to uniquely identify the variable inside a program or a library.
Definition: abg-ir.cc:20784
change_kind
The kind of change the current function suppression should apply to.
@ ADDED_FUNCTION_CHANGE_KIND
The function was added to the second subject of the diff.
@ DELETED_FUNCTION_CHANGE_KIND
The function was deleted from the second subject of the diff.
change_kind
The kind of change the current variable suppression should apply to.
@ ADDED_VARIABLE_CHANGE_KIND
The variable was added to the second second subject of the diff.
@ DELETED_VARIABLE_CHANGE_KIND
The variable was deleted from the second subject of the diff.
A type used to time various part of the libabigail system.
bool stop()
Stop the timer.
bool start()
Start the timer.
std::vector< filter_base_sptr > filters
Convenience typedef for a vector of filter_base_sptr.
bool is_decl_only_class_with_size_change(const class_or_union &first, const class_or_union &second)
Test if two classes that are decl-only (have the decl-only flag and carry no data members) but are di...
shared_ptr< filter_base > filter_base_sptr
Convenience typedef for a shared pointer to filter_base.
bool has_harmful_name_change(const decl_base_sptr &f, const decl_base_sptr &s)
Test if two decls represents a harmful name change.
bool has_decl_only_def_change(const decl_base_sptr &first, const decl_base_sptr &second)
Test if two decl_base_sptr are different just by the fact that one is decl-only and the other one is ...
bool has_basic_or_class_type_name_change(const diff *d)
Test if a diff node carries a basic or class type name change.
void apply_filter(filter_base &filter, corpus_diff_sptr d)
Walk the diff sub-trees of a a corpus_diff and apply a filter to the nodes visted....
bool is_mostly_distinct_diff(const diff *d)
Test if a diff node carries a distinct type change or a pointer/reference/typedef to distinct type ch...
shared_ptr< diff > diff_sptr
Convenience typedef for a shared_ptr for the diff class.
Definition: abg-fwd.h:79
visiting_kind operator~(visiting_kind l)
The overloaded 'bit inversion' operator for visiting_kind.
const decl_diff_base * is_decl_diff(const diff *diff)
Test if a diff node is about differences between declarations.
const diff * peel_qualified_diff(const diff *dif)
If a diff node is about changes between two qualified types, get the diff node about changes between ...
const diff * peel_pointer_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two pointer, reference or qualified types,...
void categorize_redundancy(diff *diff_tree)
Walk a given diff sub-tree to categorize each of the nodes with respect to the REDUNDANT_CATEGORY.
vector< diff * > diff_ptrs_type
Convenience typedef for a vector of diff*.
void sort_string_diff_ptr_map(const string_diff_ptr_map &map, diff_ptrs_type &sorted)
Sort a map ofg string -> diff* into a vector of diff_ptr. The diff_ptr are sorted lexicographically w...
diff_category
An enum for the different categories that a diff tree node falls into, regarding the kind of changes ...
@ ACCESS_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries access related changes,...
@ HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless data member change....
@ SUPPRESSED_CATEGORY
This means that a diff node was marked as suppressed by a user-provided suppression specification.
@ VIRTUAL_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an incompatible change to a vtable.
@ REDUNDANT_CATEGORY
A diff node in this category is redundant. That means it's present as a child of a other nodes in the...
@ SIZE_OR_OFFSET_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries a change that modifies the...
@ NON_VIRT_MEM_FUN_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a non-virtual member fu...
@ HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
A diff node in this category has a descendant node that is in the HAS_ALLOWED_CHANGE_CATEGORY categor...
@ HARMLESS_ENUM_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition of enumerator to an enum type.
@ FN_PARM_ADD_REMOVE_CHANGE_CATEGORY
A diff node in this category is a function (or function type) with at least one parameter added or re...
@ VOID_PTR_TO_PTR_CHANGE_CATEGORY
A diff node in this category carries a change from void pointer to non-void pointer.
@ PRIVATE_TYPE_CATEGORY
This means that a diff node was warked as being for a private type. That is, the diff node is meant t...
@ COMPATIBLE_TYPE_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries a change involving two com...
@ TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a type that was declaration-only and that is now ...
@ STATIC_DATA_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a static data member.
@ HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless union or class change.
@ HARMLESS_DECL_NAME_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless declaration name change....
@ NO_CHANGE_CATEGORY
This means the diff node does not carry any (meaningful) change, or that it carries changes that have...
@ HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
A diff node in this category has a parent node that is in the HAS_ALLOWED_CHANGE_CATEGORY category....
@ BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY
A diff node in this category carries a change in the size of the array type of a global variable,...
@ VAR_TYPE_CV_CHANGE_CATEGORY
A diff node in this category is for a variable which type holds a cv-qualifier change.
@ HAS_ALLOWED_CHANGE_CATEGORY
A diff node in this category carries a change that must be reported, even if the diff node is also in...
@ FN_PARM_TYPE_CV_CHANGE_CATEGORY
A diff node in this category has a function parameter type with a cv-qualifiers change.
@ FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
A diff node in this category is a function parameter type which top cv-qualifiers change.
@ FN_RETURN_TYPE_CV_CHANGE_CATEGORY
A diff node in this category is a function return type with a cv-qualifier change.
@ HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an a symbol alias change that is harmless.
shared_ptr< reporter_base > reporter_base_sptr
A convenience typedef for a shared pointer to a reporter_base.
Definition: abg-reporter.h:54
void sort_string_var_diff_sptr_map(const string_var_diff_sptr_map &map, var_diff_sptrs_type &sorted)
Sort of an instance of string_var_diff_sptr_map map.
unordered_map< string, var_diff_sptr > string_var_diff_sptr_map
Convenience typedef for a map whose key is a string and whose value is a changed variable of type var...
const class_or_union_diff * is_diff_of_class_or_union_type(const diff *d)
Test if a diff node represents a diff between two class or union types.
const 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.
diff_sptr try_to_diff< class_decl >(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
This is a specialization of try_to_diff() template to diff instances of class_decl.
shared_ptr< type_decl_diff > type_decl_diff_sptr
Convenience typedef for a shared pointer on a type_decl_diff type.
bool is_diff_of_variadic_parameter(const diff *d)
Test if a diff node represents the difference between a variadic parameter and something else.
shared_ptr< diff_context > diff_context_sptr
Convenience typedef for a shared pointer of diff_context.
Definition: abg-fwd.h:71
bool is_diff_of_global_decls(const diff *)
Tests if a given diff node is to represent the changes between two gobal decls.
shared_ptr< subrange_diff > subrange_diff_sptr
A convenience typedef for a shared pointer to subrange_diff type.
bool is_diff_of_variadic_parameter_type(const diff *d)
Test if a diff node represents the difference between a variadic parameter type and something else.
diff_category get_default_harmful_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmful.
unordered_map< string, function_decl::parameter_sptr > string_parm_map
Convenience typedef for a map which value is a function parameter. The key is the name of the functio...
unordered_map< string, enum_type_decl::enumerator > string_enumerator_map
Convenience typedef for a map which value is an enumerator. The key is the name of the enumerator.
shared_ptr< var_diff > var_diff_sptr
Convenience typedef for a shared pointer to a var_diff type.
unordered_map< string, method_decl_sptr > string_member_function_sptr_map
Convenience typedef for a hash map of strings and member functions.
const diff * peel_typedef_diff(const diff *dif)
If a diff node is about changes between two typedef types, get the diff node about changes between th...
shared_ptr< reference_diff > reference_diff_sptr
Convenience typedef for a shared pointer on a reference_diff type.
vector< base_diff_sptr > base_diff_sptrs_type
Convenience typedef for a vector of base_diff_sptr.
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.
unordered_map< string, const var_decl * > string_var_ptr_map
Convenience typedef for a map which key is a string and which value is a point to var_decl.
void sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map, var_diff_sptrs_type &sorted)
Sort the values of a unsigned_var_diff_sptr_map map and store the result into a vector of var_diff_sp...
void sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map &map, vector< fn_parm_diff_sptr > &sorted)
Sort a map of fn_parm_diff by the indexes of the function parameters.
bool is_child_node_of_base_diff(const diff *diff)
Test if a diff node is a child node of a base diff node.
visiting_kind
An enum for the different ways to visit a diff tree node.
@ SKIP_CHILDREN_VISITING_KIND
This says that the traversing code should avoid visiting the children nodes of the current node being...
@ DO_NOT_MARK_VISITED_NODES_AS_VISITED
This says that the traversing code should not mark visited nodes as having been traversed....
visiting_kind operator&(visiting_kind l, visiting_kind r)
The overloaded and operator for visiting_kind.
const diff * peel_fn_parm_diff(const diff *dif)
If a diff node is about changes between two function parameters get the diff node about changes betwe...
const function_type_diff * is_function_type_diff(const diff *diff)
Test if a diff node is a function_type_diff node.
const distinct_diff * is_distinct_diff(const diff *diff)
Test if a diff node is about differences between two diff nodes of different kinds.
unordered_map< string, changed_enumerator > string_changed_enumerator_map
Convenience typedef for a map which value is a changed enumerator. The key is the name of the changed...
visiting_kind operator|(visiting_kind l, visiting_kind r)
The overloaded or operator for visiting_kind.
const array_diff * is_array_diff(const diff *diff)
Test if a diff node is a array_diff node.
const diff * peel_reference_diff(const diff *dif)
If a diff node is about changes between two reference types, get the diff node about changes between ...
unordered_map< string, fn_parm_diff_sptr > string_fn_parm_diff_sptr_map
Convenience typedef for a map which value is a changed function parameter and which key is the name o...
string get_pretty_representation(diff *d)
Get a copy of the pretty representation of a diff node.
void sort_artifacts_set(const artifact_sptr_set_type &set, vector< type_or_decl_base_sptr > &sorted)
Sort the set of ABI artifacts contained in a artifact_sptr_set_type.
const class_or_union_diff * is_anonymous_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff between two anonymous classes or unions.
shared_ptr< base_diff > base_diff_sptr
Convenience typedef for a shared pointer to a base_diff type.
shared_ptr< scope_diff > scope_diff_sptr
Convenience typedef for a shared pointer on a scope_diff.
shared_ptr< class_diff > class_diff_sptr
Convenience typedef for a shared pointer on a class_diff type.
const base_diff * is_base_diff(const diff *diff)
Test if a diff node is about differences between two base class specifiers.
const fn_parm_diff * is_fn_parm_diff(const diff *diff)
Test if a diff node is about differences between two function parameters.
void sort_string_member_function_sptr_map(const string_member_function_sptr_map &map, class_or_union::member_functions &sorted)
Sort a map that's an instance of string_member_function_sptr_map and fill a vector of member function...
const union_diff * is_union_diff(const diff *diff)
Test if a diff node is a union_diff node.
vector< changed_var_sptr > changed_var_sptrs_type
Convenience typedef for a vector of @changed_var_sptr.gg381.
shared_ptr< pointer_diff > pointer_diff_sptr
Convenience typedef for a shared pointer on a pointer_diff type.
const diff * peel_pointer_diff(const diff *dif)
If a diff node is about changes between two pointer types, get the diff node about changes between th...
void apply_suppressions(diff *diff_tree)
Walk a given diff-sub tree and appply the suppressions carried by the context. If the suppression app...
void sort_string_parm_map(const string_parm_map &map, vector< function_decl::parameter_sptr > &sorted)
Sort a map of string -> function parameters.
void sort_string_type_base_sptr_map(string_type_base_sptr_map &map, vector< type_base_sptr > &sorted)
Sort a map of string to type_base_sptr entities.
const enum_diff * is_enum_diff(const diff *diff)
Test if a diff node is a enum_diff node.
unordered_map< string, base_diff_sptr > string_base_diff_sptr_map
Convenience typedef for a map of string and base_diff_sptr.
void sort_data_members(const string_decl_base_sptr_map &data_members, vector< decl_base_sptr > &sorted)
Sort a map of data members by the offset of their initial value.
const class_or_union_diff * is_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff node.
const corpus_diff * is_corpus_diff(const diff *diff)
Test if a diff node is a corpus_diff node.
const diff * get_typedef_diff_underlying_type_diff(const diff *diff)
Return the leaf underlying diff node of a typedef_diff node.
const typedef_diff * is_typedef_diff(const diff *diff)
Test if a diff node is a typedef_diff node.
unordered_map< unsigned, var_diff_sptr > unsigned_var_diff_sptr_map
Convenience typedef for a map whose key is an unsigned int and whose value is a changed variable of t...
type_base_sptr get_leaf_type(qualified_type_def_sptr t)
Return the first underlying type that is not a qualified type.
const diff * peel_typedef_qualified_type_or_parameter_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
bool is_less_than(const function_decl_diff &first, const function_decl_diff &second)
Compare two function_decl_diff for the purpose of sorting.
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.
void sort_string_var_ptr_map(const string_var_ptr_map &map, vector< const var_decl * > &sorted)
Sort a map of string -> pointer to var_decl.
const type_decl_diff * is_diff_of_basic_type(const diff *d)
Test if a diff node represents a diff between two basic types.
unordered_map< string, diff_sptr > string_diff_sptr_map
Convenience typedef for a map which value is a diff_sptr. The key of the map is the qualified name of...
unordered_map< const diff *, artifact_sptr_set_type, diff_hash, diff_equal > diff_artifact_set_map_type
A convenience typedef for an unordered_map which key is a diff* and which value is a artifact_sptr_se...
const qualified_type_diff * is_qualified_type_diff(const diff *diff)
Test if a diff node is about differences between two qualified types.
diff_sptr compute_diff(const decl_base_sptr first, const decl_base_sptr second, diff_context_sptr ctxt)
Compute the difference between two decls. The decls can represent either type declarations,...
unordered_map< string, diff * > string_diff_ptr_map
Convenience typedef for a map which value is a diff*. The key of the map is the qualified name of the...
void sort_string_base_diff_sptr_map(const string_base_diff_sptr_map &map, base_diff_sptrs_type &sorted)
Sort a map of string -> base_diff_sptr into a sorted vector of base_diff_sptr. The base_diff_sptr are...
void sort_changed_enumerators(const string_changed_enumerator_map &enumerators_map, changed_enumerators_type &sorted)
Sort a map of changed enumerators.
void print_diff_tree(diff *diff_tree, ostream &out)
Emit a textual representation of a diff sub-tree to an output stream.
vector< changed_enumerator > changed_enumerators_type
Convenience typedef for a vector of changed enumerators.
vector< function_decl_diff_sptr > function_decl_diff_sptrs_type
Convenience typedef for a vector of function_decl_diff_sptr.
bool is_child_node_of_function_parm_diff(const diff *diff)
Test if a diff node is a child node of a function parameter diff node.
void sort_string_virtual_member_function_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort an map of string -> virtual member function into a vector of virtual member functions....
shared_ptr< function_type_diff > function_type_diff_sptr
A convenience typedef for a shared pointer to function_type_type_diff.
const function_type_diff * is_function_type_diff_with_local_changes(const diff *diff)
Test if a given diff node carries a function type change with local changes.
const var_diff * is_var_diff(const diff *diff)
Test if a diff node is about differences between variables.
const type_diff_base * is_type_diff(const diff *diff)
Test if a diff node is about differences between types.
unordered_map< string, elf_symbol_sptr > string_elf_symbol_map
Convenience typedef for a map whose key is a string and whose value is an elf_symbol_sptr.
void sort_string_diff_sptr_map(const string_diff_sptr_map &map, diff_sptrs_type &sorted)
Sort a map ofg string -> diff_sptr into a vector of diff_sptr. The diff_sptr are sorted lexicographic...
const reference_diff * is_reference_diff(const diff *diff)
Test if a diff node is about differences between two references.
void sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map &map, var_diff_sptrs_type &sorted)
Sort the values of a string_var_diff_sptr_map and store the result in a vector of var_diff_sptr.
void apply_filters(corpus_diff_sptr diff_tree)
Apply the diff tree filters that have been associated to the context of the a given corpus_diff tree....
shared_ptr< distinct_diff > distinct_diff_sptr
Convenience typedef for a shared pointer to distinct_types_diff.
shared_ptr< corpus_diff > corpus_diff_sptr
A convenience typedef for a shared pointer to corpus_diff.
std::pair< var_decl_sptr, var_decl_sptr > changed_var_sptr
Convenience typedef for a pair of var_decl_sptr representing a var_decl change. The first member of t...
shared_ptr< typedef_diff > typedef_diff_sptr
Convenience typedef for a shared pointer on a typedef_diff type.
const diff * peel_typedef_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
void sort_enumerators(const string_enumerator_map &enumerators_map, enum_type_decl::enumerators &sorted)
Sort a map of enumerators by their value.
unordered_map< string, const function_decl * > string_function_ptr_map
Convenience typedef for a map which key is a string and which value is a pointer to decl_base.
ostream & operator<<(ostream &o, diff_category c)
Serialize an instance of diff_category to an output stream.
shared_ptr< translation_unit_diff > translation_unit_diff_sptr
Convenience typedef for a shared pointer on a translation_unit_diff type.
void compute_diff(RandomAccessOutputIterator a_base, RandomAccessOutputIterator a_begin, RandomAccessOutputIterator a_end, RandomAccessOutputIterator b_base, RandomAccessOutputIterator b_begin, RandomAccessOutputIterator b_end, vector< point > &lcs, edit_script &ses, int &ses_len)
Compute the longest common subsequence of two (sub-regions of) sequences as well as the shortest edit...
shared_ptr< reference_type_def > reference_type_def_sptr
Convenience typedef for a shared pointer on a reference_type_def.
Definition: abg-fwd.h:236
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc:6440
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:5561
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition: abg-fwd.h:270
unordered_set< type_or_decl_base_sptr, type_or_decl_hash, type_or_decl_equal > artifact_sptr_set_type
A convenience typedef for a hash set of type_or_decl_base_sptr.
Definition: abg-ir.h:550
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition: abg-ir.cc:10410
bool is_anonymous_data_member(const decl_base &d)
Test if a decl is an anonymous data member.
Definition: abg-ir.cc:5858
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:11742
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:888
change_kind
A bitfield that gives callers of abigail::ir::equals() some insight about how different two internal ...
Definition: abg-ir.h:1323
@ LOCAL_TYPE_CHANGE_KIND
This means that a given IR artifact has a local type change.
Definition: abg-ir.h:1327
@ ALL_LOCAL_CHANGES_MASK
Testing (anding) against this mask means that a given IR artifact has local differences,...
Definition: abg-ir.h:1338
@ 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:1332
bool is_user_defined_type(const type_base *t)
Test if a type is user-defined.
Definition: abg-ir.cc:5465
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:5801
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:10692
shared_ptr< array_type_def > array_type_def_sptr
Convenience typedef for a shared pointer on a array_type_def.
Definition: abg-fwd.h:245
string get_pretty_representation(const type_or_decl_base *tod, bool internal)
Build and return a copy of the pretty representation of an ABI artifact that could be either a type o...
Definition: abg-ir.cc:9201
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:10923
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:5728
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:194
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition: abg-fwd.h:211
shared_ptr< typedef_decl > typedef_decl_sptr
Convenience typedef for a shared pointer on a typedef_decl.
Definition: abg-fwd.h:168
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:10642
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:10253
const global_scope * get_global_scope(const decl_base &decl)
return the global scope as seen by a given declaration.
Definition: abg-ir.cc:8462
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition: abg-fwd.h:257
shared_ptr< ptr_to_mbr_type > ptr_to_mbr_type_sptr
Convenience typedef for a shared pointer to a ptr_to_mbr_type.
Definition: abg-fwd.h:240
shared_ptr< scope_decl > scope_decl_sptr
Convenience typedef for a shared pointer on a scope_decl.
Definition: abg-fwd.h:265
shared_ptr< type_or_decl_base > type_or_decl_base_sptr
A convenience typedef for a shared_ptr to type_or_decl_base.
Definition: abg-fwd.h:121
shared_ptr< translation_unit > translation_unit_sptr
Convenience typedef for a shared pointer on a translation_unit type.
Definition: abg-fwd.h:137
unordered_map< string, decl_base_sptr > string_decl_base_sptr_map
Convenience typedef for a map which key is a string and which value is a decl_base_sptr.
Definition: abg-fwd.h:158
bool equals(const decl_base &l, const decl_base &r, change_kind *k)
Compares two instances of decl_base.
Definition: abg-ir.cc:5112
shared_ptr< pointer_type_def > pointer_type_def_sptr
Convenience typedef for a shared pointer on a pointer_type_def.
Definition: abg-fwd.h:227
bool is_enumerator_present_in_enum(const enum_type_decl::enumerator &enr, const enum_type_decl &enom)
Test if a given enumerator is found present in an enum.
Definition: abg-ir.cc:19680
uint64_t get_absolute_data_member_offset(const var_decl &m)
Get the absolute offset of a data member.
Definition: abg-ir.cc:6259
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition: abg-ir.cc:6354
var_decl * is_var_decl(const type_or_decl_base *tod)
Tests if a declaration is a variable declaration.
Definition: abg-ir.cc:11586
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition: abg-ir.cc:10350
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition: abg-fwd.h:176
type_base_sptr strip_typedef(const type_base_sptr type)
Recursively returns the the underlying type of a typedef. The return type should not be a typedef of ...
Definition: abg-ir.cc:6717
uint64_t get_data_member_offset(const var_decl &m)
Get the offset of a data member.
Definition: abg-ir.cc:6170
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6627
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:6016
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:11445
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition: abg-ir.cc:10972
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition: abg-ir.cc:5599
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition: abg-ir.cc:10043
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:28173
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:9093
shared_ptr< type_decl > type_decl_sptr
Convenience typedef for a shared pointer on a type_decl.
Definition: abg-fwd.h:162
bool is_unique_type(const type_base_sptr &t)
Test if a type is unique in the entire environment.
Definition: abg-ir.cc:27768
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:11415
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:10944
bool is_at_global_scope(const decl_base &decl)
Tests whether a given declaration is at global scope.
Definition: abg-ir.cc:10183
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition: abg-ir.cc:5403
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:1658
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:1655
bool is_negated_suppression(const suppression_base &s)
Test if a suppression specification is a negated suppression.
Toplevel namespace for libabigail.
A comparison function for instances of base_diff.
A functor to compare instances of class_decl::base_spec.
A functor to compare two changed enumerators, based on their initial value.
size_t count_filtered_bases()
Count the number of bases classes whose changes got filtered out.
class_decl::base_spec_sptr base_has_changed(class_decl::base_spec_sptr) const
Test whether a given base class has changed. A base class has changed if it's in both in deleted *and...
The type of private data of class_or_union_diff.
size_t count_filtered_changed_dm(bool local_only=false)
Get the number of data member changes carried by the current diff node that were filtered out.
size_t count_filtered_subtype_changed_dm(bool local_only=false)
Get the number of data member sub-type changes carried by the current diff node that were filtered ou...
size_t get_deleted_non_static_data_members_number() const
Get the number of non static data members that were deleted.
size_t count_filtered_changed_mem_fns(const diff_context_sptr &)
Get the number of member functions changes carried by the current diff node that were filtered out.
decl_base_sptr subtype_changed_dm(decl_base_sptr) const
Test if the current diff node carries a data member change for a data member which name is the same a...
type_or_decl_base_sptr member_type_has_changed(decl_base_sptr) const
Test if the current diff node carries a member type change for a member type which name is the same a...
decl_base_sptr member_class_tmpl_has_changed(decl_base_sptr) const
Test if the current diff node carries a member class template change for a member class template whic...
size_t count_filtered_inserted_mem_fns(const diff_context_sptr &)
Get the number of member functions insertions carried by the current diff node that were filtered out...
size_t count_filtered_deleted_mem_fns(const diff_context_sptr &)
Get the number of member functions deletions carried by the current diff node that were filtered out.
size_t get_inserted_non_static_data_members_number() const
Get the number of non static data members that were inserted.
The type of the private data of corpus_diff::diff_stats.
bool added_unreachable_type_is_suppressed(const type_base *t) const
Test if an added type that is unreachable from public interface has been suppressed by a suppression ...
void ensure_lookup_tables_populated()
If the lookup tables are not yet built, walk the differences and fill the lookup tables.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Get the sorted vector of diff nodes representing changed unreachable types.
diff_context_sptr get_context()
Getter of the context associated with this corpus.
void categorize_redundant_changed_sub_nodes()
Walk the changed functions and variables diff nodes to categorize redundant nodes.
const string_diff_sptr_map & changed_unreachable_types() const
Get the map of diff nodes representing changed unreachable types.
bool added_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added variable symbol (that is not referenced by any debug inf...
bool lookup_tables_empty() const
Tests if the lookup tables are empty.
bool deleted_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted function symbol (that is not referenced by any debug i...
void apply_filters_and_compute_diff_stats(corpus_diff::diff_stats &)
Compute the diff stats.
bool added_variable_is_suppressed(const var_decl *var) const
Test if the change reports for a given added variable have been suppressed.
bool deleted_unreachable_type_is_suppressed(const type_base *t) const
Test if a deleted type that is unreachable from public interface has been suppressed by a suppression...
bool deleted_variable_is_suppressed(const var_decl *var) const
Test if the change reports for a give given deleted variable has been deleted.
bool deleted_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted variable symbol (that is not referenced by any debug i...
void maybe_dump_diff_tree()
If the user asked to dump the diff tree node (for changed variables and functions) on the error outpu...
void count_unreachable_types(size_t &num_added, size_t &num_removed, size_t &num_changed, size_t &num_filtered_added, size_t &num_filtered_removed, size_t &num_filtered_changed)
Count the number of types not reachable from the interface (i.e, not reachable from global functions ...
void clear_redundancy_categorization()
Walk the changed functions and variables diff nodes and clear the redundancy categorization they migh...
void count_leaf_changes(size_t &num_changes, size_t &num_filtered)
Count the number of leaf changes as well as the number of the changes that have been filtered out.
void count_leaf_type_changes(size_t &num_type_changes, size_t &num_type_changes_filtered)
Count the number of leaf *type* changes as well as the number of the leaf type changes that have been...
bool added_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added function symbol (that is not referenced by any debug inf...
bool deleted_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a given deleted function have been deleted.
void apply_supprs_to_added_removed_fns_vars_unreachable_types()
Apply suppression specifications for this corpus diff to the set of added/removed functions/variables...
void emit_diff_stats(const diff_stats &stats, ostream &out, const string &indent)
Emit the summary of the functions & variables that got removed/changed/added.
bool added_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a give given added function has been deleted.
void clear_lookup_tables()
Clear the lookup tables useful for reporting an enum_diff.
A comparison functor to compare two data members based on their offset.
A comparison functor to compare two instances of var_diff that represent changed data members based o...
A comparison functor for instances of diff.
A functor to compare two instances of diff_sptr.
The private data structure for distinct_diff.
A functor to compare instances of elf_symbol base on their names.
A functor to compare two enumerators based on their value. This implements the "less than" operator.
A comparison functor to compare two instances of fn_parm_diff based on their indexes.
"Less than" functor to compare instances of function_decl.
A "Less Than" functor to compare instance of function_decl_diff.
Functor that compares two function parameters for the purpose of sorting them.
The internal type for the impl idiom implementation of pointer_diff.
The 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:3245
A deleter for shared pointers that ... doesn't delete the object managed by the shared pointer.