libabigail
Loading...
Searching...
No Matches
abg-comparison.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2// -*- Mode: C++ -*-
3//
4// Copyright (C) 2013-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<var_decl_sptr>& 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 denoted
718/// by @p d iff @p is a pointer to an anonymous class or union diff.
721{
723 if (dif->first_class_or_union()->get_is_anonymous())
724 return dif;
725 return 0;
726}
727
728/// Test if a diff node is a @ref typedef_diff node.
729///
730/// @param diff the diff node to consider.
731///
732/// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
733/// @ref typedef_diff node.
734const typedef_diff*
736{return dynamic_cast<const typedef_diff*>(diff);}
737
738/// Test if a diff node is a @ref subrange_diff node.
739///
740/// @param diff the diff node to consider.
741///
742/// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
743/// @ref subrange_diff node.
744const subrange_diff*
746{return dynamic_cast<const subrange_diff*>(diff);}
747
748/// Test if a diff node is a @ref subrange_diff between two anonymous
749/// subranges.
750///
751/// @param d the diff node to consider.
752///
753/// @return a non-nil pointer to the @ref subrange_diff denoted by @p
754/// d iff @p d is a pointer to an anonymous @ref subrange_diff.
755const subrange_diff*
757{
758 if (const subrange_diff* dif = is_subrange_diff(d))
759 if (dif->first_subrange()->get_is_anonymous())
760 return dif;
761
762 return nullptr;
763}
764
765/// Test if a diff node is a @ref array_diff node.
766///
767/// @param diff the diff node to consider.
768///
769/// @return a non-nil pointer to a @ref array_diff iff @p diff is a
770/// @ref array_diff node.
771const array_diff*
773{return dynamic_cast<const array_diff*>(diff);}
774
775/// Test if a diff node is a @ref function_type_diff node.
776///
777/// @param diff the diff node to consider.
778///
779/// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
780/// @ref function_type_diff node.
783{return dynamic_cast<const function_type_diff*>(diff);}
784
785/// Test if a given diff node carries a function type change with
786/// local changes.
787///
788/// @param diff the diff node to consider.
789///
790/// @return a non-nil pointer to a @ref function_type_diff iff @p diff
791/// is a function_type_diff node that carries a local change.
794{
796 if (d->has_local_changes())
797 return d;
798
799 return 0;
800}
801
802/// Test if a diff node is about differences between variables.
803///
804/// @param diff the diff node to test.
805///
806/// @return a pointer to the actual var_diff that @p diff is a type
807/// of, iff it is about differences between variables.
808const var_diff*
810{
811 const var_diff* d = dynamic_cast<const var_diff*>(diff);
812 if (d)
814 return d;
815}
816
817/// Test if a diff node is about differences between functions.
818///
819/// @param diff the diff node to test.
820///
821/// @return a pointer to the actual var_diff that @p diff is a type
822/// of, iff it is about differences between variables.
825{
826 const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
827 if (d)
829 return d;
830}
831
832/// Test if a diff node is about differences between two pointers.
833///
834/// @param diff the diff node to consider.
835///
836/// @return the @p diff converted into an instance of @ref
837/// pointer_diff iff @p diff is about differences between two
838/// pointers.
839const pointer_diff*
841{return dynamic_cast<const pointer_diff*>(diff);}
842
843/// Test if a diff node is about differences between two references.
844///
845/// @param diff the diff node to consider.
846///
847/// @return the @p diff converted into an instance of @ref
848/// reference_diff iff @p diff is about differences between two
849/// references.
850const reference_diff*
852{return dynamic_cast<const reference_diff*>(diff);}
853
854/// Test if a diff node is about differences between two qualified
855/// types.
856///
857/// @param diff the diff node to consider.
858///
859/// @return @p diff converted into an instance of @ref
860/// qualified_type_diff iff @p diff is about differences between two
861/// qualified types.
864{return dynamic_cast<const qualified_type_diff*>(diff);}
865
866/// Test if a diff node is a reference or pointer diff node to a
867/// change that is neither basic type change nor distinct type change.
868///
869/// Note that this function also works on diffs of typedefs of
870/// reference or pointer.
871///
872/// @param diff the diff node to consider.
873///
874/// @return true iff @p diff is a eference or pointer diff node to a
875/// change that is neither basic type change nor distinct type change.
876bool
878{
880 if (const reference_diff* d = is_reference_diff(diff))
881 {
884 return false;
885 return true;
886 }
887 else if (const pointer_diff *d = is_pointer_diff(diff))
888 {
891 return false;
892 return true;
893 }
894
895 return false;
896}
897
898/// Test if a diff node is about differences between two function
899/// parameters.
900///
901/// @param diff the diff node to consider.
902///
903/// @return the @p diff converted into an instance of @ref
904/// reference_diff iff @p diff is about differences between two
905/// function parameters.
906const fn_parm_diff*
908{return dynamic_cast<const fn_parm_diff*>(diff);}
909
910/// Test if a diff node is about differences between two base class
911/// specifiers.
912///
913/// @param diff the diff node to consider.
914///
915/// @return the @p diff converted into an instance of @ref base_diff
916/// iff @p diff is about differences between two base class
917/// specifiers.
918const base_diff*
920{return dynamic_cast<const base_diff*>(diff);}
921
922/// Test if a diff node is about differences between two diff nodes of
923/// different kinds.
924///
925/// @param diff the diff node to consider.
926///
927/// @return the @p diff converted into an instance of @ref
928/// distintc_diff iff @p diff is about differences between two diff
929/// nodes of different kinds.
930const distinct_diff*
932{return dynamic_cast<const distinct_diff*>(diff);}
933
934/// Test if a diff node is a @ref corpus_diff node.
935///
936/// @param diff the diff node to consider.
937///
938/// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
939/// @ref corpus_diff node.
940const corpus_diff*
942{return dynamic_cast<const corpus_diff*>(diff);}
943
944/// Test if a diff node is a child node of a function parameter diff node.
945///
946/// @param diff the diff node to test.
947///
948/// @return true iff @p diff is a child node of a function parameter
949/// diff node.
950bool
953
954/// Test if a diff node is a child node of a base diff node.
955///
956/// @param diff the diff node to test.
957///
958/// @return true iff @p diff is a child node of a base diff node.
959bool
962
963/// The default traverse function.
964///
965/// @return true.
966bool
969
970diff_context::diff_context()
971 : priv_(new diff_context::priv)
972{
973 // Setup all the diff output filters we have.
975
977 add_diff_filter(f);
978
979 // f.reset(new filtering::harmless_filter);
980 // add_diff_filter(f);
981
982 // f.reset(new filtering::harmful_filter);
983 // add_diff_filter(f);
984}
985
986diff_context::~diff_context() = default;
987
988/// Test if logging was requested.
989///
990/// @return true iff logging was requested.
991bool
993{return priv_->do_log_;}
994
995/// Set logging as requested.
996///
997/// @param f the flag
998void
1000{priv_->do_log_ = f;}
1001
1002/// Set the corpus diff relevant to this context.
1003///
1004/// @param d the corpus_diff we are interested in.
1005void
1007{priv_->corpus_diff_ = d;}
1008
1009/// Get the corpus diff for the current context.
1010///
1011/// @return the corpus diff of this context.
1012const corpus_diff_sptr&
1014{return priv_->corpus_diff_;}
1015
1016/// Getter for the first corpus of the corpus diff of the current context.
1017///
1018/// @return the first corpus of the corpus diff of the current
1019/// context, if no corpus diff is associated to the context.
1020corpus_sptr
1022{
1023 if (priv_->corpus_diff_)
1024 return priv_->corpus_diff_->first_corpus();
1025 return corpus_sptr();
1026}
1027
1028/// Getter for the second corpus of the corpus diff of the current
1029/// context.
1030///
1031/// @return the second corpus of the corpus diff of the current
1032/// context, if no corpus diff is associated to the context.
1033corpus_sptr
1035{
1036 if (priv_->corpus_diff_)
1037 return priv_->corpus_diff_->second_corpus();
1038 return corpus_sptr();
1039}
1040
1041/// Getter of the reporter to be used in this context.
1042///
1043/// @return the reporter to be used in this context.
1046{
1047 if (!priv_->reporter_)
1048 {
1050 priv_->reporter_.reset(new leaf_reporter);
1051 else
1052 priv_->reporter_.reset(new default_reporter);
1053 }
1054 ABG_ASSERT(priv_->reporter_);
1055 return priv_->reporter_;
1056}
1057
1058/// Setter of the reporter to be used in this context.
1059///
1060/// @param r the reporter to be used in this context.
1061void
1063{priv_->reporter_ = r;}
1064
1065/// Tests if the current diff context already has a diff for two decls.
1066///
1067/// @param first the first decl to consider.
1068///
1069/// @param second the second decl to consider.
1070///
1071/// @return a pointer to the diff for @p first @p second if found,
1072/// null otherwise.
1074diff_context::has_diff_for(const type_or_decl_base_sptr first,
1075 const type_or_decl_base_sptr second) const
1076{
1077 types_or_decls_diff_map_type::const_iterator i =
1078 priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1079 if (i != priv_->types_or_decls_diff_map.end())
1080 return i->second;
1081 return diff_sptr();
1082}
1083
1084/// Tests if the current diff context already has a diff for two types.
1085///
1086/// @param first the first type to consider.
1087///
1088/// @param second the second type to consider.
1089///
1090/// @return a pointer to the diff for @p first @p second if found,
1091/// null otherwise.
1093diff_context::has_diff_for_types(const type_base_sptr first,
1094 const type_base_sptr second) const
1095{return has_diff_for(first, second);}
1096
1097/// Tests if the current diff context already has a given diff.
1098///
1099///@param d the diff to consider.
1100///
1101/// @return a pointer to the diff found for @p d
1102const diff*
1103diff_context::has_diff_for(const diff* d) const
1104{return has_diff_for(d->first_subject(), d->second_subject()).get();}
1105
1106/// Tests if the current diff context already has a given diff.
1107///
1108///@param d the diff to consider.
1109///
1110/// @return a pointer to the diff found for @p d
1112diff_context::has_diff_for(const diff_sptr d) const
1113{return has_diff_for(d->first_subject(), d->second_subject());}
1114
1115/// Getter for the bitmap that represents the set of categories that
1116/// the user wants to see reported.
1117///
1118/// @return a bitmap that represents the set of categories that the
1119/// user wants to see reported.
1120diff_category
1122{return priv_->allowed_category_;}
1123
1124/// Setter for the bitmap that represents the set of categories that
1125/// the user wants to see reported.
1126///
1127/// @param c a bitmap that represents the set of categories that the
1128/// user wants to see represented.
1129void
1131{priv_->allowed_category_ = c;}
1132
1133/// Setter for the bitmap that represents the set of categories that
1134/// the user wants to see reported
1135///
1136/// This function perform a bitwise or between the new set of
1137/// categories and the current ones, and then sets the current
1138/// categories to the result of the or.
1139///
1140/// @param c a bitmap that represents the set of categories that the
1141/// user wants to see represented.
1142void
1144{priv_->allowed_category_ = priv_->allowed_category_ | c;}
1145
1146/// Setter for the bitmap that represents the set of categories that
1147/// the user wants to see reported
1148///
1149/// This function actually unsets bits from the current categories.
1150///
1151/// @param c a bitmap that represents the set of categories to unset
1152/// from the current categories.
1153void
1155{priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1156
1157/// Add a diff for two decls to the cache of the current diff_context.
1158///
1159/// Doing this allows to later find the added diff from its two
1160/// subject decls.
1161///
1162/// @param first the first decl to consider.
1163///
1164/// @param second the second decl to consider.
1165///
1166/// @param the diff to add.
1167void
1168diff_context::add_diff(type_or_decl_base_sptr first,
1170 const diff_sptr d)
1171{priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1172
1173/// Add a diff tree node to the cache of the current diff_context
1174///
1175/// @param d the diff tree node to add.
1176void
1177diff_context::add_diff(const diff* d)
1178{
1179 if (d)
1180 {
1181 diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1182 add_diff(d->first_subject(), d->second_subject(), dif);
1183 }
1184}
1185
1186/// Add a diff tree node to the cache of the current diff_context
1187///
1188/// @param d the diff tree node to add.
1189void
1190diff_context::add_diff(const diff_sptr d)
1191{
1192 if (d)
1193 add_diff(d->first_subject(), d->second_subject(), d);
1194}
1195
1196/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1197/// @ref diff represented by their two subjects.
1198///
1199/// @param first the first subject of the diff.
1200///
1201/// @param second the second subject of the diff.
1202///
1203/// @return the canonical diff for the diff node represented by the
1204/// two diff subjects @p first and @p second. If no canonical diff
1205/// node was registered for these subjects, then a nil node is
1206/// returned.
1209 const type_or_decl_base_sptr second) const
1210{return has_diff_for(first, second);}
1211
1212/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1213/// @ref diff represented by the two subjects of a given diff node.
1214///
1215/// @param d the diff node to get the canonical node for.
1216///
1217/// @return the canonical diff for the diff node represented by the
1218/// two diff subjects of @p d. If no canonical diff node was
1219/// registered for these subjects, then a nil node is returned.
1222{return has_diff_for(d);}
1223
1224/// Setter for the @ref CanonicalDiff "canonical diff node" for the
1225/// @ref diff represented by their two subjects.
1226///
1227/// @param first the first subject of the diff.
1228///
1229/// @param second the second subject of the diff.
1230///
1231/// @param d the new canonical diff.
1232void
1233diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1234 const type_or_decl_base_sptr second,
1235 const diff_sptr d)
1236{
1237 ABG_ASSERT(d);
1238 if (!has_diff_for(first, second))
1239 {
1240 add_diff(first, second, d);
1241 priv_->canonical_diffs.push_back(d);
1242 }
1243}
1244
1245/// If there is is a @ref CanonicalDiff "canonical diff node"
1246/// registered for two diff subjects, return it. Otherwise, register
1247/// a canonical diff node for these two diff subjects and return it.
1248///
1249/// @param first the first subject of the diff.
1250///
1251/// @param second the second subject of the diff.
1252///
1253/// @param d the new canonical diff node.
1254///
1255/// @return the canonical diff node.
1257diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1258 const type_or_decl_base_sptr second,
1259 const diff_sptr canonical_diff)
1260{
1261 ABG_ASSERT(canonical_diff);
1262
1263 diff_sptr canonical = get_canonical_diff_for(first, second);
1264 if (!canonical)
1265 {
1266 canonical = canonical_diff;
1267 set_canonical_diff_for(first, second, canonical);
1268 }
1269 return canonical;
1270}
1271
1272/// Set the canonical diff node property of a given diff node
1273/// appropriately.
1274///
1275/// For a given diff node that has no canonical diff node, retrieve
1276/// the canonical diff node (by looking at its diff subjects and at
1277/// the current context) and set the canonical diff node property of
1278/// the diff node to that canonical diff node. If no canonical diff
1279/// node has been registered to the diff context for the subjects of
1280/// the diff node then, register the canonical diff node as being the
1281/// diff node itself; and set its canonical diff node property as
1282/// such. Otherwise, if the diff node already has a canonical diff
1283/// node, do nothing.
1284///
1285/// @param diff the diff node to initialize the canonical diff node
1286/// property for.
1287void
1289{
1290 if (diff->get_canonical_diff() == 0)
1291 {
1292 diff_sptr canonical =
1293 set_or_get_canonical_diff_for(diff->first_subject(),
1295 diff);
1296 diff->set_canonical_diff(canonical.get());
1297 }
1298}
1299
1300/// Add a diff node to the set of diff nodes that are kept alive for
1301/// the life time of the current instance of diff_context.
1302///
1303/// Note that diff added to the diff cache are kept alive as well, and
1304/// don't need to be passed to this function to be kept alive.
1305///
1306/// @param d the diff node to be kept alive during the life time of
1307/// the current instance of @ref diff_context.
1308void
1310{priv_->live_diffs_.insert(d);}
1311
1312/// Test if a diff node has been traversed.
1313///
1314/// @param d the diff node to consider.
1315///
1316/// @return the first diff node against which @p d is redundant.
1317diff*
1319{
1320 const diff* canonical = d->get_canonical_diff();
1321 ABG_ASSERT(canonical);
1322
1323 size_t ptr_value = reinterpret_cast<size_t>(canonical);
1324 pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1325 if (it != priv_->visited_diff_nodes_.end())
1326 return reinterpret_cast<diff*>(it->second);
1327 else
1328 return 0;
1329}
1330
1331/// Test if a diff node has been traversed.
1332///
1333/// @param d the diff node to consider.
1334///
1335/// @return the first diff node against which @p d is redundant.
1338{
1340 return diff;
1341}
1342
1343/// Mark a diff node as traversed by a traversing algorithm.
1344///
1345/// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1346/// node that is marked as traversed.
1347///
1348/// Subsequent invocations of diff_has_been_visited() on the diff node
1349/// will yield true.
1350void
1352{
1353 if (diff_has_been_visited(d))
1354 return;
1355
1356 const diff* canonical = d->get_canonical_diff();
1357 ABG_ASSERT(canonical);
1358
1359 size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1360 size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1361 priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1362}
1363
1364/// Unmark all the diff nodes that were marked as being traversed.
1365void
1367{priv_->visited_diff_nodes_.clear();}
1368
1369/// This sets a flag that, if it's true, then during the traversing of
1370/// a diff nodes tree each node is visited at most once.
1371///
1372/// @param f if true then during the traversing of a diff nodes tree
1373/// each node is visited at most once.
1374///
1375void
1377{priv_->forbid_visiting_a_node_twice_ = f;}
1378
1379/// This function sets a flag os that if @ref
1380/// forbid_visiting_a_node_twice() returns true, then each time the
1381/// node visitor starts visiting a new interface, it resets the
1382/// memory the systems has about already visited node.
1383///
1384/// @param f the flag to set.
1385void
1387{priv_->reset_visited_diffs_for_each_interface_ = f;}
1388
1389/// Return a flag that, if true, then during the traversing of a diff
1390/// nodes tree each node is visited at most once.
1391///
1392/// @return the boolean flag.
1393bool
1395{return priv_->forbid_visiting_a_node_twice_;}
1396
1397/// Return a flag that, if true, then during the traversing of a diff
1398/// nodes tree each node is visited at most once, while visiting the
1399/// diff tree underneath a given interface (public function or
1400/// variable). Each time a new interface is visited, the nodes
1401/// visited while visiting previous interfaces can be visited again.
1402///
1403/// @return the boolean flag.
1404///
1405/// @return the boolean flag.
1406bool
1408{
1409 return (priv_->forbid_visiting_a_node_twice_
1410 && priv_->reset_visited_diffs_for_each_interface_);
1411}
1412
1413/// Getter for the diff tree nodes filters to apply to diff sub-trees.
1414///
1415/// @return the vector of tree filters to apply to diff sub-trees.
1416const filtering::filters&
1418{return priv_->filters_;}
1419
1420/// Setter for the diff filters to apply to a given diff sub-tree.
1421///
1422/// @param f the new diff filter to add to the vector of diff filters
1423/// to apply to diff sub-trees.
1424void
1426{priv_->filters_.push_back(f);}
1427
1428/// Apply the diff filters to a given diff sub-tree.
1429///
1430/// If the current context is instructed to filter out some categories
1431/// then this function walks the given sub-tree and categorizes its
1432/// nodes by using the filters held by the context.
1433///
1434/// @param diff the diff sub-tree to apply the filters to.
1435void
1437{
1438 if (!diff)
1439 return;
1440
1441 if (!diff->has_changes())
1442 return;
1443
1444 for (filtering::filters::const_iterator i = diff_filters().begin();
1445 i != diff_filters().end();
1446 ++i)
1447 {
1449 if (do_log())
1450 {
1451 std::cerr << "applying a filter to diff '"
1453 << "'...\n";
1454 t.start();
1455 }
1456
1458
1459 if (do_log())
1460 {
1461 t.stop();
1462 std::cerr << "filter applied!:" << t << "\n";
1463
1464 std::cerr << "propagating categories for the same diff node ... \n";
1465 t.start();
1466 }
1467
1469
1470 if (do_log())
1471 {
1472 t.stop();
1473 std::cerr << "category propagated!: " << t << "\n";
1474 }
1475 }
1476
1477 }
1478
1479/// Apply the diff filters to the diff nodes of a @ref corpus_diff
1480/// instance.
1481///
1482/// If the current context is instructed to filter out some categories
1483/// then this function walks the diff tree and categorizes its nodes
1484/// by using the filters held by the context.
1485///
1486/// @param diff the corpus diff to apply the filters to.
1487void
1489{
1490
1491 if (!diff || !diff->has_changes())
1492 return;
1493
1494 for (filtering::filters::const_iterator i = diff_filters().begin();
1495 i != diff_filters().end();
1496 ++i)
1497 {
1500 }
1501}
1502
1503/// Getter for the vector of suppressions that specify which diff node
1504/// reports should be dropped on the floor.
1505///
1506/// @return the set of suppressions.
1507const suppressions_type&
1509{return priv_->suppressions_;}
1510
1511/// Getter for the vector of suppressions that specify which diff node
1512/// reports should be dropped on the floor.
1513///
1514/// @return the set of suppressions.
1517{
1518 // Invalidate negated and direct suppressions caches that are built
1519 // from priv_->suppressions_;
1520 priv_->negated_suppressions_.clear();
1521 priv_->direct_suppressions_.clear();
1522 return priv_->suppressions_;
1523}
1524
1525/// Getter of the negated suppression specifications that are
1526/// comprised in the general vector of suppression specifications
1527/// returned by diff_context::suppressions().
1528///
1529/// Note that the first invocation of this function scans the vector
1530/// returned by diff_context::suppressions() and caches the negated
1531/// suppressions from there.
1532///
1533/// Subsequent invocations of this function just return the cached
1534/// negated suppressions.
1535///
1536/// @return the negated suppression specifications stored in this diff
1537/// context.
1540{
1541 if (priv_->negated_suppressions_.empty())
1542 for (auto s : suppressions())
1544 priv_->negated_suppressions_.push_back(s);
1545
1546 return priv_->negated_suppressions_;
1547}
1548
1549/// Getter of the direct suppression specification (those that are
1550/// not negated) comprised in the general vector of suppression
1551/// specifications returned by diff_context::suppression().
1552///
1553/// Note that the first invocation of this function scans the vector
1554/// returned by diff_context::suppressions() and caches the direct
1555/// suppressions from there.
1556///
1557/// Subsequent invocations of this function just return the cached
1558/// direct suppressions.
1559///
1560/// @return the direct suppression specifications.
1563{
1564 if (priv_->direct_suppressions_.empty())
1565 {
1566 for (auto s : suppressions())
1567 if (!is_negated_suppression(s))
1568 priv_->direct_suppressions_.push_back(s);
1569 }
1570 return priv_->direct_suppressions_;
1571}
1572
1573/// Add a new suppression specification that specifies which diff node
1574/// reports should be dropped on the floor.
1575///
1576/// @param suppr the new suppression specification to add to the
1577/// existing set of suppressions specifications of the diff context.
1578void
1580{
1581 priv_->suppressions_.push_back(suppr);
1582 // Invalidate negated and direct suppressions caches that are built
1583 // from priv_->suppressions_;
1584 priv_->negated_suppressions_.clear();
1585 priv_->direct_suppressions_.clear();
1586}
1587
1588/// Add new suppression specifications that specify which diff node
1589/// reports should be dropped on the floor.
1590///
1591/// @param supprs the new suppression specifications to add to the
1592/// existing set of suppression specifications of the diff context.
1593void
1595{
1596 priv_->suppressions_.insert(priv_->suppressions_.end(),
1597 supprs.begin(), supprs.end());
1598}
1599
1600/// Test if it's requested to perform diff node categorization.
1601///
1602/// @return true iff it's requested to perform diff node
1603/// categorization.
1604bool
1606{return priv_->perform_change_categorization_;}
1607
1608/// Request change categorization or not.
1609///
1610/// @param f true iff change categorization is requested.
1611void
1613{priv_->perform_change_categorization_ = f;}
1614
1615/// Set the flag that indicates if the diff using this context should
1616/// show only leaf changes or not.
1617///
1618/// @param f the new value of the flag that indicates if the diff
1619/// using this context should show only leaf changes or not.
1620void
1622{
1623 // This function can be called only if the reporter hasn't yet been
1624 // created. Once it's been created, we are supposed to live with
1625 // it.
1626 ABG_ASSERT(priv_->reporter_ == 0);
1627 priv_->leaf_changes_only_ = f;
1628}
1629
1630/// Get the flag that indicates if the diff using this context should
1631/// show only leaf changes or not.
1632///
1633/// @return the value of the flag that indicates if the diff using
1634/// this context should show only leaf changes or not.
1635bool
1637{return priv_->leaf_changes_only_;}
1638
1639/// Get the flag that indicates if the diff reports using this context
1640/// should show sizes and offsets in an hexadecimal base or not. If
1641/// not, then they are to be shown in a decimal base.
1642///
1643/// @return true iff sizes and offsets are to be shown in an
1644/// hexadecimal base.
1645bool
1647{return priv_->hex_values_;}
1648
1649/// Set the flag that indicates if diff reports using this context
1650/// should show sizes and offsets in an hexadecimal base or not. If
1651/// not, then they are to be shown in a decimal base.
1652///
1653/// @param f if true then sizes and offsets are to be shown in an
1654/// hexadecimal base.
1655void
1657{priv_->hex_values_ = f;}
1658
1659/// Get the flag that indicates if diff reports using this context
1660/// should show sizes and offsets in bits, rather than bytes.
1661///
1662/// @return true iff sizes and offsets are to be shown in bits.
1663/// Otherwise they are to be shown in bytes.
1664bool
1666{return priv_->show_offsets_sizes_in_bits_;}
1667
1668/// Set the flag that indicates if diff reports using this context
1669/// should show sizes and offsets in bits, rather than bytes.
1670///
1671/// @param f if true then sizes and offsets are to be shown in bits.
1672/// Otherwise they are to be shown in bytes.
1673void
1675{priv_->show_offsets_sizes_in_bits_ = f;}
1676
1677/// Set a flag saying if offset changes should be reported in a
1678/// relative way. That is, if the report should say how of many bits
1679/// a class/struct data member did move.
1680///
1681/// @param f the new boolean value of the flag.
1682void
1684{priv_->show_relative_offset_changes_ = f;}
1685
1686/// Get the flag saying if offset changes should be reported in a
1687/// relative way. That is, if the report should say how of many bits
1688/// a class/struct data member did move.
1689///
1690/// @return the boolean value of the flag.
1691bool
1693{return priv_->show_relative_offset_changes_;}
1694
1695/// Set a flag saying if the comparison module should only show the
1696/// diff stats.
1697///
1698/// @param f the flag to set.
1699void
1701{priv_->show_stats_only_ = f;}
1702
1703/// Test if the comparison module should only show the diff stats.
1704///
1705/// @return true if the comparison module should only show the diff
1706/// stats, false otherwise.
1707bool
1709{return priv_->show_stats_only_;}
1710
1711/// Setter for the property that says if the comparison module should
1712/// show the soname changes in its report.
1713///
1714/// @param f the new value of the property.
1715void
1717{priv_->show_soname_change_ = f;}
1718
1719/// Getter for the property that says if the comparison module should
1720/// show the soname changes in its report.
1721///
1722/// @return the value of the property.
1723bool
1725{return priv_->show_soname_change_;}
1726
1727/// Setter for the property that says if the comparison module should
1728/// show the architecture changes in its report.
1729///
1730/// @param f the new value of the property.
1731void
1733{priv_->show_architecture_change_ = f;}
1734
1735/// Getter for the property that says if the comparison module should
1736/// show the architecture changes in its report.
1737///
1738/// @return the value of the property.
1739bool
1741{return priv_->show_architecture_change_;}
1742
1743/// Set a flag saying to show the deleted functions.
1744///
1745/// @param f true to show deleted functions.
1746void
1748{priv_->show_deleted_fns_ = f;}
1749
1750/// @return true if we want to show the deleted functions, false
1751/// otherwise.
1752bool
1754{return priv_->show_deleted_fns_;}
1755
1756/// Set a flag saying to show the changed functions.
1757///
1758/// @param f true to show the changed functions.
1759void
1761{priv_->show_changed_fns_ = f;}
1762
1763/// @return true if we want to show the changed functions, false otherwise.
1764bool
1766{return priv_->show_changed_fns_;}
1767
1768/// Set a flag saying to show the added functions.
1769///
1770/// @param f true to show the added functions.
1771void
1773{priv_->show_added_fns_ = f;}
1774
1775/// @return true if we want to show the added functions, false
1776/// otherwise.
1777bool
1779{return priv_->show_added_fns_;}
1780
1781/// Set a flag saying to show the deleted variables.
1782///
1783/// @param f true to show the deleted variables.
1784void
1786{priv_->show_deleted_vars_ = f;}
1787
1788/// @return true if we want to show the deleted variables, false
1789/// otherwise.
1790bool
1792{return priv_->show_deleted_vars_;}
1793
1794/// Set a flag saying to show the changed variables.
1795///
1796/// @param f true to show the changed variables.
1797void
1799{priv_->show_changed_vars_ = f;}
1800
1801/// @return true if we want to show the changed variables, false otherwise.
1802bool
1804{return priv_->show_changed_vars_;}
1805
1806/// Set a flag saying to show the added variables.
1807///
1808/// @param f true to show the added variables.
1809void
1811{priv_->show_added_vars_ = f;}
1812
1813/// @return true if we want to show the added variables, false
1814/// otherwise.
1815bool
1817{return priv_->show_added_vars_;}
1818
1819bool
1820diff_context::show_linkage_names() const
1821{return priv_->show_linkage_names_;}
1822
1823void
1824diff_context::show_linkage_names(bool f)
1825{priv_->show_linkage_names_= f;}
1826
1827/// Set a flag saying to show location information.
1828///
1829/// @param f true to show location information.
1830void
1832{priv_->show_locs_= f;}
1833
1834/// @return true if we want to show location information, false
1835/// otherwise.
1836bool
1838{return priv_->show_locs_;}
1839
1840/// A getter for the flag that says if we should report about
1841/// functions or variables diff nodes that have *exclusively*
1842/// redundant diff tree children nodes.
1843///
1844/// @return the flag.
1845bool
1847{return priv_->show_redundant_changes_;}
1848
1849/// A setter for the flag that says if we should report about
1850/// functions or variables diff nodes that have *exclusively*
1851/// redundant diff tree children nodes.
1852///
1853/// @param f the flag to set.
1854void
1856{priv_->show_redundant_changes_ = f;}
1857
1858/// Getter for the flag that indicates if symbols not referenced by
1859/// any debug info are to be compared and reported about.
1860///
1861/// @return the boolean flag.
1862bool
1864{return priv_->show_syms_unreferenced_by_di_;}
1865
1866/// Setter for the flag that indicates if symbols not referenced by
1867/// any debug info are to be compared and reported about.
1868///
1869/// @param f the new flag to set.
1870void
1872{priv_->show_syms_unreferenced_by_di_ = f;}
1873
1874/// Getter for the flag that indicates if symbols not referenced by
1875/// any debug info and that got added are to be reported about.
1876///
1877/// @return true iff symbols not referenced by any debug info and that
1878/// got added are to be reported about.
1879bool
1881{return priv_->show_added_syms_unreferenced_by_di_;}
1882
1883/// Setter for the flag that indicates if symbols not referenced by
1884/// any debug info and that got added are to be reported about.
1885///
1886/// @param f the new flag that says if symbols not referenced by any
1887/// debug info and that got added are to be reported about.
1888void
1890{priv_->show_added_syms_unreferenced_by_di_ = f;}
1891
1892/// Setter for the flag that indicates if changes on types unreachable
1893/// from global functions and variables are to be reported.
1894///
1895/// @param f if true, then changes on types unreachable from global
1896/// functions and variables are to be reported.
1897void
1899{priv_->show_unreachable_types_ = f;}
1900
1901/// Getter for the flag that indicates if changes on types unreachable
1902/// from global functions and variables are to be reported.
1903///
1904/// @return true iff changes on types unreachable from global
1905/// functions and variables are to be reported.
1906bool
1908{return priv_->show_unreachable_types_;}
1909
1910/// Getter of the flag that indicates if the leaf reporter should
1911/// display a summary of the interfaces impacted by a given leaf
1912/// change or not.
1913///
1914/// @return the flag that indicates if the leaf reporter should
1915/// display a summary of the interfaces impacted by a given leaf
1916/// change or not.
1917bool
1919{return priv_->show_impacted_interfaces_;}
1920
1921/// Setter of the flag that indicates if the leaf reporter should
1922/// display a summary of the interfaces impacted by a given leaf
1923/// change or not.
1924///
1925/// @param f the new value of the flag that indicates if the leaf
1926/// reporter should display a summary of the interfaces impacted by a
1927/// given leaf change or not.
1928void
1930{priv_->show_impacted_interfaces_ = f;}
1931
1932/// Setter for the default output stream used by code of the
1933/// comparison engine. By default the default output stream is a NULL
1934/// pointer.
1935///
1936/// @param o a pointer to the default output stream.
1937void
1939{priv_->default_output_stream_ = o;}
1940
1941/// Getter for the default output stream used by code of the
1942/// comparison engine. By default the default output stream is a NULL
1943/// pointer.
1944///
1945/// @return a pointer to the default output stream.
1946ostream*
1948{return priv_->default_output_stream_;}
1949
1950/// Setter for the errror output stream used by code of the comparison
1951/// engine. By default the error output stream is a NULL pointer.
1952///
1953/// @param o a pointer to the error output stream.
1954void
1956{priv_->error_output_stream_ = o;}
1957
1958/// Getter for the errror output stream used by code of the comparison
1959/// engine. By default the error output stream is a NULL pointer.
1960///
1961/// @return a pointer to the error output stream.
1962ostream*
1964{return priv_->error_output_stream_;}
1965
1966/// Test if the comparison engine should dump the diff tree for the
1967/// changed functions and variables it has.
1968///
1969/// @return true if after the comparison, the engine should dump the
1970/// diff tree for the changed functions and variables it has.
1971bool
1973{return priv_->dump_diff_tree_;}
1974
1975/// Set if the comparison engine should dump the diff tree for the
1976/// changed functions and variables it has.
1977///
1978/// @param f true if after the comparison, the engine should dump the
1979/// diff tree for the changed functions and variables it has.
1980void
1982{priv_->dump_diff_tree_ = f;}
1983
1984/// Emit a textual representation of a diff tree to the error output
1985/// stream of the current context, for debugging purposes.
1986///
1987/// @param d the diff tree to serialize to the error output associated
1988/// to the current instance of @ref diff_context.
1989void
1995
1996/// Emit a textual representation of a @ref corpus_diff tree to the error
1997/// output stream of the current context, for debugging purposes.
1998///
1999/// @param d the @ref corpus_diff tree to serialize to the error
2000/// output associated to the current instance of @ref diff_context.
2001void
2007// </diff_context stuff>
2008
2009// <diff stuff>
2010
2011/// Constructor for the @ref diff type.
2012///
2013/// This constructs a diff between two subjects that are actually
2014/// declarations; the first and the second one.
2015///
2016/// @param first_subject the first decl (subject) of the diff.
2017///
2018/// @param second_subject the second decl (subject) of the diff.
2019diff::diff(type_or_decl_base_sptr first_subject,
2020 type_or_decl_base_sptr second_subject)
2021 : priv_(new priv(first_subject, second_subject,
2024 /*reported_once=*/false,
2025 /*currently_reporting=*/false))
2026{}
2027
2028/// Constructor for the @ref diff type.
2029///
2030/// This constructs a diff between two subjects that are actually
2031/// declarations; the first and the second one.
2032///
2033/// @param first_subject the first decl (subject) of the diff.
2034///
2035/// @param second_subject the second decl (subject) of the diff.
2036///
2037/// @param ctxt the context of the diff. Note that this context
2038/// object must stay alive during the entire life time of the current
2039/// instance of @ref diff. Otherwise, memory corruption issues occur.
2040diff::diff(type_or_decl_base_sptr first_subject,
2041 type_or_decl_base_sptr second_subject,
2042 diff_context_sptr ctxt)
2043 : priv_(new priv(first_subject, second_subject,
2044 ctxt, NO_CHANGE_CATEGORY,
2045 /*reported_once=*/false,
2046 /*currently_reporting=*/false))
2047{}
2048
2049/// Test if logging was requested
2050///
2051/// @return true iff logging was requested.
2052bool
2054{return context()->do_log();}
2055
2056/// Request logging (or not)
2057///
2058/// @param f true iff logging is to be requested.
2059void
2061{context()->do_log(f);}
2062
2063/// Flag a given diff node as being traversed.
2064///
2065/// For certain diff nodes like @ref class_diff, it's important to
2066/// avoid traversing the node again while it's already being
2067/// traversed; otherwise this leads to infinite loops. So the
2068/// diff::begin_traversing() and diff::end_traversing() methods flag a
2069/// given node as being traversed (or not), so that
2070/// diff::is_traversing() can tell if the node is being traversed.
2071///
2072/// Note that traversing a node means visiting it *and* visiting its
2073/// children nodes.
2074///
2075/// The canonical node is marked as being traversed too.
2076///
2077/// These functions are called by the traversing code.
2078void
2080{
2082 if (priv_->canonical_diff_)
2083 priv_->canonical_diff_->priv_->traversing_ = true;
2084 priv_->traversing_ = true;
2085}
2086
2087/// Tell if a given node is being traversed or not.
2088///
2089/// Note that traversing a node means visiting it *and* visiting its
2090/// children nodes.
2091///
2092/// It's the canonical node which is looked at, actually.
2093///
2094/// Please read the comments for the diff::begin_traversing() for mode
2095/// context.
2096///
2097/// @return true if the current instance of @diff is being traversed.
2098bool
2100{
2101 if (priv_->canonical_diff_)
2102 return priv_->canonical_diff_->priv_->traversing_;
2103 return priv_->traversing_;
2104}
2105
2106/// Flag a given diff node as not being traversed anymore.
2107///
2108/// Note that traversing a node means visiting it *and* visiting its
2109/// children nodes.
2110///
2111/// Please read the comments of the function diff::begin_traversing()
2112/// for mode context.
2113void
2115{
2117 if (priv_->canonical_diff_)
2118 priv_->canonical_diff_->priv_->traversing_ = false;
2119 priv_->traversing_ = false;
2120}
2121
2122/// Finish the insertion of a diff tree node into the diff graph.
2123///
2124/// This function might be called several times. It must perform the
2125/// insertion only once.
2126///
2127/// For instance, certain kinds of diff tree node have specific
2128/// children nodes that are populated after the constructor of the
2129/// diff tree node has been called. In that case, calling overloads
2130/// of this method ensures that these children nodes are properly
2131/// gathered and setup.
2132void
2134{
2135 if (diff::priv_->finished_)
2136 return;
2138 diff::priv_->finished_ = true;
2139}
2140
2141/// Getter of the first subject of the diff.
2142///
2143/// @return the first subject of the diff.
2146{return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2147
2148/// Getter of the second subject of the diff.
2149///
2150/// @return the second subject of the diff.
2153{return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2154
2155/// Getter for the children nodes of the current @ref diff node.
2156///
2157/// @return a vector of the children nodes.
2158const vector<diff*>&
2160{return priv_->children_;}
2161
2162/// Getter for the parent node of the current @ref diff node.
2163///
2164/// @return the parent node of the current @ref diff node.
2165const diff*
2167{return priv_->parent_;}
2168
2169/// Getter for the canonical diff of the current instance of @ref
2170/// diff.
2171///
2172/// Note that the canonical diff node for the current instanc eof diff
2173/// node must have been set by invoking
2174/// class_diff::initialize_canonical_diff() on the current instance of
2175/// diff node.
2176///
2177/// @return the canonical diff node or null if none was set.
2178diff*
2180{return priv_->canonical_diff_;}
2181
2182/// Setter for the canonical diff of the current instance of @ref
2183/// diff.
2184///
2185/// @param d the new canonical node to set.
2186void
2188{priv_->canonical_diff_ = d;}
2189
2190/// Add a new child node to the vector of children nodes for the
2191/// current @ref diff node.
2192///
2193/// @param d the new child node to add to the children nodes.
2194void
2196{
2197 ABG_ASSERT(d);
2198
2199 // Ensure 'd' is kept alive for the life time of the context of this
2200 // diff.
2201 context()->keep_diff_alive(d);
2202
2203 // Add the underlying pointer of 'd' to the vector of children.
2204 // Note that this vector holds no reference to 'd'. This is to avoid
2205 // reference cycles. The reference to 'd' is held by the context of
2206 // this diff, thanks to the call to context()->keep_diff_alive(d)
2207 // above.
2208 priv_->children_.push_back(d.get());
2209
2210 d->priv_->parent_ = this;
2211}
2212
2213/// Getter of the context of the current diff.
2214///
2215/// @return the context of the current diff.
2218{return priv_->get_context();}
2219
2220/// Setter of the context of the current diff.
2221///
2222/// @param c the new context to set.
2223void
2225{priv_->ctxt_ = c;}
2226
2227/// Tests if we are currently in the middle of emitting a report for
2228/// this diff.
2229///
2230/// @return true if we are currently emitting a report for the
2231/// current diff, false otherwise.
2232bool
2234{
2235 if (priv_->canonical_diff_)
2236 return priv_->canonical_diff_->priv_->currently_reporting_;
2237 return priv_->currently_reporting_;
2238}
2239
2240/// Sets a flag saying if we are currently in the middle of emitting
2241/// a report for this diff.
2242///
2243/// @param f true if we are currently emitting a report for the
2244/// current diff, false otherwise.
2245void
2247{
2248 if (priv_->canonical_diff_)
2249 priv_->canonical_diff_->priv_->currently_reporting_ = f;
2250 priv_->currently_reporting_ = f;
2251}
2252
2253/// Tests if a report has already been emitted for the current diff.
2254///
2255/// @return true if a report has already been emitted for the
2256/// current diff, false otherwise.
2257bool
2259{
2260 ABG_ASSERT(priv_->canonical_diff_);
2261 return priv_->canonical_diff_->priv_->reported_once_;
2262}
2263
2264/// The generic traversing code that walks a given diff sub-tree.
2265///
2266/// Note that there is a difference between traversing a diff node and
2267/// visiting it. Basically, traversing a diff node means visiting it
2268/// and visiting its children nodes too. So one can visit a node
2269/// without traversing it. But traversing a node without visiting it
2270/// is not possible.
2271///
2272/// Note that the insertion of the "generic view" of the diff node
2273/// into the graph being traversed is done "on the fly". The
2274/// insertion of the "typed view" of the diff node into the graph is
2275/// done implicitely. To learn more about the generic and typed view
2276/// of the diff node, please read the introductory comments of the
2277/// @ref diff class.
2278///
2279/// Note that by default this traversing code visits a given class of
2280/// equivalence of a diff node only once. This behaviour can been
2281/// changed by calling
2282/// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2283/// very risky as it might create endless loops while visiting a diff
2284/// tree graph that has changes that refer to themselves; that is,
2285/// diff tree graphs with cycles.
2286///
2287/// When a diff node is encountered, the
2288/// diff_node_visitor::visit_begin() method is invoked on the diff
2289/// node first.
2290///
2291/// If the diff node has already been visited, then
2292/// node_visitor::visit_end() is called on it and the node traversing
2293/// is done; the children of the diff node are not visited in this
2294/// case.
2295///
2296/// If the diff node has *NOT* been visited yet, then the
2297/// diff_node_visitor::visit() method is invoked with it's 'pre'
2298/// argument set to true. Then if the diff_node_visitor::visit()
2299/// returns true, then the children nodes of the diff node are
2300/// visited. Otherwise, no children nodes of the diff node is
2301/// visited and the diff_node_visitor::visit_end() is called.
2302
2303/// After the children nodes are visited (and only if they are
2304/// visited) the diff_node_visitor::visit() method is invoked with
2305/// it's 'pre' argument set to false. And then the
2306/// diff_node_visitor::visit_end() is called.
2307///
2308/// @param v the entity that visits each node of the diff sub-tree.
2309///
2310/// @return true to tell the caller that all of the sub-tree could be
2311/// walked. This instructs the caller to keep walking the rest of the
2312/// tree. Return false otherwise.
2313bool
2315{
2316 // Insert the "generic view" of the diff node into its graph.
2318
2319 v.visit_begin(this);
2320
2321 bool already_visited = false;
2322 if (context()->visiting_a_node_twice_is_forbidden()
2323 && context()->diff_has_been_visited(this))
2324 already_visited = true;
2325
2326 bool mark_visited_nodes_as_traversed =
2328
2329 if (!already_visited && !v.visit(this, /*pre=*/true))
2330 {
2331 v.visit_end(this);
2332 if (mark_visited_nodes_as_traversed)
2333 context()->mark_diff_as_visited(this);
2334 return false;
2335 }
2336
2338 && !is_traversing()
2339 && !already_visited)
2340 {
2342 for (vector<diff*>::const_iterator i = children_nodes().begin();
2343 i != children_nodes().end();
2344 ++i)
2345 {
2346 if (!(*i)->traverse(v))
2347 {
2348 v.visit_end(this);
2349 if (mark_visited_nodes_as_traversed)
2350 context()->mark_diff_as_visited(this);
2352 return false;
2353 }
2354 }
2356 }
2357
2358 if (!v.visit(this, /*pref=*/false))
2359 {
2360 v.visit_end(this);
2361 if (mark_visited_nodes_as_traversed)
2362 context()->mark_diff_as_visited(this);
2363 return false;
2364 }
2365
2366 v.visit_end(this);
2367 if (!already_visited && mark_visited_nodes_as_traversed)
2368 context()->mark_diff_as_visited(this);
2369
2370 return true;
2371}
2372
2373/// Sets a flag saying if a report has already been emitted for the
2374/// current diff.
2375///
2376/// @param f true if a report has already been emitted for the
2377/// current diff, false otherwise.
2378void
2380{
2381 ABG_ASSERT(priv_->canonical_diff_);
2382 priv_->canonical_diff_->priv_->reported_once_ = f;
2383 priv_->reported_once_ = f;
2384}
2385
2386/// Getter for the local category of the current diff tree node.
2387///
2388/// The local category represents the set of categories of a diff
2389/// node, not taking in account the categories inherited from its
2390/// children nodes.
2391///
2392/// @return the local category of the current diff tree node.
2395{return priv_->local_category_;}
2396
2397/// Getter of the category of the class of equivalence of the current
2398/// diff tree node.
2399///
2400/// That is, if the current diff tree node has a canonical node,
2401/// return the category of that canonical node. Otherwise, return the
2402/// category of the current node.
2403///
2404/// @return the category of the class of equivalence of the current
2405/// tree node.
2408{
2409 diff* canonical = get_canonical_diff();
2410 return canonical ? canonical->get_category() : get_category();
2411}
2412
2413/// Getter for the category of the current diff tree node.
2414///
2415/// This category represents the union of the local category and the
2416/// categories inherited from the children diff nodes.
2417///
2418/// @return the category of the current diff tree node.
2421{return priv_->category_;}
2422
2423/// Adds the current diff tree node to an additional set of
2424/// categories. Note that the categories include thoses inherited
2425/// from the children nodes of this 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, including those inherited from
2432/// its children nodes.
2435{
2436 priv_->category_ = priv_->category_ | c;
2437 return priv_->category_;
2438}
2439
2440/// Adds the current diff tree node to the categories resulting from
2441/// the local changes of the current diff node.
2442///
2443/// @param c a bit-map representing the set of categories to add the
2444/// current diff tree node to.
2445///
2446/// @return the resulting bit-map representing the categories this
2447/// current diff tree node belongs to.
2450{
2451 priv_->local_category_ = priv_->local_category_ | c;
2452 return priv_->local_category_;
2453}
2454
2455/// Adds the current diff tree node to the categories resulting from
2456/// the local and inherited changes of the current diff node.
2457///
2458/// @param c a bit-map representing the set of categories to add the
2459/// current diff tree node to.
2460void
2466
2467/// Remove the current diff tree node from an a existing sef of
2468/// categories. The categories include those inherited from the
2469/// children nodes of the current diff node.
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, including the categories
2476/// inherited from the children nodes of the current diff node.
2479{
2480 priv_->category_ = priv_->category_ & ~c;
2481 return priv_->category_;
2482}
2483
2484/// Remove the current diff tree node from the categories resulting
2485/// from the local changes.
2486///
2487/// @param c a bit-map representing the set of categories to add the
2488/// current diff tree node to.
2489///
2490/// @return the resulting bit-map representing the categories this
2491/// current diff tree onde belongs to.
2494{
2495 priv_->local_category_ = priv_->local_category_ & ~c;
2496 return priv_->local_category_;
2497}
2498
2499/// Set the category of the current @ref diff node. This category
2500/// includes the categories inherited from the children nodes of the
2501/// current diff node.
2502///
2503/// @param c the new category for the current diff node.
2504void
2506{priv_->category_ = c;}
2507
2508/// Set the local category of the current @ref diff node.
2509///
2510/// @param c the new category for the current diff node.
2511void
2513{priv_->local_category_ = c;}
2514
2515/// Test if this diff tree node is to be filtered out for reporting
2516/// purposes.
2517///
2518/// There is a difference between a diff node being filtered out and
2519/// being suppressed. Being suppressed means that there is a
2520/// suppression specification that suppresses the diff node
2521/// specifically. Being filtered out mean the node is either
2522/// suppressed, or it's filtered out because the suppression of a set
2523/// of (children) nodes caused this node to be filtered out as well.
2524/// For instance, if a function diff has all its children diff nodes
2525/// suppressed and if the function diff node carries no local change,
2526/// then the function diff node itself is going to be filtered out.
2527///
2528/// The function tests if the categories of the diff tree node are
2529/// "forbidden" by the context or not.
2530///
2531/// @return true iff the current diff node should NOT be reported.
2532bool
2534{
2535 if (diff * canonical = get_canonical_diff())
2536 if ((canonical->get_category() & SUPPRESSED_CATEGORY
2537 || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2538 && !canonical->is_allowed_by_specific_negated_suppression()
2539 && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2540 && !canonical->has_parent_allowed_by_specific_negated_suppression())
2541 // The canonical type was suppressed either by a user-provided
2542 // suppression specification or by a "private-type" suppression
2543 // specification.. This means all the classes of equivalence of
2544 // that canonical type were suppressed. So this node should be
2545 // filtered out.
2546 return true;
2547 return priv_->is_filtered_out(get_category());
2548}
2549
2550/// Test if this diff tree node is to be filtered out for reporting
2551/// purposes, but by considering only the categories that were *NOT*
2552/// inherited from its children nodes.
2553///
2554/// The function tests if the local categories of the diff tree node
2555/// are "forbidden" by the context or not.
2556///
2557/// @return true iff the current diff node should NOT be reported,
2558/// with respect to its local categories.
2559bool
2561{return priv_->is_filtered_out(get_local_category());}
2562
2563/// Test if this diff tree node is to be filtered out for reporting
2564/// purposes, but without considering the categories that can /force/
2565/// the node to be unfiltered.
2566///
2567/// The function tests if the categories of the diff tree node are
2568/// "forbidden" by the context or not.
2569///
2570/// @return true iff the current diff node should should NOT be
2571/// reported, with respect to the categories that might filter it out
2572/// only.
2573bool
2583
2584/// Test if the current diff node has been suppressed by a
2585/// user-provided suppression specification.
2586///
2587/// @return true if the current diff node has been suppressed by a
2588/// user-provided suppression list.
2589bool
2591{
2592 bool is_private = false;
2593 return is_suppressed(is_private);
2594}
2595
2596/// Test if the current diff node has been suppressed by a
2597/// user-provided suppression specification or by an auto-generated
2598/// "private type" suppression specification.
2599///
2600/// Note that private type suppressions are auto-generated from the
2601/// path to where public headers are, as given by the user.
2602///
2603/// Here is the current algorithm:
2604///
2605/// First, suppress this diff node if it's not matched by any
2606/// negated suppression specifications. If it's not
2607/// suppressed, then suppress it if it's matched by direct
2608/// suppression specifications.
2609///
2610/// @param is_private_type out parameter if the current diff node was
2611/// suppressed because it's a private type then this parameter is set
2612/// to true.
2613///
2614/// @return true if the current diff node has been suppressed by a
2615/// user-provided suppression list.
2616bool
2617diff::is_suppressed(bool &is_private_type) const
2618{
2619 // If there is at least one negated suppression, then suppress the
2620 // current diff node by default ...
2621 bool do_suppress = !context()->negated_suppressions().empty();
2622
2623 // ... unless there is at least one negated suppression that
2624 // specifically asks to keep this diff node around (un-suppressed).
2625 for (auto n : context()->negated_suppressions())
2626 if (!n->suppresses_diff(this))
2627 {
2628 do_suppress = false;
2629 break;
2630 }
2631
2632 // Then walk the set of non-negated, AKA direct, suppressions. If at
2633 // least one suppression suppresses the current diff node then the
2634 // diff node must be suppressed.
2635 for (auto d : context()->direct_suppressions())
2636 if (d->suppresses_diff(this))
2637 {
2638 do_suppress = true;
2640 is_private_type = true;
2641 break;
2642 }
2643
2644 return do_suppress;
2645}
2646
2647/// Test if this diff tree node should be reported.
2648///
2649/// @return true iff the current node should be reported.
2650bool
2652{
2653 if (has_changes() && !is_filtered_out())
2654 return true;
2655 return false;
2656}
2657
2658/// Test if this diff tree node should be reported when considering
2659/// the categories that were *NOT* inherited from its children nodes.
2660///
2661/// @return true iff the current node should be reported.
2662bool
2664{
2665 if (has_local_changes()
2667 return true;
2668 return false;
2669}
2670
2671/// Test if this diff node is allowed (prevented from being
2672/// suppressed) by at least one negated suppression specification.
2673///
2674/// @return true if this diff node is meant to be allowed by at least
2675/// one negated suppression specification.
2676bool
2678{
2679 const suppressions_type& suppressions = context()->suppressions();
2680 for (suppressions_type::const_iterator i = suppressions.begin();
2681 i != suppressions.end();
2682 ++i)
2683 {
2685 && !(*i)->suppresses_diff(this))
2686 return true;
2687 }
2688 return false;
2689}
2690
2691/// Test if the current diff node has a descendant node which is
2692/// specifically allowed by a negated suppression specification.
2693///
2694/// @return true iff the current diff node has a descendant node
2695/// which is specifically allowed by a negated suppression
2696/// specification.
2697bool
2703
2704/// Test if the current diff node has a parent node which is
2705/// specifically allowed by a negated suppression specification.
2706///
2707/// @return true iff the current diff node has a parent node which is
2708/// specifically allowed by a negated suppression specification.
2709bool
2715
2716/// Get a pretty representation of the current @ref diff node.
2717///
2718/// This is suitable for e.g. emitting debugging traces for the diff
2719/// tree nodes.
2720///
2721/// @return the pretty representation of the diff node.
2722const string&
2724{
2725 if (priv_->pretty_representation_.empty())
2726 priv_->pretty_representation_ = "empty_diff";
2727 return priv_->pretty_representation_;
2728}
2729
2730/// Default implementation of the hierachy chaining virtual function.
2731///
2732/// There are several types of diff nodes that have logical children
2733/// nodes; for instance, a typedef_diff has the diff of the underlying
2734/// type as a child node. A var_diff has the diff of the types of the
2735/// variables as a child node, etc.
2736///
2737/// But because the @ref diff base has a generic representation for
2738/// children nodes of the all the types of @ref diff nodes (regardless
2739/// of the specific most-derived type of diff node) that one can get
2740/// using the method diff::children_nodes(), one need to populate that
2741/// vector of children node.
2742///
2743/// Populating that vector of children node is done by this function;
2744/// it must be overloaded by each most-derived type of diff node that
2745/// extends the @ref diff type.
2746void
2749
2750// </diff stuff>
2751
2752// <type_diff_base stuff>
2753
2754type_diff_base::type_diff_base(type_base_sptr first_subject,
2755 type_base_sptr second_subject,
2756 diff_context_sptr ctxt)
2757 : diff(first_subject, second_subject, ctxt),
2758 priv_(new priv)
2759{}
2760
2761type_diff_base::~type_diff_base()
2762{}
2763// </type_diff_base stuff>
2764
2765// <decl_diff_base stuff>
2766
2767/// Constructor of @ref decl_diff_base.
2768///
2769/// @param first_subject the first subject of the diff.
2770///
2771/// @param second_subject the second subject of the diff.
2772///
2773/// @param ctxt the context of the diff. This object must stay alive
2774/// at least during the life time of the current instance of @ref
2775/// decl_diff_base, otherwise, memory corruption issues occur.
2776decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2777 decl_base_sptr second_subject,
2778 diff_context_sptr ctxt)
2779 : diff(first_subject, second_subject, ctxt),
2780 priv_(new priv)
2781{}
2782
2783decl_diff_base::~decl_diff_base()
2784{}
2785
2786// </decl_diff_base stuff>
2787
2788// <distinct_diff stuff>
2789
2790/// @return a pretty representation for the @ref distinct_diff node.
2791const string&
2793{
2794 if (diff::priv_->pretty_representation_.empty())
2795 {
2796 std::ostringstream o;
2797 o << "distinct_diff[";
2798 if (first_subject())
2799 o << first_subject()->get_pretty_representation();
2800 else
2801 o << "null";
2802 o << ", ";
2803 if (second_subject())
2804 o << second_subject()->get_pretty_representation() ;
2805 else
2806 o << "null";
2807 o << "]" ;
2808 diff::priv_->pretty_representation_ = o.str();
2809 }
2810 return diff::priv_->pretty_representation_;
2811}
2812
2813/// Populate the vector of children node of the @ref diff base type
2814/// sub-object of this instance of @distinct_diff.
2815///
2816/// The children nodes can then later be retrieved using
2817/// diff::children_nodes().
2818void
2826
2827/// Constructor for @ref distinct_diff.
2828///
2829/// Note that the two entities considered for the diff (and passed in
2830/// parameter) must be of different kinds.
2831///
2832/// @param first the first entity to consider for the diff.
2833///
2834/// @param second the second entity to consider for the diff.
2835///
2836/// @param ctxt the context of the diff. Note that this context
2837/// object must stay alive at least during the life time of the
2838/// current instance of @ref distinct_diff. Otherwise memory
2839/// corruption issues occur.
2846
2847/// Getter for the first subject of the diff.
2848///
2849/// @return the first subject of the diff.
2852{return first_subject();}
2853
2854/// Getter for the second subject of the diff.
2855///
2856/// @return the second subject of the diff.
2860
2861/// Getter for the child diff of this distinct_diff instance.
2862///
2863/// When a distinct_diff has two subjects that are different but
2864/// compatible, then the distinct_diff instance has a child diff node
2865/// (named the compatible child diff) that is the diff between the two
2866/// subjects stripped from their typedefs. Otherwise, the compatible
2867/// child diff is nul.
2868///
2869/// Note that two diff subjects (that compare different) are
2870/// considered compatible if stripping typedefs out of them makes them
2871/// comparing equal.
2872///
2873/// @return the compatible child diff node, if any. Otherwise, null.
2874const diff_sptr
2876{
2877 if (!priv_->compatible_child_diff)
2878 {
2879 type_base_sptr fs = strip_typedef(is_type(first())),
2880 ss = strip_typedef(is_type(second()));
2881
2882 if (fs && ss
2885 && *fs == *ss)
2886 priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2888 context());
2889 }
2890 return priv_->compatible_child_diff;
2891}
2892
2893/// Test if the two arguments are of different kind, or that are both
2894/// NULL.
2895///
2896/// @param first the first argument to test for similarity in kind.
2897///
2898/// @param second the second argument to test for similarity in kind.
2899///
2900/// @return true iff the two arguments are of different kind.
2901bool
2904{
2905 if (!!first != !!second)
2906 return true;
2907 if (!first && !second)
2908 // We do consider diffs of two empty decls as a diff of distinct
2909 // kinds, for now.
2910 return true;
2911 if (first == second)
2912 return false;
2913
2914 const type_or_decl_base &f = *first, &s = *second;
2915 return typeid(f) != typeid(s);
2916}
2917
2918/// @return true if the two subjects of the diff are different, false
2919/// otherwise.
2920bool
2922{return first() != second();}
2923
2924/// @return the kind of local change carried by the current diff node.
2925/// The value returned is zero if the current node carries no local
2926/// change.
2927enum change_kind
2929{
2930 // Changes on a distinct_diff are all local.
2931 if (has_changes())
2933 return NO_CHANGE_KIND;
2934}
2935
2936/// Emit a report about the current diff instance.
2937///
2938/// @param out the output stream to send the diff report to.
2939///
2940/// @param indent the indentation string to use in the report.
2941void
2942distinct_diff::report(ostream& out, const string& indent) const
2943{
2944 context()->get_reporter()->report(*this, out, indent);
2945}
2946
2947/// Try to diff entities that are of distinct kinds.
2948///
2949/// @param first the first entity to consider for the diff.
2950///
2951/// @param second the second entity to consider for the diff.
2952///
2953/// @param ctxt the context of the diff.
2954///
2955/// @return a non-null diff if a diff object could be built, null
2956/// otherwise.
2959 const type_or_decl_base_sptr second,
2960 diff_context_sptr ctxt)
2961{
2963 return distinct_diff_sptr();
2964
2965 distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2966
2967 ctxt->initialize_canonical_diff(result);
2968
2969 return result;
2970}
2971
2972/// </distinct_diff stuff>
2973
2974/// Try to compute a diff on two instances of DiffType representation.
2975///
2976/// The function template performs the diff if and only if the decl
2977/// representations are of a DiffType.
2978///
2979/// @tparm DiffType the type of instances to diff.
2980///
2981/// @param first the first representation of decl to consider in the
2982/// diff computation.
2983///
2984/// @param second the second representation of decl to consider in the
2985/// diff computation.
2986///
2987/// @param ctxt the diff context to use.
2988///
2989///@return the diff of the two types @p first and @p second if and
2990///only if they represent the parametrized type DiffType. Otherwise,
2991///returns a NULL pointer value.
2992template<typename DiffType>
2995 const type_or_decl_base_sptr second,
2996 diff_context_sptr ctxt)
2997{
2998 if (shared_ptr<DiffType> f =
2999 dynamic_pointer_cast<DiffType>(first))
3000 {
3001 shared_ptr<DiffType> s =
3002 dynamic_pointer_cast<DiffType>(second);
3003 if (!s)
3004 return diff_sptr();
3005 return compute_diff(f, s, ctxt);
3006 }
3007 return diff_sptr();
3008}
3009
3010
3011/// This is a specialization of @ref try_to_diff() template to diff
3012/// instances of @ref class_decl.
3013///
3014/// @param first the first representation of decl to consider in the
3015/// diff computation.
3016///
3017/// @param second the second representation of decl to consider in the
3018/// diff computation.
3019///
3020/// @param ctxt the diff context to use.
3021template<>
3024 const type_or_decl_base_sptr second,
3025 diff_context_sptr ctxt)
3026{
3027 if (class_decl_sptr f =
3028 dynamic_pointer_cast<class_decl>(first))
3029 {
3030 class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
3031 if (!s)
3032 return diff_sptr();
3033
3034 if (f->get_is_declaration_only())
3035 {
3036 class_decl_sptr f2 =
3037 is_class_type (f->get_definition_of_declaration());
3038 if (f2)
3039 f = f2;
3040 }
3041 if (s->get_is_declaration_only())
3042 {
3043 class_decl_sptr s2 =
3044 is_class_type(s->get_definition_of_declaration());
3045 if (s2)
3046 s = s2;
3047 }
3048 return compute_diff(f, s, ctxt);
3049 }
3050 return diff_sptr();
3051}
3052
3053/// Try to diff entities that are of distinct kinds.
3054///
3055/// @param first the first entity to consider for the diff.
3056///
3057/// @param second the second entity to consider for the diff.
3058///
3059/// @param ctxt the context of the diff.
3060///
3061/// @return a non-null diff if a diff object could be built, null
3062/// otherwise.
3063static diff_sptr
3064try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3065 const type_or_decl_base_sptr second,
3066 diff_context_sptr ctxt)
3067{return compute_diff_for_distinct_kinds(first, second, ctxt);}
3068
3069/// Compute the difference between two types.
3070///
3071/// The function considers every possible types known to libabigail
3072/// and runs the appropriate diff function on them.
3073///
3074/// Whenever a new kind of type decl is supported by abigail, if we
3075/// want to be able to diff two instances of it, we need to update
3076/// this function to support it.
3077///
3078/// @param first the first type decl to consider for the diff
3079///
3080/// @param second the second type decl to consider for the diff.
3081///
3082/// @param ctxt the diff context to use.
3083///
3084/// @return the resulting diff. It's a pointer to a descendent of
3085/// abigail::comparison::diff.
3086static diff_sptr
3087compute_diff_for_types(const type_or_decl_base_sptr& first,
3088 const type_or_decl_base_sptr& second,
3089 const diff_context_sptr& ctxt)
3090{
3091 type_or_decl_base_sptr f = first;
3092 type_or_decl_base_sptr s = second;
3093
3094 diff_sptr d;
3095
3096 ((d = try_to_diff<type_decl>(f, s, ctxt))
3097 ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3098 ||(d = try_to_diff<union_decl>(f, s,ctxt))
3099 ||(d = try_to_diff<class_decl>(f, s,ctxt))
3100 ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3101 ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3102 ||(d = try_to_diff<ptr_to_mbr_type>(f, s, ctxt))
3104 ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3105 ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3106 ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3107 ||(d = try_to_diff<function_type>(f, s, ctxt))
3108 ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3109
3110 ABG_ASSERT(d);
3111
3112 return d;
3113}
3114
3115diff_category
3116operator|(diff_category c1, diff_category c2)
3117{return static_cast<diff_category>(static_cast<unsigned>(c1)
3118 | static_cast<unsigned>(c2));}
3119
3120diff_category&
3121operator|=(diff_category& c1, diff_category c2)
3122{
3123 c1 = c1 | c2;
3124 return c1;
3125}
3126
3127diff_category&
3128operator&=(diff_category& c1, diff_category c2)
3129{
3130 c1 = c1 & c2;
3131 return c1;
3132}
3133
3134diff_category
3135operator^(diff_category c1, diff_category c2)
3136{return static_cast<diff_category>(static_cast<unsigned>(c1)
3137 ^ static_cast<unsigned>(c2));}
3138
3139diff_category
3140operator&(diff_category c1, diff_category c2)
3141{return static_cast<diff_category>(static_cast<unsigned>(c1)
3142 & static_cast<unsigned>(c2));}
3143
3144diff_category
3145operator~(diff_category c)
3146{return static_cast<diff_category>(~static_cast<unsigned>(c));}
3147
3148
3149/// Getter of a bitmap made of the set of change categories that are
3150/// considered harmless.
3151///
3152/// @return the bitmap made of the set of change categories that are
3153/// considered harmless.
3154diff_category
3174
3175/// Getter of a bitmap made of the set of change categories that are
3176/// considered harmful.
3177///
3178/// @return the bitmap made of the set of change categories that are
3179/// considered harmful.
3190
3191/// Serialize an instance of @ref diff_category to an output stream.
3192///
3193/// @param o the output stream to serialize @p c to.
3194///
3195/// @param c the instance of diff_category to serialize.
3196///
3197/// @return the output stream to serialize @p c to.
3198ostream&
3199operator<<(ostream& o, diff_category c)
3200{
3201 bool emitted_a_category = false;
3202
3203 if (c == NO_CHANGE_CATEGORY)
3204 {
3205 o << "NO_CHANGE_CATEGORY";
3206 emitted_a_category = true;
3207 }
3208
3209 if (c & ACCESS_CHANGE_CATEGORY)
3210 {
3211 if (emitted_a_category)
3212 o << "|";
3213 o << "ACCESS_CHANGE_CATEGORY";
3214 emitted_a_category |= true;
3215 }
3216
3218 {
3219 if (emitted_a_category)
3220 o << "|";
3221 o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3222 emitted_a_category |= true;
3223 }
3224
3226 {
3227 if (emitted_a_category)
3228 o << "|";
3229 o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3230 emitted_a_category |= true;
3231 }
3232
3234 {
3235 if (emitted_a_category)
3236 o << "|";
3237 o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3238 emitted_a_category |= true;
3239 }
3240
3242 {
3243 if (emitted_a_category)
3244 o << "|";
3245 o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3246 emitted_a_category |= true;
3247 }
3248
3250 {
3251 if (emitted_a_category)
3252 o << "|";
3253 o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3254 emitted_a_category |= true;
3255 }
3256
3258 {
3259 if (emitted_a_category)
3260 o << "|";
3261 o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3262 emitted_a_category |= true;
3263 }
3264
3266 {
3267 if (emitted_a_category)
3268 o << "|";
3269 o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3270 emitted_a_category |= true;
3271 }
3272
3274 {
3275 if (emitted_a_category)
3276 o << "|";
3277 o << "HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY";
3278 emitted_a_category |= true;
3279 }
3280
3281 if (c & SUPPRESSED_CATEGORY)
3282 {
3283 if (emitted_a_category)
3284 o << "|";
3285 o << "SUPPRESSED_CATEGORY";
3286 emitted_a_category |= true;
3287 }
3288
3289 if (c & PRIVATE_TYPE_CATEGORY)
3290 {
3291 if (emitted_a_category)
3292 o << "|";
3293 o << "PRIVATE_TYPE_CATEGORY";
3294 emitted_a_category |= true;
3295 }
3296
3298 {
3299 if (emitted_a_category)
3300 o << "|";
3301 o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3302 emitted_a_category |= true;
3303 }
3304
3306 {
3307 if (emitted_a_category)
3308 o << "|";
3309 o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3310 emitted_a_category |= true;
3311 }
3312
3313 if (c & REFERENCE_LVALUENESS_CHANGE_CATEGORY)
3314 {
3315 if (emitted_a_category)
3316 o << "|";
3317 o << "REFERENCE_LVALUENESS_CHANGE_CATEGORY";
3318 emitted_a_category |= true;
3319 }
3320
3322 {
3323 if (emitted_a_category)
3324 o << "|";
3325 o << "NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY";
3326 emitted_a_category |= true;
3327 }
3328
3330 {
3331 if (emitted_a_category)
3332 o << "|";
3333 o << "NON_COMPATIBLE_NAME_CHANGE_CATEGORY";
3334 emitted_a_category |= true;
3335 }
3336
3337 if (c & REDUNDANT_CATEGORY)
3338 {
3339 if (emitted_a_category)
3340 o << "|";
3341 o << "REDUNDANT_CATEGORY";
3342 emitted_a_category |= true;
3343 }
3344
3346 {
3347 if (emitted_a_category)
3348 o << "|";
3349 o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3350 emitted_a_category |= true;
3351 }
3352
3354 {
3355 if (emitted_a_category)
3356 o << "|";
3357 o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3358 emitted_a_category |= true;
3359 }
3360
3362 {
3363 if (emitted_a_category)
3364 o << "|";
3365 o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3366 emitted_a_category |= true;
3367 }
3368
3370 {
3371 if (emitted_a_category)
3372 o << "|";
3373 o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3374 emitted_a_category |= true;
3375 }
3376
3378 {
3379 if (emitted_a_category)
3380 o << "|";
3381 o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3382 emitted_a_category |= true;
3383 }
3384
3386 {
3387 if (emitted_a_category)
3388 o << "|";
3389 o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3390 emitted_a_category |= true;
3391 }
3392
3394 {
3395 if (emitted_a_category)
3396 o << "|";
3397 o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3398 emitted_a_category |= true;
3399 }
3400
3402 {
3403 if (emitted_a_category)
3404 o << "|";
3405 o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3406 emitted_a_category |= true;
3407 }
3408
3410 {
3411 if (emitted_a_category)
3412 o << "|";
3413 o << "HAS_ALLOWED_CHANGE_CATEGORY";
3414 emitted_a_category |= true;
3415 }
3416
3418 {
3419 if (emitted_a_category)
3420 o << "|";
3421 o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3422 emitted_a_category |= true;
3423 }
3424
3426 {
3427 if (emitted_a_category)
3428 o << "|";
3429 o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3430 emitted_a_category |= true;
3431 }
3432
3433 return o;
3434}
3435
3436/// Compute the difference between two decls.
3437///
3438/// The function consider every possible decls known to libabigail and
3439/// runs the appropriate diff function on them.
3440///
3441/// Whenever a new kind of non-type decl is supported by abigail, if
3442/// we want to be able to diff two instances of it, we need to update
3443/// this function to support it.
3444///
3445/// @param first the first decl to consider for the diff
3446///
3447/// @param second the second decl to consider for the diff.
3448///
3449/// @param ctxt the diff context to use.
3450///
3451/// @return the resulting diff.
3452static diff_sptr
3453compute_diff_for_decls(const decl_base_sptr first,
3454 const decl_base_sptr second,
3455 diff_context_sptr ctxt)
3456{
3457
3458 diff_sptr d;
3459
3460 ((d = try_to_diff<function_decl>(first, second, ctxt))
3461 || (d = try_to_diff<var_decl>(first, second, ctxt))
3462 || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3463
3464 ABG_ASSERT(d);
3465
3466 return d;
3467}
3468
3469/// Compute the difference between two decls. The decls can represent
3470/// either type declarations, or non-type declaration.
3471///
3472/// Note that the two decls must have been created in the same @ref
3473/// environment, otherwise, this function aborts.
3474///
3475/// @param first the first decl to consider.
3476///
3477/// @param second the second decl to consider.
3478///
3479/// @param ctxt the diff context to use.
3480///
3481/// @return the resulting diff, or NULL if the diff could not be
3482/// computed.
3484compute_diff(const decl_base_sptr first,
3485 const decl_base_sptr second,
3486 diff_context_sptr ctxt)
3487{
3488 if (!first || !second)
3489 return diff_sptr();
3490
3491 diff_sptr d;
3492 if (is_type(first) && is_type(second))
3493 d = compute_diff_for_types(first, second, ctxt);
3494 else
3495 d = compute_diff_for_decls(first, second, ctxt);
3496 ABG_ASSERT(d);
3497 return d;
3498}
3499
3500/// Compute the difference between two types.
3501///
3502/// Note that the two types must have been created in the same @ref
3503/// environment, otherwise, this function aborts.
3504///
3505/// @param first the first type to consider.
3506///
3507/// @param second the second type to consider.
3508///
3509/// @param ctxt the diff context to use.
3510///
3511/// @return the resulting diff, or NULL if the diff couldn't be
3512/// computed.
3514compute_diff(const type_base_sptr first,
3515 const type_base_sptr second,
3516 diff_context_sptr ctxt)
3517{
3518 decl_base_sptr f = get_type_declaration(first),
3519 s = get_type_declaration(second);
3520
3521 diff_sptr d = compute_diff_for_types(f,s, ctxt);
3522 ABG_ASSERT(d);
3523 return d;
3524}
3525
3526/// Get a copy of the pretty representation of a diff node.
3527///
3528/// @param d the diff node to consider.
3529///
3530/// @return the pretty representation string.
3531string
3533{
3534 if (!d)
3535 return "";
3536 string prefix= "diff of ";
3537 return prefix + get_pretty_representation(d->first_subject());
3538}
3539
3540// <var_diff stuff>
3541
3542/// Populate the vector of children node of the @ref diff base type
3543/// sub-object of this instance of @ref var_diff.
3544///
3545/// The children node can then later be retrieved using
3546/// diff::children_node().
3547void
3550
3551/// @return the pretty representation for this current instance of
3552/// @ref var_diff.
3553const string&
3555{
3556 if (diff::priv_->pretty_representation_.empty())
3557 {
3558 std::ostringstream o;
3559 o << "var_diff["
3560 << first_subject()->get_pretty_representation()
3561 << ", "
3562 << second_subject()->get_pretty_representation()
3563 << "]";
3564 diff::priv_->pretty_representation_ = o.str();
3565 }
3566 return diff::priv_->pretty_representation_;
3567}
3568/// Constructor for @ref var_diff.
3569///
3570/// @param first the first instance of @ref var_decl to consider in
3571/// the diff.
3572///
3573/// @param second the second instance of @ref var_decl to consider in
3574/// the diff.
3575///
3576/// @param type_diff the diff between types of the instances of
3577/// var_decl.
3578///
3579/// @param ctxt the diff context to use.
3581 var_decl_sptr second,
3582 diff_sptr type_diff,
3583 diff_context_sptr ctxt)
3584 : decl_diff_base(first, second, ctxt),
3585 priv_(new priv)
3586{priv_->type_diff_ = type_diff;}
3587
3588/// Getter for the first @ref var_decl of the diff.
3589///
3590/// @return the first @ref var_decl of the diff.
3593{return dynamic_pointer_cast<var_decl>(first_subject());}
3594
3595/// Getter for the second @ref var_decl of the diff.
3596///
3597/// @return the second @ref var_decl of the diff.
3600{return dynamic_pointer_cast<var_decl>(second_subject());}
3601
3602/// Getter for the diff of the types of the instances of @ref
3603/// var_decl.
3604///
3605/// @return the diff of the types of the instances of @ref var_decl.
3608{
3609 if (diff_sptr result = priv_->type_diff_.lock())
3610 return result;
3611 else
3612 {
3613 result = compute_diff(first_var()->get_type(),
3614 second_var()->get_type(),
3615 context());
3616 context()->keep_diff_alive(result);
3617 priv_->type_diff_ = result;
3618 return result;
3619 }
3620}
3621
3622/// Return true iff the diff node has a change.
3623///
3624/// @return true iff the diff node has a change.
3625bool
3627{return *first_var() != *second_var();}
3628
3629/// @return the kind of local change carried by the current diff node.
3630/// The value returned is zero if the current node carries no local
3631/// change.
3632enum change_kind
3634{
3635 ir::change_kind k = ir::NO_CHANGE_KIND;
3636 if (!equals(*first_var(), *second_var(), &k))
3637 return k & ir::ALL_LOCAL_CHANGES_MASK;
3638 return ir::NO_CHANGE_KIND;
3639}
3640
3641/// Report the diff in a serialized form.
3642///
3643/// @param out the stream to serialize the diff to.
3644///
3645/// @param indent the prefix to use for the indentation of this
3646/// serialization.
3647void
3648var_diff::report(ostream& out, const string& indent) const
3649{
3650 context()->get_reporter()->report(*this, out, indent);
3651}
3652
3653/// Compute the diff between two instances of @ref var_decl.
3654///
3655/// Note that the two decls must have been created in the same @ref
3656/// environment, otherwise, this function aborts.
3657///
3658/// @param first the first @ref var_decl to consider for the diff.
3659///
3660/// @param second the second @ref var_decl to consider for the diff.
3661///
3662/// @param ctxt the diff context to use.
3663///
3664/// @return the resulting diff between the two @ref var_decl.
3667 const var_decl_sptr second,
3668 diff_context_sptr ctxt)
3669{
3670 var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3671 ctxt->initialize_canonical_diff(d);
3672
3673 return d;
3674}
3675
3676// </var_diff stuff>
3677
3678// <pointer_type_def stuff>
3679
3680/// Populate the vector of children node of the @ref diff base type
3681/// sub-object of this instance of @ref pointer_diff.
3682///
3683/// The children node can then later be retrieved using
3684/// diff::children_node().
3685void
3688
3689/// Constructor for a pointer_diff.
3690///
3691/// @param first the first pointer to consider for the diff.
3692///
3693/// @param second the secon pointer to consider for the diff.
3694///
3695/// @param ctxt the diff context to use.
3697 pointer_type_def_sptr second,
3698 diff_sptr underlying,
3699 diff_context_sptr ctxt)
3700 : type_diff_base(first, second, ctxt),
3701 priv_(new priv(underlying))
3702{}
3703
3704/// Getter for the first subject of a pointer diff
3705///
3706/// @return the first pointer considered in this pointer diff.
3709{return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3710
3711/// Getter for the second subject of a pointer diff
3712///
3713/// @return the second pointer considered in this pointer diff.
3716{return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3717
3718/// @return the pretty represenation for the current instance of @ref
3719/// pointer_diff.
3720const string&
3722{
3723 if (diff::priv_->pretty_representation_.empty())
3724 {
3725 std::ostringstream o;
3726 o << "pointer_diff["
3727 << first_subject()->get_pretty_representation()
3728 << ", "
3729 << second_subject()->get_pretty_representation()
3730 << "]";
3731 diff::priv_->pretty_representation_ = o.str();
3732 }
3733 return diff::priv_->pretty_representation_;
3734}
3735
3736/// Return true iff the current diff node carries a change.
3737///
3738/// @return true iff the current diff node carries a change.
3739bool
3742
3743/// @return the kind of local change carried by the current diff node.
3744/// The value returned is zero if the current node carries no local
3745/// change.
3746enum change_kind
3748{
3749 ir::change_kind k = ir::NO_CHANGE_KIND;
3750 if (!equals(*first_pointer(), *second_pointer(), &k))
3751 return k & ir::ALL_LOCAL_CHANGES_MASK;
3752 return ir::NO_CHANGE_KIND;
3753}
3754
3755/// Getter for the diff between the pointed-to types of the pointers
3756/// of this diff.
3757///
3758/// @return the diff between the pointed-to types.
3761{return priv_->underlying_type_diff_;}
3762
3763/// Setter for the diff between the pointed-to types of the pointers
3764/// of this diff.
3765///
3766/// @param d the new diff between the pointed-to types of the pointers
3767/// of this diff.
3768void
3770{priv_->underlying_type_diff_ = d;}
3771
3772/// Report the diff in a serialized form.
3773///
3774/// @param out the stream to serialize the diff to.
3775///
3776/// @param indent the prefix to use for the indentation of this
3777/// serialization.
3778void
3779pointer_diff::report(ostream& out, const string& indent) const
3780{
3781 context()->get_reporter()->report(*this, out, indent);
3782}
3783
3784/// Compute the diff between between two pointers.
3785///
3786/// Note that the two types must have been created in the same @ref
3787/// environment, otherwise, this function aborts.
3788///
3789/// @param first the pointer to consider for the diff.
3790///
3791/// @param second the pointer to consider for the diff.
3792///
3793/// @return the resulting diff between the two pointers.
3794///
3795/// @param ctxt the diff context to use.
3798 pointer_type_def_sptr second,
3799 diff_context_sptr ctxt)
3800{
3801 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3802 second->get_pointed_to_type(),
3803 ctxt);
3804 pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3805 ctxt->initialize_canonical_diff(result);
3806
3807 return result;
3808}
3809
3810// </pointer_type_def>
3811
3812// <subrange_diff >
3813
3814/// Constructor of the @ref subrange_diff diff node type.
3815///
3816/// @param first the first subrange type to consider for the diff.
3817///
3818/// @param second the second subrange type to consider for the diff.
3819///
3820/// @param underlying_type_diff the underlying type diff between @p
3821/// first and @p second.
3822///
3823/// @param ctxt the diff context to use.
3825(const array_type_def::subrange_sptr& first,
3826 const array_type_def::subrange_sptr& second,
3827 const diff_sptr& underlying_type_diff,
3828 const diff_context_sptr ctxt)
3829 : type_diff_base(first, second, ctxt),
3830 priv_(new priv(underlying_type_diff))
3831{}
3832
3833
3834/// Getter of the first subrange of the current instance @ref
3835/// subrange_diff.
3836///
3837/// @return The first subrange of the current instance @ref subrange_diff.
3841
3842/// Getter of the second subrange of the current instance @ref
3843/// subrange_diff.
3844///
3845/// @return The second subrange of the current instance @ref
3846/// subrange_diff.
3850
3851/// Getter of the diff node of the underlying types of the current
3852/// @ref subrange_diff diff node.
3853///
3854/// @return The diff node of the underlying types of the current @ref
3855/// subrange_diff diff node.
3856const diff_sptr
3858{return priv_->underlying_type_diff_;}
3859
3860/// Getter the pretty representation of the @ref subrange_diff diff
3861/// node.
3862///
3863/// @return The pretty representation of the @ref subrange_diff diff node.
3864const string&
3866{
3867 if (diff::priv_->pretty_representation_.empty())
3868 {
3869 std::ostringstream o;
3870 o << "subrange_diff["
3871 << first_subject()->get_pretty_representation()
3872 << ","
3873 << second_subject()->get_pretty_representation()
3874 << "]";
3875 diff::priv_->pretty_representation_ = o.str();
3876 }
3877 return diff::priv_->pretty_representation_;
3878}
3879
3880/// Test if the current @ref subrange_diff node carries any change.
3881///
3882/// @return true iff the current @ref subrange_diff node carries any
3883/// change.
3884bool
3887
3888/// Test if the current @ref subrange_diff node carries any local
3889/// change.
3890///
3891/// @return true iff the current @ref subrange_diff node carries any
3892/// local change.
3893enum change_kind
3895{
3896 ir::change_kind k = ir::NO_CHANGE_KIND;
3897 if (!equals(*first_subrange(), *second_subrange(), &k))
3898 return k & ir::ALL_LOCAL_CHANGES_MASK;
3899 return ir::NO_CHANGE_KIND;
3900}
3901
3902/// Report about the changes carried by this node.
3903///
3904/// @param out the output stream to send the report to.
3905///
3906/// @param indent the indentation string to use.
3907void
3908subrange_diff::report(ostream& out, const string& indent) const
3909{context()->get_reporter()->report(*this, out, indent);}
3910
3911/// Populate the vector of children node of the @ref diff base type
3912/// sub-object of this instance of @ref subrange_diff.
3913///
3914/// The children node can then later be retrieved using
3915/// diff::children_node().
3916void
3919
3920/// Compute the diff between two instances of @ref subrange_diff.
3921///
3922/// Note that the two decls must have been created in the same @ref
3923/// environment, otherwise, this function aborts.
3924///
3925/// @param first the first @ref subrange_diff to consider for the diff.
3926///
3927/// @param second the second @ref subrange_diff to consider for the diff.
3928///
3929/// @param ctxt the diff context to use.
3930///
3931/// @return the resulting diff between the two @ref subrange_diff.
3935 diff_context_sptr ctxt)
3936{
3937 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3938 second->get_underlying_type(),
3939 ctxt);
3940
3941 subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
3942 ctxt->initialize_canonical_diff(result);
3943 return result;
3944}
3945
3946//</subrange_diff >
3947
3948
3949// <array_type_def>
3950
3951/// Populate the vector of children node of the @ref diff base type
3952/// sub-object of this instance of @ref array_diff.
3953///
3954/// The children node can then later be retrieved using
3955/// diff::children_node().
3956void
3963
3964/// Constructor for array_diff
3965///
3966/// @param first the first array_type of the diff.
3967///
3968/// @param second the second array_type of the diff.
3969///
3970/// @param element_type_diff the diff between the two array element
3971/// types.
3972///
3973/// @param ctxt the diff context to use.
3975 const array_type_def_sptr second,
3976 diff_sptr element_type_diff,
3977 vector<subrange_diff_sptr>& subrange_diffs,
3978 diff_context_sptr ctxt)
3979 : type_diff_base(first, second, ctxt),
3980 priv_(new priv(element_type_diff, subrange_diffs))
3981{}
3982
3983/// Getter for the first array of the diff.
3984///
3985/// @return the first array of the diff.
3988{return dynamic_pointer_cast<array_type_def>(first_subject());}
3989
3990/// Getter for the second array of the diff.
3991///
3992/// @return for the second array of the diff.
3995{return dynamic_pointer_cast<array_type_def>(second_subject());}
3996
3997/// Getter for the diff between the two types of array elements.
3998///
3999/// @return the diff between the two types of array elements.
4000const diff_sptr&
4002{return priv_->element_type_diff_;}
4003
4004/// Getter for the diffs between the array subranges.
4005///
4006/// @return the diffs between the array subranges.
4007const vector<subrange_diff_sptr>&
4009{return priv_->subrange_diffs_;}
4010
4011/// Test if any subrange diff is to be reported.
4012///
4013/// @return true if any subrange diff is to be reported, false
4014/// otherwise.
4015bool
4017{
4018 for (const auto& diff: subrange_diffs())
4019 if (diff->to_be_reported())
4020 return true;
4021
4022 return false;
4023}
4024
4025/// Setter for the diff between the two array element types.
4026///
4027/// @param d the new diff between the two array element types.
4028void
4030{priv_->element_type_diff_ = d;}
4031
4032/// Setter for the diff between the two sets of array sub-ranges.
4033///
4034/// @param d the new diff between the two sets of array sub-ranges.
4035void
4036array_diff::subrange_diffs(const vector<subrange_diff_sptr>& d)
4037{priv_->subrange_diffs_ = d;}
4038
4039/// @return the pretty representation for the current instance of @ref
4040/// array_diff.
4041const string&
4043{
4044 if (diff::priv_->pretty_representation_.empty())
4045 {
4046 std::ostringstream o;
4047 o << "array_diff["
4048 << first_subject()->get_pretty_representation()
4049 << ", "
4050 << second_subject()->get_pretty_representation()
4051 << "]";
4052 diff::priv_->pretty_representation_ = o.str();
4053 }
4054 return diff::priv_->pretty_representation_;
4055}
4056
4057/// Return true iff the current diff node carries a change.
4058///
4059/// @return true iff the current diff node carries a change.
4060bool
4062{
4063 bool l = false;
4064
4065 // the array element types match check for differing dimensions
4066 // etc...
4068 f = dynamic_pointer_cast<array_type_def>(first_subject()),
4069 s = dynamic_pointer_cast<array_type_def>(second_subject());
4070
4071 if (f->get_name() != s->get_name())
4072 l |= true;
4073 if (f->get_size_in_bits() != s->get_size_in_bits())
4074 l |= true;
4075 if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
4076 l |= true;
4077
4078 l |= element_type_diff()
4079 ? element_type_diff()->has_changes()
4080 : false;
4081
4082 for (const auto& subrange_diff : subrange_diffs())
4083 l |= subrange_diff->has_changes();
4084
4085 return l;
4086}
4087
4088
4089/// @return the kind of local change carried by the current diff node.
4090/// The value returned is zero if the current node carries no local
4091/// change.
4092enum change_kind
4094{
4095 ir::change_kind k = ir::NO_CHANGE_KIND;
4096 if (!equals(*first_array(), *second_array(), &k))
4097 return k & ir::ALL_LOCAL_CHANGES_MASK;
4098 return ir::NO_CHANGE_KIND;
4099}
4100
4101/// Report the diff in a serialized form.
4102///
4103/// @param out the output stream to serialize the dif to.
4104///
4105/// @param indent the string to use for indenting the report.
4106void
4107array_diff::report(ostream& out, const string& indent) const
4108{
4109 context()->get_reporter()->report(*this, out, indent);
4110}
4111
4112/// Compute the diff between two arrays.
4113///
4114/// Note that the two types must have been created in the same @ref
4115/// environment, otherwise, this function aborts.
4116///
4117/// @param first the first array to consider for the diff.
4118///
4119/// @param second the second array to consider for the diff.
4120///
4121/// @param ctxt the diff context to use.
4124 array_type_def_sptr second,
4125 diff_context_sptr ctxt)
4126{
4127 diff_sptr element_diff = compute_diff_for_types(first->get_element_type(),
4128 second->get_element_type(),
4129 ctxt);
4130 vector<subrange_diff_sptr> subrange_diffs;
4131 if (first->get_subranges().size() == first->get_subranges().size())
4132 {
4133 for (unsigned i = 0; i < first->get_subranges().size(); ++i)
4134 {
4136 compute_diff(first->get_subranges()[i],
4137 second->get_subranges()[i],
4138 ctxt);
4139 subrange_diffs.push_back(subrange_diff);
4140 }
4141 }
4142 array_diff_sptr result(new array_diff(first, second,
4143 element_diff,
4144 subrange_diffs,
4145 ctxt));
4146 ctxt->initialize_canonical_diff(result);
4147 return result;
4148}
4149// </array_type_def>
4150
4151// <reference_type_def>
4152
4153/// Populate the vector of children node of the @ref diff base type
4154/// sub-object of this instance of @ref reference_diff.
4155///
4156/// The children node can then later be retrieved using
4157/// diff::children_node().
4158void
4161
4162/// Constructor for reference_diff
4163///
4164/// @param first the first reference_type of the diff.
4165///
4166/// @param second the second reference_type of the diff.
4167///
4168/// @param ctxt the diff context to use.
4170 const reference_type_def_sptr second,
4171 diff_sptr underlying,
4172 diff_context_sptr ctxt)
4173 : type_diff_base(first, second, ctxt),
4174 priv_(new priv(underlying))
4175{}
4176
4177/// Getter for the first reference of the diff.
4178///
4179/// @return the first reference of the diff.
4182{return dynamic_pointer_cast<reference_type_def>(first_subject());}
4183
4184/// Getter for the second reference of the diff.
4185///
4186/// @return for the second reference of the diff.
4189{return dynamic_pointer_cast<reference_type_def>(second_subject());}
4190
4191
4192/// Getter for the diff between the two referred-to types.
4193///
4194/// @return the diff between the two referred-to types.
4195const diff_sptr&
4197{return priv_->underlying_type_diff_;}
4198
4199/// Setter for the diff between the two referred-to types.
4200///
4201/// @param d the new diff betweend the two referred-to types.
4202diff_sptr&
4204{
4205 priv_->underlying_type_diff_ = d;
4206 return priv_->underlying_type_diff_;
4207}
4208
4209/// @return the pretty representation for the current instance of @ref
4210/// reference_diff.
4211const string&
4213{
4214 if (diff::priv_->pretty_representation_.empty())
4215 {
4216 std::ostringstream o;
4217 o << "reference_diff["
4218 << first_subject()->get_pretty_representation()
4219 << ", "
4220 << second_subject()->get_pretty_representation()
4221 << "]";
4222 diff::priv_->pretty_representation_ = o.str();
4223 }
4224 return diff::priv_->pretty_representation_;
4225}
4226
4227/// Return true iff the current diff node carries a change.
4228///
4229/// @return true iff the current diff node carries a change.
4230bool
4232{
4233 return first_reference() != second_reference();
4234}
4235
4236/// @return the kind of local change carried by the current diff node.
4237/// The value returned is zero if the current node carries no local
4238/// change.
4239enum change_kind
4241{
4242 ir::change_kind k = ir::NO_CHANGE_KIND;
4243 if (!equals(*first_reference(), *second_reference(), &k))
4244 return k & ir::ALL_LOCAL_CHANGES_MASK;
4245 return ir::NO_CHANGE_KIND;
4246}
4247
4248/// Report the diff in a serialized form.
4249///
4250/// @param out the output stream to serialize the dif to.
4251///
4252/// @param indent the string to use for indenting the report.
4253void
4254reference_diff::report(ostream& out, const string& indent) const
4255{
4256 context()->get_reporter()->report(*this, out, indent);
4257}
4258
4259/// Compute the diff between two references.
4260///
4261/// Note that the two types must have been created in the same @ref
4262/// environment, otherwise, this function aborts.
4263///
4264/// @param first the first reference to consider for the diff.
4265///
4266/// @param second the second reference to consider for the diff.
4267///
4268/// @param ctxt the diff context to use.
4272 diff_context_sptr ctxt)
4273{
4274 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4275 second->get_pointed_to_type(),
4276 ctxt);
4277 reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4278 ctxt->initialize_canonical_diff(result);
4279 return result;
4280}
4281// </reference_type_def>
4282
4283// <ptr_to_mbr_diff stuff>
4284
4285
4286/// Constructor of @ref ptr_to_mbr_diff.
4287///
4288/// @param first the first pointer-to-member subject of the diff.
4289///
4290/// @param second the second pointer-to-member subject of the diff.
4291///
4292/// @param member_type_diff the diff node carrying changes to the
4293/// member type of the pointer-to-member we are considering.
4294///
4295/// @param containing_type_diff the diff node carrying changes to the
4296/// containing type of the pointer-to-member we are considering.
4297///
4298/// @param ctxt the context of the diff we are considering.
4299ptr_to_mbr_diff::ptr_to_mbr_diff(const ptr_to_mbr_type_sptr& first,
4300 const ptr_to_mbr_type_sptr& second,
4301 const diff_sptr& member_type_diff,
4302 const diff_sptr& containing_type_diff,
4303 diff_context_sptr ctxt)
4304 : type_diff_base(first, second, ctxt),
4305 priv_(new priv(member_type_diff, containing_type_diff))
4306{}
4307
4308/// Getter of the first pointer-to-member subject of the current diff
4309/// node.
4310///
4311/// @return the first pointer-to-member subject of the current diff
4312/// node.
4315{return dynamic_pointer_cast<ptr_to_mbr_type>(first_subject());}
4316
4317/// Getter of the second pointer-to-member subject of the current diff
4318/// node.
4319///
4320/// @return the second pointer-to-member subject of the current diff
4321/// node.
4324{return dynamic_pointer_cast<ptr_to_mbr_type>(second_subject());}
4325
4326/// Getter of the diff node carrying changes to the member type of
4327/// first subject of the current diff node.
4328///
4329/// @return The diff node carrying changes to the member type of first
4330/// subject of the current diff node.
4331const diff_sptr
4333{return priv_->member_type_diff_;}
4334
4335/// Getter of the diff node carrying changes to the containing type of
4336/// first subject of the current diff node.
4337///
4338/// @return The diff node carrying changes to the containing type of
4339/// first subject of the current diff node.
4340const diff_sptr
4342{return priv_->containing_type_diff_;}
4343
4344/// Test whether the current diff node carries any change.
4345///
4346/// @return true iff the current diff node carries any change.
4347bool
4352
4353/// Test whether the current diff node carries any local change.
4354///
4355/// @return true iff the current diff node carries any local change.
4356enum change_kind
4358{
4359 ir::change_kind k = ir::NO_CHANGE_KIND;
4361 return k & ir::ALL_LOCAL_CHANGES_MASK;
4362 return ir::NO_CHANGE_KIND;
4363}
4364
4365/// Get the pretty representation of the current @ref ptr_to_mbr_diff
4366/// node.
4367///
4368/// @return the pretty representation of the current diff node.
4369const string&
4371{
4372 if (diff::priv_->pretty_representation_.empty())
4373 {
4374 std::ostringstream o;
4375 o << "ptr_to_mbr_diff["
4376 << first_subject()->get_pretty_representation()
4377 << ", "
4378 << second_subject()->get_pretty_representation()
4379 << "]";
4380 diff::priv_->pretty_representation_ = o.str();
4381 }
4382 return diff::priv_->pretty_representation_;
4383}
4384
4385void
4386ptr_to_mbr_diff::report(ostream& out, const string& indent) const
4387{
4388 context()->get_reporter()->report(*this, out, indent);
4389}
4390
4391/// Populate the vector of children node of the @ref diff base type
4392/// sub-object of this instance of @ref ptr_to_mbr_diff.
4393///
4394/// The children node can then later be retrieved using
4395/// diff::children_node().
4396void
4402
4403/// Destructor of @ref ptr_to_mbr_diff.
4407
4408/// Compute the diff between two @ref ptr_to_mbr_type types.
4409///
4410/// Note that the two types must have been created in the same @ref
4411/// environment, otherwise, this function aborts.
4412///
4413/// @param first the first pointer-to-member type to consider for the diff.
4414///
4415/// @param second the second pointer-to-member type to consider for the diff.
4416///
4417/// @param ctxt the diff context to use.
4420 const ptr_to_mbr_type_sptr& second,
4421 diff_context_sptr& ctxt)
4422{
4423 diff_sptr member_type_diff =
4424 compute_diff(is_type(first->get_member_type()),
4425 is_type(second->get_member_type()),
4426 ctxt);
4427
4428 diff_sptr containing_type_diff =
4429 compute_diff(is_type(first->get_containing_type()),
4430 is_type(second->get_containing_type()),
4431 ctxt);
4432
4433 ptr_to_mbr_diff_sptr result(new ptr_to_mbr_diff(first, second,
4434 member_type_diff,
4435 containing_type_diff,
4436 ctxt));
4437 ctxt->initialize_canonical_diff(result);
4438 return result;
4439}
4440
4441// </ptr_to_mbr_diff stuff>
4442
4443// <qualified_type_diff stuff>
4444
4445/// Populate the vector of children node of the @ref diff base type
4446/// sub-object of this instance of @ref qualified_type_diff.
4447///
4448/// The children node can then later be retrieved using
4449/// diff::children_node().
4450void
4453
4454/// Constructor for qualified_type_diff.
4455///
4456/// @param first the first qualified type of the diff.
4457///
4458/// @param second the second qualified type of the diff.
4459///
4460/// @param ctxt the diff context to use.
4461qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4462 qualified_type_def_sptr second,
4463 diff_sptr under,
4464 diff_context_sptr ctxt)
4465 : type_diff_base(first, second, ctxt),
4466 priv_(new priv(under))
4467{}
4468
4469/// Getter for the first qualified type of the diff.
4470///
4471/// @return the first qualified type of the diff.
4472const qualified_type_def_sptr
4474{return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4475
4476/// Getter for the second qualified type of the diff.
4477///
4478/// @return the second qualified type of the diff.
4479const qualified_type_def_sptr
4481{return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4482
4483/// Getter for the diff between the underlying types of the two
4484/// qualified types.
4485///
4486/// @return the diff between the underlying types of the two qualified
4487/// types.
4490{return priv_->underlying_type_diff;}
4491
4492/// Getter for the diff between the most underlying non-qualified
4493/// types of two qualified types.
4494///
4495/// @return the diff between the most underlying non-qualified types
4496/// of two qualified types.
4499{
4500 if (!priv_->leaf_underlying_type_diff)
4501 priv_->leaf_underlying_type_diff
4502 = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4504 context());
4505
4506 return priv_->leaf_underlying_type_diff;
4507}
4508
4509/// Setter for the diff between the underlying types of the two
4510/// qualified types.
4511///
4512/// @return the diff between the underlying types of the two qualified
4513/// types.
4514void
4516{priv_->underlying_type_diff = d;}
4517
4518/// @return the pretty representation of the current instance of @ref
4519/// qualified_type_diff.
4520const string&
4522{
4523 if (diff::priv_->pretty_representation_.empty())
4524 {
4525 std::ostringstream o;
4526 o << "qualified_type_diff["
4527 << first_subject()->get_pretty_representation()
4528 << ", "
4529 << second_subject()->get_pretty_representation()
4530 << "]";
4531 diff::priv_->pretty_representation_ = o.str();
4532 }
4533 return diff::priv_->pretty_representation_;
4534}
4535
4536/// Return true iff the current diff node carries a change.
4537///
4538/// @return true iff the current diff node carries a change.
4539bool
4542
4543/// @return the kind of local change carried by the current diff node.
4544/// The value returned is zero if the current node carries no local
4545/// change.
4546enum change_kind
4548{
4549 ir::change_kind k = ir::NO_CHANGE_KIND;
4551 return k & ir::ALL_LOCAL_CHANGES_MASK;
4552 return ir::NO_CHANGE_KIND;
4553}
4554
4555/// Report the diff in a serialized form.
4556///
4557/// @param out the output stream to serialize to.
4558///
4559/// @param indent the string to use to indent the lines of the report.
4560void
4561qualified_type_diff::report(ostream& out, const string& indent) const
4562{
4563 context()->get_reporter()->report(*this, out, indent);
4564}
4565
4566/// Compute the diff between two qualified types.
4567///
4568/// Note that the two types must have been created in the same @ref
4569/// environment, otherwise, this function aborts.
4570///
4571/// @param first the first qualified type to consider for the diff.
4572///
4573/// @param second the second qualified type to consider for the diff.
4574///
4575/// @param ctxt the diff context to use.
4576qualified_type_diff_sptr
4577compute_diff(const qualified_type_def_sptr first,
4578 const qualified_type_def_sptr second,
4579 diff_context_sptr ctxt)
4580{
4581 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4582 second->get_underlying_type(),
4583 ctxt);
4584 qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4585 d, ctxt));
4586 ctxt->initialize_canonical_diff(result);
4587 return result;
4588}
4589
4590// </qualified_type_diff stuff>
4591
4592// <enum_diff stuff>
4593
4594/// Clear the lookup tables useful for reporting an enum_diff.
4595///
4596/// This function must be updated each time a lookup table is added or
4597/// removed from the class_diff::priv.
4598void
4599enum_diff::clear_lookup_tables()
4600{
4601 priv_->deleted_enumerators_.clear();
4602 priv_->inserted_enumerators_.clear();
4603 priv_->changed_enumerators_.clear();
4604}
4605
4606/// Tests if the lookup tables are empty.
4607///
4608/// @return true if the lookup tables are empty, false otherwise.
4609bool
4610enum_diff::lookup_tables_empty() const
4611{
4612 return (priv_->deleted_enumerators_.empty()
4613 && priv_->inserted_enumerators_.empty()
4614 && priv_->changed_enumerators_.empty());
4615}
4616
4617/// If the lookup tables are not yet built, walk the differences and
4618/// fill the lookup tables.
4619void
4620enum_diff::ensure_lookup_tables_populated()
4621{
4622 if (!lookup_tables_empty())
4623 return;
4624
4625 {
4626 edit_script e = priv_->enumerators_changes_;
4627
4628 for (vector<deletion>::const_iterator it = e.deletions().begin();
4629 it != e.deletions().end();
4630 ++it)
4631 {
4632 unsigned i = it->index();
4633 const enum_type_decl::enumerator& n =
4634 first_enum()->get_enumerators()[i];
4635 const string& name = n.get_name();
4636 ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4637 == priv_->deleted_enumerators_.end());
4638 priv_->deleted_enumerators_[name] = n;
4639 }
4640
4641 for (vector<insertion>::const_iterator it = e.insertions().begin();
4642 it != e.insertions().end();
4643 ++it)
4644 {
4645 for (vector<unsigned>::const_iterator iit =
4646 it->inserted_indexes().begin();
4647 iit != it->inserted_indexes().end();
4648 ++iit)
4649 {
4650 unsigned i = *iit;
4651 const enum_type_decl::enumerator& n =
4652 second_enum()->get_enumerators()[i];
4653 const string& name = n.get_name();
4654 ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4655 == priv_->inserted_enumerators_.end());
4656 string_enumerator_map::const_iterator j =
4657 priv_->deleted_enumerators_.find(name);
4658 if (j == priv_->deleted_enumerators_.end())
4659 priv_->inserted_enumerators_[name] = n;
4660 else
4661 {
4662 if (j->second != n)
4663 priv_->changed_enumerators_[j->first] =
4664 std::make_pair(j->second, n);
4665 priv_->deleted_enumerators_.erase(j);
4666 }
4667 }
4668 }
4669 }
4670}
4671
4672/// Populate the vector of children node of the @ref diff base type
4673/// sub-object of this instance of @ref enum_diff.
4674///
4675/// The children node can then later be retrieved using
4676/// diff::children_node().
4677void
4680
4681/// Constructor for enum_diff.
4682///
4683/// @param first the first enum type of the diff.
4684///
4685/// @param second the second enum type of the diff.
4686///
4687/// @param underlying_type_diff the diff of the two underlying types
4688/// of the two enum types.
4689///
4690/// @param ctxt the diff context to use.
4692 const enum_type_decl_sptr second,
4693 const diff_sptr underlying_type_diff,
4694 const diff_context_sptr ctxt)
4695 : type_diff_base(first, second, ctxt),
4696 priv_(new priv(underlying_type_diff))
4697{}
4698
4699/// @return the first enum of the diff.
4702{return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4703
4704/// @return the second enum of the diff.
4707{return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4708
4709/// @return the diff of the two underlying enum types.
4712{return priv_->underlying_type_diff_;}
4713
4714/// @return a map of the enumerators that were deleted.
4717{return priv_->deleted_enumerators_;}
4718
4719/// @return a map of the enumerators that were inserted
4722{return priv_->inserted_enumerators_;}
4723
4724/// @return a map of the enumerators that were changed
4727{return priv_->changed_enumerators_;}
4728
4729/// @return the pretty representation of the current instance of @ref
4730/// enum_diff.
4731const string&
4733{
4734 if (diff::priv_->pretty_representation_.empty())
4735 {
4736 std::ostringstream o;
4737 o << "enum_diff["
4738 << first_subject()->get_pretty_representation()
4739 << ", "
4740 << second_subject()->get_pretty_representation()
4741 << "]";
4742 diff::priv_->pretty_representation_ = o.str();
4743 }
4744 return diff::priv_->pretty_representation_;
4745}
4746
4747/// Return true iff the current diff node carries a change.
4748///
4749/// @return true iff the current diff node carries a change.
4750bool
4752{return first_enum() != second_enum();}
4753
4754/// @return the kind of local change carried by the current diff node.
4755/// The value returned is zero if the current node carries no local
4756/// change.
4757enum change_kind
4759{
4760 ir::change_kind k = ir::NO_CHANGE_KIND;
4761 if (!equals(*first_enum(), *second_enum(), &k))
4762 return k & ir::ALL_LOCAL_CHANGES_MASK;
4763 return ir::NO_CHANGE_KIND;
4764}
4765
4766/// Report the differences between the two enums.
4767///
4768/// @param out the output stream to send the report to.
4769///
4770/// @param indent the string to use for indentation.
4771void
4772enum_diff::report(ostream& out, const string& indent) const
4773{
4774 context()->get_reporter()->report(*this, out, indent);
4775}
4776
4777/// Compute the set of changes between two instances of @ref
4778/// enum_type_decl.
4779///
4780/// Note that the two types must have been created in the same @ref
4781/// environment, otherwise, this function aborts.
4782///
4783/// @param first a pointer to the first enum_type_decl to consider.
4784///
4785/// @param second a pointer to the second enum_type_decl to consider.
4786///
4787/// @return the resulting diff of the two enums @p first and @p
4788/// second.
4789///
4790/// @param ctxt the diff context to use.
4791enum_diff_sptr
4793 const enum_type_decl_sptr second,
4794 diff_context_sptr ctxt)
4795{
4796 diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4797 second->get_underlying_type(),
4798 ctxt);
4799 enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4800 if (first != second)
4801 {
4802 compute_diff(first->get_enumerators().begin(),
4803 first->get_enumerators().end(),
4804 second->get_enumerators().begin(),
4805 second->get_enumerators().end(),
4806 d->priv_->enumerators_changes_);
4807 d->ensure_lookup_tables_populated();
4808 }
4809 ctxt->initialize_canonical_diff(d);
4810
4811 return d;
4812}
4813// </enum_diff stuff>
4814
4815// <class_or_union_diff stuff>
4816
4817/// Test if the current diff node carries a member type change for a
4818/// member type which name is the same as the name of a given type
4819/// declaration.
4820///
4821/// @param d the type declaration which name should be equal to the
4822/// name of the member type that might have changed.
4823///
4824/// @return the member type that has changed, iff there were a member
4825/// type (which name is the same as the name of @p d) that changed.
4826/// Note that the member type that is returned is the new value of the
4827/// member type that changed.
4830{
4831 string qname = d->get_qualified_name();
4832 string_diff_sptr_map::const_iterator it =
4833 changed_member_types_.find(qname);
4834
4835 return ((it == changed_member_types_.end())
4837 : it->second->second_subject());
4838}
4839
4840/// Test if the current diff node carries a data member change for a
4841/// data member which name is the same as the name of a given type
4842/// declaration.
4843///
4844/// @param d the type declaration which name should be equal to the
4845/// name of the data member that might have changed.
4846///
4847/// @return the data member that has changed, iff there were a data
4848/// member type (which name is the same as the name of @p d) that
4849/// changed. Note that the data member that is returned is the new
4850/// value of the data member that changed.
4851decl_base_sptr
4853{
4854 string qname = d->get_qualified_name();
4855 string_var_diff_sptr_map::const_iterator it =
4856 subtype_changed_dm_.find(qname);
4857
4858 if (it == subtype_changed_dm_.end())
4859 return decl_base_sptr();
4860 return it->second->second_var();
4861}
4862
4863/// Test if the current diff node carries a member class template
4864/// change for a member class template which name is the same as the
4865/// name of a given type declaration.
4866///
4867/// @param d the type declaration which name should be equal to the
4868/// name of the member class template that might have changed.
4869///
4870/// @return the member class template that has changed, iff there were
4871/// a member class template (which name is the same as the name of @p
4872/// d) that changed. Note that the member class template that is
4873/// returned is the new value of the member class template that
4874/// changed.
4875decl_base_sptr
4877{
4878 string qname = d->get_qualified_name();
4879 string_diff_sptr_map::const_iterator it =
4880 changed_member_class_tmpls_.find(qname);
4881
4882 return ((it == changed_member_class_tmpls_.end())
4883 ? decl_base_sptr()
4884 : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4885}
4886
4887/// Get the number of non static data members that were deleted.
4888///
4889/// @return the number of non static data members that were deleted.
4890size_t
4892{
4893 size_t result = 0;
4894
4895 for (string_decl_base_sptr_map::const_iterator i =
4896 deleted_data_members_.begin();
4897 i != deleted_data_members_.end();
4898 ++i)
4899 if (is_member_decl(i->second)
4900 && !get_member_is_static(i->second))
4901 ++result;
4902
4903 return result;
4904}
4905
4906/// Get the number of non static data members that were inserted.
4907///
4908/// @return the number of non static data members that were inserted.
4909size_t
4911{
4912 size_t result = 0;
4913
4914 for (string_decl_base_sptr_map::const_iterator i =
4915 inserted_data_members_.begin();
4916 i != inserted_data_members_.end();
4917 ++i)
4918 if (is_member_decl(i->second)
4919 && !get_member_is_static(i->second))
4920 ++result;
4921
4922 return result;
4923}
4924
4925/// Get the number of data member sub-type changes carried by the
4926/// current diff node that were filtered out.
4927///
4928/// @param local_only if true, it means that only (filtered) local
4929/// changes are considered.
4930///
4931/// @return the number of data member sub-type changes carried by the
4932/// current diff node that were filtered out.
4933size_t
4935{
4936 size_t num_filtered= 0;
4937 for (var_diff_sptrs_type::const_iterator i =
4938 sorted_subtype_changed_dm_.begin();
4939 i != sorted_subtype_changed_dm_.end();
4940 ++i)
4941 {
4942 if (local_only)
4943 {
4944 if ((*i)->has_local_changes() && (*i)->is_filtered_out())
4945 ++num_filtered;
4946 }
4947 else
4948 {
4949 if ((*i)->is_filtered_out())
4950 ++num_filtered;
4951 }
4952 }
4953 return num_filtered;
4954}
4955
4956/// Get the number of data member changes carried by the current diff
4957/// node that were filtered out.
4958///
4959/// @param local_only if true, it means that only (filtered) local
4960/// changes are considered.
4961///
4962/// @return the number of data member changes carried by the current
4963/// diff node that were filtered out.
4964size_t
4966{
4967 size_t num_filtered= 0;
4968
4969 for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4970 i != changed_dm_.end();
4971 ++i)
4972 {
4973 diff_sptr diff = i->second;
4974 if (local_only)
4975 {
4976 if (diff->has_changes() && diff->is_filtered_out())
4977 ++num_filtered;
4978 }
4979 else
4980 {
4981 if (diff->is_filtered_out())
4982 ++num_filtered;
4983 }
4984 }
4985 return num_filtered;
4986}
4987
4988/// Skip the processing of the current member function if its
4989/// virtual-ness is disallowed by the user.
4990///
4991/// This is to be used in the member functions below that are used to
4992/// count the number of filtered inserted, deleted and changed member
4993/// functions.
4994#define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
4995 do { \
4996 if (get_member_function_is_virtual(f) \
4997 || get_member_function_is_virtual(s)) \
4998 { \
4999 if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
5000 continue; \
5001 } \
5002 else \
5003 { \
5004 if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
5005 continue; \
5006 } \
5007 } while (false)
5008
5009/// Get the number of member functions changes carried by the current
5010/// diff node that were filtered out.
5011///
5012/// @return the number of member functions changes carried by the
5013/// current diff node that were filtered out.
5014size_t
5016(const diff_context_sptr& ctxt)
5017{
5018 size_t count = 0;
5019 diff_category allowed_category = ctxt->get_allowed_category();
5020
5021 for (function_decl_diff_sptrs_type::const_iterator i =
5022 sorted_changed_member_functions_.begin();
5023 i != sorted_changed_member_functions_.end();
5024 ++i)
5025 {
5026 method_decl_sptr f =
5027 dynamic_pointer_cast<method_decl>
5028 ((*i)->first_function_decl());
5029 ABG_ASSERT(f);
5030
5031 method_decl_sptr s =
5032 dynamic_pointer_cast<method_decl>
5033 ((*i)->second_function_decl());
5034 ABG_ASSERT(s);
5035
5037
5038 diff_sptr diff = *i;
5039 ctxt->maybe_apply_filters(diff);
5040
5041 if (diff->is_filtered_out())
5042 ++count;
5043 }
5044
5045 return count;
5046}
5047
5048/// Get the number of member functions insertions carried by the current
5049/// diff node that were filtered out.
5050///
5051/// @return the number of member functions insertions carried by the
5052/// current diff node that were filtered out.
5053size_t
5055(const diff_context_sptr& ctxt)
5056{
5057 size_t count = 0;
5058 diff_category allowed_category = ctxt->get_allowed_category();
5059
5060 for (string_member_function_sptr_map::const_iterator i =
5061 inserted_member_functions_.begin();
5062 i != inserted_member_functions_.end();
5063 ++i)
5064 {
5065 method_decl_sptr f = i->second,
5066 s = i->second;
5067
5069
5070 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5071 ctxt->maybe_apply_filters(diff);
5072
5074 && diff->is_filtered_out())
5075 ++count;
5076 }
5077
5078 return count;
5079}
5080
5081/// Get the number of member functions deletions carried by the current
5082/// diff node that were filtered out.
5083///
5084/// @return the number of member functions deletions carried by the
5085/// current diff node that were filtered out.
5086size_t
5088(const diff_context_sptr& ctxt)
5089{
5090 size_t count = 0;
5091 diff_category allowed_category = ctxt->get_allowed_category();
5092
5093 for (string_member_function_sptr_map::const_iterator i =
5094 deleted_member_functions_.begin();
5095 i != deleted_member_functions_.end();
5096 ++i)
5097 {
5098 method_decl_sptr f = i->second,
5099 s = i->second;
5100
5102
5103 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
5104 ctxt->maybe_apply_filters(diff);
5105
5107 && diff->is_filtered_out())
5108 ++count;
5109 }
5110
5111 return count;
5112}
5113
5114/// Clear the lookup tables useful for reporting.
5115///
5116/// This function must be updated each time a lookup table is added or
5117/// removed from the class_or_union_diff::priv.
5118void
5120{
5121 priv_->deleted_member_types_.clear();
5122 priv_->inserted_member_types_.clear();
5123 priv_->changed_member_types_.clear();
5124 priv_->deleted_data_members_.clear();
5125 priv_->inserted_data_members_.clear();
5126 priv_->subtype_changed_dm_.clear();
5127 priv_->deleted_member_functions_.clear();
5128 priv_->inserted_member_functions_.clear();
5129 priv_->changed_member_functions_.clear();
5130 priv_->deleted_member_class_tmpls_.clear();
5131 priv_->inserted_member_class_tmpls_.clear();
5132 priv_->changed_member_class_tmpls_.clear();
5133}
5134
5135/// Tests if the lookup tables are empty.
5136///
5137/// @return true if the lookup tables are empty, false otherwise.
5138bool
5140{
5141 return (priv_->deleted_member_types_.empty()
5142 && priv_->inserted_member_types_.empty()
5143 && priv_->changed_member_types_.empty()
5144 && priv_->deleted_data_members_.empty()
5145 && priv_->inserted_data_members_.empty()
5146 && priv_->subtype_changed_dm_.empty()
5147 && priv_->inserted_member_functions_.empty()
5148 && priv_->deleted_member_functions_.empty()
5149 && priv_->changed_member_functions_.empty()
5150 && priv_->deleted_member_class_tmpls_.empty()
5151 && priv_->inserted_member_class_tmpls_.empty()
5152 && priv_->changed_member_class_tmpls_.empty());
5153}
5154
5155/// If the lookup tables are not yet built, walk the differences and
5156/// fill them.
5157void
5159{
5160 {
5161 edit_script& e = priv_->member_types_changes_;
5162
5163 for (vector<deletion>::const_iterator it = e.deletions().begin();
5164 it != e.deletions().end();
5165 ++it)
5166 {
5167 unsigned i = it->index();
5168 decl_base_sptr d =
5169 get_type_declaration(first_class_or_union()->get_member_types()[i]);
5170 class_or_union_sptr record_type = is_class_or_union_type(d);
5171 if (record_type && record_type->get_is_declaration_only())
5172 continue;
5173 string name = d->get_name();
5174 priv_->deleted_member_types_[name] = d;
5175 }
5176
5177 for (vector<insertion>::const_iterator it = e.insertions().begin();
5178 it != e.insertions().end();
5179 ++it)
5180 {
5181 for (vector<unsigned>::const_iterator iit =
5182 it->inserted_indexes().begin();
5183 iit != it->inserted_indexes().end();
5184 ++iit)
5185 {
5186 unsigned i = *iit;
5187 decl_base_sptr d =
5188 get_type_declaration(second_class_or_union()->get_member_types()[i]);
5189 class_or_union_sptr record_type = is_class_or_union_type(d);
5190 if (record_type && record_type->get_is_declaration_only())
5191 continue;
5192 string name = d->get_name();
5193 string_decl_base_sptr_map::const_iterator j =
5194 priv_->deleted_member_types_.find(name);
5195 if (j != priv_->deleted_member_types_.end())
5196 {
5197 if (*j->second != *d)
5198 priv_->changed_member_types_[name] =
5199 compute_diff(j->second, d, context());
5200
5201 priv_->deleted_member_types_.erase(j);
5202 }
5203 else
5204 priv_->inserted_member_types_[name] = d;
5205 }
5206 }
5207 }
5208
5209 {
5210 edit_script& e = priv_->data_members_changes_;
5211
5212 for (vector<deletion>::const_iterator it = e.deletions().begin();
5213 it != e.deletions().end();
5214 ++it)
5215 {
5216 unsigned i = it->index();
5217 var_decl_sptr data_member =
5218 is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
5219 string name = data_member->get_anon_dm_reliable_name();
5220
5221 ABG_ASSERT(priv_->deleted_data_members_.find(name)
5222 == priv_->deleted_data_members_.end());
5223 priv_->deleted_data_members_[name] = data_member;
5224 }
5225
5226 for (vector<insertion>::const_iterator it = e.insertions().begin();
5227 it != e.insertions().end();
5228 ++it)
5229 {
5230 for (vector<unsigned>::const_iterator iit =
5231 it->inserted_indexes().begin();
5232 iit != it->inserted_indexes().end();
5233 ++iit)
5234 {
5235 unsigned i = *iit;
5236 decl_base_sptr d =
5237 second_class_or_union()->get_non_static_data_members()[i];
5238 var_decl_sptr added_dm = is_var_decl(d);
5239 string name = added_dm->get_anon_dm_reliable_name();
5240 ABG_ASSERT(priv_->inserted_data_members_.find(name)
5241 == priv_->inserted_data_members_.end());
5242
5243 bool ignore_added_anonymous_data_member = false;
5244 if (is_anonymous_data_member(added_dm))
5245 {
5246 //
5247 // Handle insertion of anonymous data member to
5248 // replace existing data members.
5249 //
5250 // For instance consider this:
5251 // struct S
5252 // {
5253 // int a;
5254 // int b;
5255 // int c;
5256 // };// end struct S
5257 //
5258 // Where the data members 'a' and 'b' are replaced
5259 // by an anonymous data member without changing the
5260 // effective bit layout of the structure:
5261 //
5262 // struct S
5263 // {
5264 // struct
5265 // {
5266 // union
5267 // {
5268 // int a;
5269 // char a_1;
5270 // };
5271 // union
5272 // {
5273 // int b;
5274 // char b_1;
5275 // };
5276 // };
5277 // int c;
5278 // }; // end struct S
5279 //
5280 var_decl_sptr replaced_dm, replacing_dm;
5281 bool added_anon_dm_changes_dm = false;
5282 // The vector of data members replaced by anonymous
5283 // data members.
5284 vector<var_decl_sptr> dms_replaced_by_anon_dm;
5285
5286 //
5287 // Let's start collecting the set of data members
5288 // which have been replaced by anonymous types in a
5289 // harmless way. These are going to be collected into
5290 // dms_replaced_by_anon_dm and, ultimately, into
5291 // priv_->dms_replaced_by_adms_
5292 //
5293 for (string_decl_base_sptr_map::const_iterator it =
5294 priv_->deleted_data_members_.begin();
5295 it != priv_->deleted_data_members_.end();
5296 ++it)
5297 {
5298 // We don't support this pattern for anonymous
5299 // data members themselves being replaced. If
5300 // that occurs then we'll just report it verbatim.
5301 if (is_anonymous_data_member(it->second))
5302 continue;
5303
5304 string deleted_dm_name = it->second->get_name();
5305 if ((replacing_dm =
5307 deleted_dm_name)))
5308 {
5309 // So it looks like replacing_dm might have
5310 // replaced the data member which name is
5311 // 'deleted_dm_name'. Let's look deeper to be
5312 // sure.
5313 //
5314 // Note that replacing_dm is part (member) of
5315 // an anonymous data member that might replace
5316 // replaced_dm.
5317
5318 // So let's get that replaced data member.
5319 replaced_dm = is_var_decl(it->second);
5320 size_t replaced_dm_offset =
5321 get_data_member_offset(replaced_dm),
5322 replacing_dm_offset =
5323 get_absolute_data_member_offset(replacing_dm);
5324
5325 if (replaced_dm_offset != replacing_dm_offset)
5326 {
5327 // So the replacing data member and the
5328 // replaced data member don't have the
5329 // same offset. This is not the pattern we
5330 // are looking for. Rather, it looks like
5331 // the anonymous data member has *changed*
5332 // the data member.
5333 added_anon_dm_changes_dm = true;
5334 break;
5335 }
5336
5337 if (replaced_dm->get_type()->get_size_in_bits()
5338 == replaced_dm->get_type()->get_size_in_bits())
5339 dms_replaced_by_anon_dm.push_back(replaced_dm);
5340 else
5341 {
5342 added_anon_dm_changes_dm = true;
5343 break;
5344 }
5345 }
5346 }
5347
5348 // Now walk dms_replaced_by_anon_dm to fill up
5349 // priv_->dms_replaced_by_adms_ with the set of data
5350 // members replaced by anonymous data members.
5351 if (!added_anon_dm_changes_dm
5352 && !dms_replaced_by_anon_dm.empty())
5353 {
5354 // See if the added data member isn't too big.
5355 type_base_sptr added_dm_type = added_dm->get_type();
5356 ABG_ASSERT(added_dm_type);
5357 var_decl_sptr new_next_dm =
5359 added_dm);
5360 var_decl_sptr old_next_dm =
5361 first_class_or_union()->find_data_member(new_next_dm);
5362
5363 if (!old_next_dm
5364 || (old_next_dm
5365 && (get_absolute_data_member_offset(old_next_dm)
5366 == get_absolute_data_member_offset(new_next_dm))))
5367 {
5368 // None of the data members that are replaced
5369 // by the added union should be considered as
5370 // having been deleted.
5371 ignore_added_anonymous_data_member = true;
5372 for (vector<var_decl_sptr>::const_iterator i =
5373 dms_replaced_by_anon_dm.begin();
5374 i != dms_replaced_by_anon_dm.end();
5375 ++i)
5376 {
5377 string n = (*i)->get_name();
5378 priv_->dms_replaced_by_adms_[n] =
5379 added_dm;
5380 priv_->deleted_data_members_.erase(n);
5381 }
5382 }
5383 }
5384 }
5385
5386 if (!ignore_added_anonymous_data_member)
5387 {
5388 // Detect changed data members.
5389 //
5390 // A changed data member (that we shall name D) is a data
5391 // member that satisfies the conditions below:
5392 //
5393 // 1/ It must have been added.
5394 //
5395 // 2/ It must have been deleted as well.
5396 //
5397 // 3/ There must be a non-empty difference between the
5398 // deleted D and the added D.
5399 string_decl_base_sptr_map::const_iterator j =
5400 priv_->deleted_data_members_.find(name);
5401 if (j != priv_->deleted_data_members_.end())
5402 {
5403 if (*j->second != *d)
5404 {
5405 var_decl_sptr old_dm = is_var_decl(j->second);
5406 priv_->subtype_changed_dm_[name]=
5407 compute_diff(old_dm, added_dm, context());
5408 }
5409 priv_->deleted_data_members_.erase(j);
5410 }
5411 else
5412 priv_->inserted_data_members_[name] = d;
5413 }
5414 }
5415 }
5416
5417 // Now detect when a data member is deleted from offset N and
5418 // another one is added to offset N. In that case, we want to be
5419 // able to say that the data member at offset N changed.
5420 for (string_decl_base_sptr_map::const_iterator i =
5421 priv_->deleted_data_members_.begin();
5422 i != priv_->deleted_data_members_.end();
5423 ++i)
5424 {
5425 unsigned offset = get_data_member_offset(i->second);
5426 priv_->deleted_dm_by_offset_[offset] = i->second;
5427 }
5428
5429 for (string_decl_base_sptr_map::const_iterator i =
5430 priv_->inserted_data_members_.begin();
5431 i != priv_->inserted_data_members_.end();
5432 ++i)
5433 {
5434 unsigned offset = get_data_member_offset(i->second);
5435 priv_->inserted_dm_by_offset_[offset] = i->second;
5436 }
5437
5438 for (unsigned_decl_base_sptr_map::const_iterator i =
5439 priv_->inserted_dm_by_offset_.begin();
5440 i != priv_->inserted_dm_by_offset_.end();
5441 ++i)
5442 {
5443 unsigned_decl_base_sptr_map::const_iterator j =
5444 priv_->deleted_dm_by_offset_.find(i->first);
5445 if (j != priv_->deleted_dm_by_offset_.end())
5446 {
5447 var_decl_sptr old_dm = is_var_decl(j->second);
5448 var_decl_sptr new_dm = is_var_decl(i->second);
5449 priv_->changed_dm_[i->first] =
5450 compute_diff(old_dm, new_dm, context());
5451 }
5452 }
5453
5454 for (unsigned_var_diff_sptr_map::const_iterator i =
5455 priv_->changed_dm_.begin();
5456 i != priv_->changed_dm_.end();
5457 ++i)
5458 {
5459 priv_->deleted_dm_by_offset_.erase(i->first);
5460 priv_->inserted_dm_by_offset_.erase(i->first);
5461 priv_->deleted_data_members_.erase
5462 (i->second->first_var()->get_anon_dm_reliable_name());
5463 priv_->inserted_data_members_.erase
5464 (i->second->second_var()->get_anon_dm_reliable_name());
5465 }
5466
5467 // Now detect anonymous data members that might appear as deleted
5468 // even though all their data members are still present. Consider
5469 // these as being non-deleted.
5470 string_decl_base_sptr_map non_anonymous_dms_in_second_class;
5472 non_anonymous_dms_in_second_class);
5473 vector<string> deleted_data_members_to_delete;
5474 // Walk data members considered deleted ...
5475 for (auto& entry : priv_->deleted_data_members_)
5476 {
5477 var_decl_sptr data_member = is_var_decl(entry.second);
5478 ABG_ASSERT(data_member);
5479 if (is_anonymous_data_member(data_member))
5480 {
5481 // Let's look at this anonymous data member that is
5482 // considered deleted because it's moved from where it was
5483 // initially, at very least. If its leaf data members are
5484 // still present in the second class then, we won't
5485 // consider it as deleted.
5486 class_or_union_sptr cou = anonymous_data_member_to_class_or_union(data_member);
5487 ABG_ASSERT(cou);
5488 string_decl_base_sptr_map non_anonymous_data_members;
5489 // Lets collect the leaf data members of the anonymous
5490 // data member.
5491 collect_non_anonymous_data_members(cou, non_anonymous_data_members);
5492 bool anonymous_dm_members_present = true;
5493 // Let's see if at least one of the leaf members of the
5494 // anonymous data member is NOT present in the second
5495 // version of the class.
5496 for (auto& e : non_anonymous_data_members)
5497 {
5498 if (non_anonymous_dms_in_second_class.find(e.first)
5499 == non_anonymous_dms_in_second_class.end())
5500 // Grrr, OK, it looks like at least one leaf data
5501 // member of the original anonymous data member was
5502 // removed from the class, so yeah, the anonymous
5503 // data member might have been removed after all.
5504 anonymous_dm_members_present = false;
5505 }
5506 if (anonymous_dm_members_present)
5507 // All leaf data members of the anonymous data member
5508 // are still present in the second version of the class.
5509 // So let's mark that anonymous data member as NOT being
5510 // deleted.
5511 deleted_data_members_to_delete.push_back(data_member->get_anon_dm_reliable_name());
5512 }
5513 }
5514 // All anonymous data members that were recognized as being NOT
5515 // deleted should be removed from the set of deleted data members
5516 // now.
5517 for (string& name_of_dm_to_delete: deleted_data_members_to_delete)
5518 priv_->deleted_data_members_.erase(name_of_dm_to_delete);
5519 }
5520 sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5521 priv_->sorted_subtype_changed_dm_);
5522 sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5523 priv_->sorted_changed_dm_);
5524
5525 {
5526 edit_script& e = priv_->member_class_tmpls_changes_;
5527
5528 for (vector<deletion>::const_iterator it = e.deletions().begin();
5529 it != e.deletions().end();
5530 ++it)
5531 {
5532 unsigned i = it->index();
5533 decl_base_sptr d =
5534 first_class_or_union()->get_member_class_templates()[i]->
5535 as_class_tdecl();
5536 string name = d->get_name();
5537 ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5538 == priv_->deleted_member_class_tmpls_.end());
5539 priv_->deleted_member_class_tmpls_[name] = d;
5540 }
5541
5542 for (vector<insertion>::const_iterator it = e.insertions().begin();
5543 it != e.insertions().end();
5544 ++it)
5545 {
5546 for (vector<unsigned>::const_iterator iit =
5547 it->inserted_indexes().begin();
5548 iit != it->inserted_indexes().end();
5549 ++iit)
5550 {
5551 unsigned i = *iit;
5552 decl_base_sptr d =
5553 second_class_or_union()->get_member_class_templates()[i]->
5554 as_class_tdecl();
5555 string name = d->get_name();
5556 ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5557 == priv_->inserted_member_class_tmpls_.end());
5558 string_decl_base_sptr_map::const_iterator j =
5559 priv_->deleted_member_class_tmpls_.find(name);
5560 if (j != priv_->deleted_member_class_tmpls_.end())
5561 {
5562 if (*j->second != *d)
5563 priv_->changed_member_types_[name]=
5564 compute_diff(j->second, d, context());
5565 priv_->deleted_member_class_tmpls_.erase(j);
5566 }
5567 else
5568 priv_->inserted_member_class_tmpls_[name] = d;
5569 }
5570 }
5571 }
5572 sort_string_diff_sptr_map(priv_->changed_member_types_,
5573 priv_->sorted_changed_member_types_);
5574}
5575
5576/// Allocate the memory for the priv_ pimpl data member of the @ref
5577/// class_or_union_diff class.
5578void
5580{
5581 if (!priv_)
5582 priv_.reset(new priv);
5583}
5584
5585/// Constructor for the @ref class_or_union_diff class.
5586///
5587/// @param first_scope the first @ref class_or_union of the diff node.
5588///
5589/// @param second_scope the second @ref class_or_union of the diff node.
5590///
5591/// @param ctxt the context of the diff.
5592class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5593 class_or_union_sptr second_scope,
5594 diff_context_sptr ctxt)
5595 : type_diff_base(first_scope, second_scope, ctxt)
5596 //priv_(new priv)
5597{}
5598
5599/// Getter of the private data of the @ref class_or_union_diff type.
5600///
5601/// Note that due to an optimization, the private data of @ref
5602/// class_or_union_diff can be shared among several instances of
5603/// class_or_union_diff, so you should never try to access
5604/// class_or_union_diff::priv directly.
5605///
5606/// When class_or_union_diff::priv is shared, this function returns
5607/// the correct shared one.
5608///
5609/// @return the (possibly) shared private data of the current instance
5610/// of @ref class_or_union_diff.
5611const class_or_union_diff::priv_ptr&
5613{
5614 if (priv_)
5615 return priv_;
5616
5617 // If the current class_or_union_diff::priv member is empty, then look for
5618 // the shared one, from the canonical type.
5619 class_or_union_diff *canonical =
5620 dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5621 ABG_ASSERT(canonical);
5622 ABG_ASSERT(canonical->priv_);
5623
5624 return canonical->priv_;
5625}
5626
5627/// Destructor of class_or_union_diff.
5631
5632/// @return the first @ref class_or_union involved in the diff.
5633class_or_union_sptr
5636
5637/// @return the second @ref class_or_union involved in the diff.
5638class_or_union_sptr
5641
5642/// @return the edit script of the member types of the two @ref
5643/// class_or_union.
5644const edit_script&
5646{return get_priv()->member_types_changes_;}
5647
5648/// @return the edit script of the member types of the two @ref
5649/// class_or_union.
5652{return get_priv()->member_types_changes_;}
5653
5654/// @return the edit script of the data members of the two @ref
5655/// class_or_union.
5656const edit_script&
5658{return get_priv()->data_members_changes_;}
5659
5660/// @return the edit script of the data members of the two @ref
5661/// class_or_union.
5664{return get_priv()->data_members_changes_;}
5665
5666/// Getter for the data members that got inserted.
5667///
5668/// @return a map of data members that got inserted.
5671{return get_priv()->inserted_data_members_;}
5672
5673/// Getter for the data members that got deleted.
5674///
5675/// @return a map of data members that got deleted.
5678{return get_priv()->deleted_data_members_;}
5679
5680/// @return the edit script of the member functions of the two @ref
5681/// class_or_union.
5682const edit_script&
5684{return get_priv()->member_fns_changes_;}
5685
5686/// Getter for the virtual members functions that have had a change in
5687/// a sub-type, without having a change in their symbol name.
5688///
5689/// @return a sorted vector of virtual member functions that have a
5690/// sub-type change.
5693{return get_priv()->sorted_changed_member_functions_;}
5694
5695/// @return the edit script of the member functions of the two
5696/// classes.
5699{return get_priv()->member_fns_changes_;}
5700
5701/// @return a map of member functions that got deleted.
5704{return get_priv()->deleted_member_functions_;}
5705
5706/// @return a map of member functions that got inserted.
5709{return get_priv()->inserted_member_functions_;}
5710
5711/// Getter of the map of data members that got replaced by another
5712/// data member. The key of the map is the offset at which the
5713/// element got replaced and the value is a pointer to the @ref
5714/// var_diff representing the replacement of the data member.
5715///
5716/// @return sorted vector of changed data member.
5719{return get_priv()->changed_dm_;}
5720
5721/// Getter of the sorted vector of data members that got replaced by
5722/// another data member.
5723///
5724/// @return sorted vector of changed data member.
5727{return get_priv()->sorted_changed_dm_;}
5728
5729/// Count the number of /filtered/ data members that got replaced by
5730/// another data member.
5731///
5732/// @return the number of changed data member that got filtered out.
5733size_t
5735{return get_priv()->count_filtered_changed_dm(local);}
5736
5737/// Getter of the sorted vector of data members with a (sub-)type change.
5738///
5739/// @return sorted vector of changed data member.
5742{return get_priv()->sorted_subtype_changed_dm_;}
5743
5744/// Count the number of /filtered/ data members with a sub-type change.
5745///
5746/// @return the number of changed data member that got filtered out.
5747size_t
5749{return get_priv()->count_filtered_subtype_changed_dm(local);}
5750
5751/// Get the map of data members that got replaced by anonymous data
5752/// members.
5753///
5754/// The key of a map entry is the name of the replaced data member and
5755/// the value is the anonymous data member that replaces it.
5756///
5757/// @return the map of data members replaced by anonymous data
5758/// members.
5761{return get_priv()->dms_replaced_by_adms_;}
5762
5763/// Get an ordered vector of of data members that got replaced by
5764/// anonymous data members.
5765///
5766/// This returns a vector of pair of two data members: the one that
5767/// was replaced, and the anonymous data member that replaced it.
5768///
5769/// @return the sorted vector data members replaced by anonymous data members.
5772{
5773 if (priv_->dms_replaced_by_adms_ordered_.empty())
5774 {
5775 for (string_decl_base_sptr_map::const_iterator it =
5776 priv_->dms_replaced_by_adms_.begin();
5777 it != priv_->dms_replaced_by_adms_.end();
5778 ++it)
5779 {
5780 const var_decl_sptr dm =
5781 first_class_or_union()->find_data_member(it->first);
5782 ABG_ASSERT(dm);
5783 changed_var_sptr changed_dm(dm, is_data_member(it->second));
5784 priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5785 }
5786 sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5787 }
5788
5789 return priv_->dms_replaced_by_adms_ordered_;
5790}
5791
5792/// @return the edit script of the member function templates of the two
5793/// @ref class_or_union.
5794const edit_script&
5796{return get_priv()->member_fn_tmpls_changes_;}
5797
5798/// @return the edit script of the member function templates of the
5799/// two @ref class_or_union.
5802{return get_priv()->member_fn_tmpls_changes_;}
5803
5804/// @return the edit script of the member class templates of the two
5805/// @ref class_or_union.
5806const edit_script&
5808{return get_priv()->member_class_tmpls_changes_;}
5809
5810/// @return the edit script of the member class templates of the two
5811/// @ref class_or_union.
5814{return get_priv()->member_class_tmpls_changes_;}
5815
5816/// Test if the current diff node carries a change.
5817bool
5820
5821/// @return the kind of local change carried by the current diff node.
5822/// The value returned is zero if the current node carries no local
5823/// change.
5824enum change_kind
5826{
5827 ir::change_kind k = ir::NO_CHANGE_KIND;
5829 return k & ir::ALL_LOCAL_CHANGES_MASK;
5830 return ir::NO_CHANGE_KIND;
5831}
5832
5833
5834/// Report the changes carried by the current @ref class_or_union_diff
5835/// node in a textual format.
5836///
5837/// @param out the output stream to write the textual report to.
5838///
5839/// @param indent the number of white space to use as indentation.
5840void
5841class_or_union_diff::report(ostream& out, const string& indent) const
5842{
5843 context()->get_reporter()->report(*this, out, indent);
5844}
5845
5846/// Populate the vector of children node of the @ref diff base type
5847/// sub-object of this instance of @ref class_or_union_diff.
5848///
5849/// The children node can then later be retrieved using
5850/// diff::children_node().
5851void
5853{
5854 // data member changes
5855 for (var_diff_sptrs_type::const_iterator i =
5856 get_priv()->sorted_subtype_changed_dm_.begin();
5857 i != get_priv()->sorted_subtype_changed_dm_.end();
5858 ++i)
5859 if (diff_sptr d = *i)
5861
5862 for (var_diff_sptrs_type::const_iterator i =
5863 get_priv()->sorted_changed_dm_.begin();
5864 i != get_priv()->sorted_changed_dm_.end();
5865 ++i)
5866 if (diff_sptr d = *i)
5868
5869 // member types changes
5870 for (diff_sptrs_type::const_iterator i =
5871 get_priv()->sorted_changed_member_types_.begin();
5872 i != get_priv()->sorted_changed_member_types_.end();
5873 ++i)
5874 if (diff_sptr d = *i)
5876
5877 // member function changes
5878 for (function_decl_diff_sptrs_type::const_iterator i =
5879 get_priv()->sorted_changed_member_functions_.begin();
5880 i != get_priv()->sorted_changed_member_functions_.end();
5881 ++i)
5882 if (diff_sptr d = *i)
5884}
5885
5886// </class_or_union_diff stuff>
5887
5888//<class_diff stuff>
5889
5890/// Clear the lookup tables useful for reporting.
5891///
5892/// This function must be updated each time a lookup table is added or
5893/// removed from the class_diff::priv.
5894void
5895class_diff::clear_lookup_tables(void)
5896{
5897 priv_->deleted_bases_.clear();
5898 priv_->inserted_bases_.clear();
5899 priv_->changed_bases_.clear();
5900}
5901
5902/// Tests if the lookup tables are empty.
5903///
5904/// @return true if the lookup tables are empty, false otherwise.
5905bool
5906class_diff::lookup_tables_empty(void) const
5907{
5908 return (priv_->deleted_bases_.empty()
5909 && priv_->inserted_bases_.empty()
5910 && priv_->changed_bases_.empty());
5911}
5912
5913/// Find a virtual destructor in a map of member functions
5914///
5915/// @param map the map of member functions. Note that the key of the
5916/// map is the member function name. The key is the member function.
5917///
5918/// @return an iterator to the destructor found or, if no virtual destructor
5919/// was found, return map.end()
5920static string_member_function_sptr_map::const_iterator
5921find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
5922{
5923 for (string_member_function_sptr_map::const_iterator i = map.begin();
5924 i !=map.end();
5925 ++i)
5926 {
5927 if (get_member_function_is_dtor(i->second)
5928 && get_member_function_is_virtual(i->second))
5929 return i;
5930 }
5931 return map.end();
5932}
5933
5934/// If the lookup tables are not yet built, walk the differences and
5935/// fill them.
5936void
5937class_diff::ensure_lookup_tables_populated(void) const
5938{
5940
5941 if (!lookup_tables_empty())
5942 return;
5943
5944 {
5945 edit_script& e = get_priv()->base_changes_;
5946
5947 for (vector<deletion>::const_iterator it = e.deletions().begin();
5948 it != e.deletions().end();
5949 ++it)
5950 {
5951 unsigned i = it->index();
5953 first_class_decl()->get_base_specifiers()[i];
5954 string name = b->get_base_class()->get_qualified_name();
5955 ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5956 == get_priv()->deleted_bases_.end());
5957 get_priv()->deleted_bases_[name] = b;
5958 }
5959
5960 for (vector<insertion>::const_iterator it = e.insertions().begin();
5961 it != e.insertions().end();
5962 ++it)
5963 {
5964 for (vector<unsigned>::const_iterator iit =
5965 it->inserted_indexes().begin();
5966 iit != it->inserted_indexes().end();
5967 ++iit)
5968 {
5969 unsigned i = *iit;
5971 second_class_decl()->get_base_specifiers()[i];
5972 string name = b->get_base_class()->get_qualified_name();
5973 ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5974 == get_priv()->inserted_bases_.end());
5975 string_base_sptr_map::const_iterator j =
5976 get_priv()->deleted_bases_.find(name);
5977 if (j != get_priv()->deleted_bases_.end())
5978 {
5979 if (j->second != b)
5980 get_priv()->changed_bases_[name] =
5981 compute_diff(j->second, b, context());
5982 else
5983 // The base class changed place. IOW, the base
5984 // classes got re-arranged. Let's keep track of the
5985 // base classes that moved.
5986 get_priv()->moved_bases_.push_back(b);
5987 get_priv()->deleted_bases_.erase(j);
5988 }
5989 else
5990 get_priv()->inserted_bases_[name] = b;
5991 }
5992 }
5993
5994 // ===============================================================
5995 // Detect when a data member is deleted from the class but is now
5996 // present in one of the bases at the same offset. In that case,
5997 // the data member should not be considered as removed.
5998 // ===============================================================
6000 class_or_union_diff::priv_->deleted_data_members_;
6001
6002 vector<var_decl_sptr> deleted_data_members_present_in_bases;
6003 for (auto entry : deleted_data_members)
6004 {
6005 var_decl_sptr deleted_member = is_var_decl(entry.second);
6006 ABG_ASSERT(deleted_member);
6007 for (class_decl::base_spec_sptr base : second_class_decl()->get_base_specifiers())
6008 {
6009 class_decl_sptr klass = base->get_base_class();
6010 var_decl_sptr member = klass->find_data_member(deleted_member->get_name());
6011 if (member)
6012 deleted_data_members_present_in_bases.push_back(member);
6013 }
6014 }
6015 // Walk the deleted data members that are now in one of the bases,
6016 // of the new type, at the same offset, and let's see if they have
6017 // sub-type changes. In any cases, these should not be considered
6018 // as being deleted.
6019 for (var_decl_sptr m : deleted_data_members_present_in_bases)
6020 {
6021 string name = m->get_name();
6022 auto it = deleted_data_members.find(name);
6023 ABG_ASSERT(it != deleted_data_members.end());
6024 var_decl_sptr deleted_member = is_var_decl(it->second);
6025 if (*deleted_member != *m)
6026 {
6027 var_diff_sptr dif = compute_diff(deleted_member, m, context());
6028 ABG_ASSERT(dif);
6029 class_or_union_diff::priv_->subtype_changed_dm_[name]= dif;
6030 }
6031 deleted_data_members.erase(name);
6032 }
6033 }
6034
6035 sort_string_base_sptr_map(get_priv()->deleted_bases_,
6036 get_priv()->sorted_deleted_bases_);
6037 sort_string_base_sptr_map(get_priv()->inserted_bases_,
6038 get_priv()->sorted_inserted_bases_);
6039 sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
6040 get_priv()->sorted_changed_bases_);
6041
6042 {
6043 const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
6044
6045 edit_script& e = p->member_fns_changes_;
6046
6047 for (vector<deletion>::const_iterator it = e.deletions().begin();
6048 it != e.deletions().end();
6049 ++it)
6050 {
6051 unsigned i = it->index();
6052 method_decl_sptr mem_fn =
6053 first_class_decl()->get_virtual_mem_fns()[i];
6054 string name = mem_fn->get_linkage_name();
6055 if (name.empty())
6056 name = mem_fn->get_pretty_representation();
6057 ABG_ASSERT(!name.empty());
6058 if (p->deleted_member_functions_.find(name)
6059 != p->deleted_member_functions_.end())
6060 continue;
6061 p->deleted_member_functions_[name] = mem_fn;
6062 }
6063
6064 for (vector<insertion>::const_iterator it = e.insertions().begin();
6065 it != e.insertions().end();
6066 ++it)
6067 {
6068 for (vector<unsigned>::const_iterator iit =
6069 it->inserted_indexes().begin();
6070 iit != it->inserted_indexes().end();
6071 ++iit)
6072 {
6073 unsigned i = *iit;
6074
6075 method_decl_sptr mem_fn =
6076 second_class_decl()->get_virtual_mem_fns()[i];
6077 string name = mem_fn->get_linkage_name();
6078 if (name.empty())
6079 name = mem_fn->get_pretty_representation();
6080 ABG_ASSERT(!name.empty());
6081 if (p->inserted_member_functions_.find(name)
6082 != p->inserted_member_functions_.end())
6083 continue;
6084 string_member_function_sptr_map::const_iterator j =
6085 p->deleted_member_functions_.find(name);
6086
6087 if (j != p->deleted_member_functions_.end())
6088 {
6089 if (*j->second != *mem_fn)
6090 p->changed_member_functions_[name] =
6091 compute_diff(static_pointer_cast<function_decl>(j->second),
6092 static_pointer_cast<function_decl>(mem_fn),
6093 context());
6094 p->deleted_member_functions_.erase(j);
6095 }
6096 else
6097 p->inserted_member_functions_[name] = mem_fn;
6098 }
6099 }
6100
6101 // Now walk the allegedly deleted member functions; check if their
6102 // underlying symbols are deleted as well; otherwise, consider
6103 // that the member function in question hasn't been deleted.
6104
6105 // Also, while walking the deleted member functions, we attend at
6106 // a particular cleanup business related to (virtual) C++
6107 // destructors:
6108 //
6109 // In the binary, there can be at least three types of
6110 // destructors, defined in the document
6111 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
6112 //
6113 // 1/ Base object destructor (aka D2 destructor):
6114 //
6115 // "A function that runs the destructors for non-static data
6116 // members of T and non-virtual direct base classes of T. "
6117 //
6118 // 2/ Complete object destructor (aka D1 destructor):
6119 //
6120 // "A function that, in addition to the actions required of a
6121 // base object destructor, runs the destructors for the
6122 // virtual base classes of T."
6123 //
6124 // 3/ Deleting destructor (aka D0 destructor):
6125 //
6126 // "A function that, in addition to the actions required of a
6127 // complete object destructor, calls the appropriate
6128 // deallocation function (i.e,. operator delete) for T."
6129 //
6130 // With binaries generated by GCC, these destructors might be ELF
6131 // clones of each others, meaning, their ELF symbols can be
6132 // aliases.
6133 //
6134 // Also, note that because the actual destructor invoked by user
6135 // code is virtual, it's invoked through the vtable. So the
6136 // presence of the underlying D0, D1, D2 in the binary might vary
6137 // without that variation being an ABI issue, provided that the
6138 // destructor invoked through the vtable is present.
6139 //
6140 // So, a particular virtual destructor implementation for a class
6141 // might disapear and be replaced by another one in a subsequent
6142 // version of the binary. If all versions of the binary have an
6143 // actual virtual destructor, things might be considered fine.
6144 vector<string> to_delete;
6145 corpus_sptr f = context()->get_first_corpus(),
6146 s = context()->get_second_corpus();
6147 if (s)
6148 for (string_member_function_sptr_map::const_iterator i =
6149 deleted_member_fns().begin();
6150 i != deleted_member_fns().end();
6151 ++i)
6152 {
6153 if (get_member_function_is_virtual(i->second))
6154 {
6155 if (get_member_function_is_dtor(i->second))
6156 {
6157 // If a particular virtual destructor is deleted,
6158 // but the new binary still have a virtual
6159 // destructor for that class we consider that things
6160 // are fine. For instance, in the
6161 // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
6162 // test, a new D4 destructor replaces the old ones.
6163 // But because the virtual destructor is still
6164 // there, this is not an ABI issue. So let's detect
6165 // this case.
6166 auto it =
6167 find_virtual_dtor_in_map(p->inserted_member_functions_);
6168 if (it != p->inserted_member_functions_.end())
6169 {
6170 // So the deleted virtual destructor is not
6171 // really deleted, because a proper virtual
6172 // destructor was added to the new version.
6173 // Let's remove the deleted/added virtual
6174 // destructor then.
6175 string name =
6176 (!i->second->get_linkage_name().empty())
6177 ? i->second->get_linkage_name()
6178 : i->second->get_pretty_representation();
6179 to_delete.push_back(name);
6180 p->inserted_member_functions_.erase(it);
6181 }
6182 }
6183 continue;
6184 }
6185 // We assume that all non-virtual member functions functions
6186 // we look at here have ELF symbols.
6187 if (!i->second->get_symbol()
6188 || s->lookup_function_symbol(*i->second->get_symbol()))
6189 to_delete.push_back(i->first);
6190 }
6191
6192
6193 for (vector<string>::const_iterator i = to_delete.begin();
6194 i != to_delete.end();
6195 ++i)
6196 p->deleted_member_functions_.erase(*i);
6197
6198 // Do something similar for added functions.
6199 to_delete.clear();
6200 if (f)
6201 for (string_member_function_sptr_map::const_iterator i =
6202 inserted_member_fns().begin();
6203 i != inserted_member_fns().end();
6204 ++i)
6205 {
6206 if (get_member_function_is_virtual(i->second))
6207 continue;
6208 // We assume that all non-virtual member functions functions
6209 // we look at here have ELF symbols.
6210 if (!i->second->get_symbol()
6211 || f->lookup_function_symbol(*i->second->get_symbol()))
6212 to_delete.push_back(i->first);
6213 }
6214
6215 for (vector<string>::const_iterator i = to_delete.begin();
6216 i != to_delete.end();
6217 ++i)
6218 p->inserted_member_functions_.erase(*i);
6219
6220 sort_string_member_function_sptr_map(p->deleted_member_functions_,
6221 p->sorted_deleted_member_functions_);
6222
6223 sort_string_member_function_sptr_map(p->inserted_member_functions_,
6224 p->sorted_inserted_member_functions_);
6225
6227 (p->changed_member_functions_,
6228 p->sorted_changed_member_functions_);
6229 }
6230}
6231
6232/// Allocate the memory for the priv_ pimpl data member of the @ref
6233/// class_diff class.
6234void
6235class_diff::allocate_priv_data()
6236{
6238 if (!priv_)
6239 priv_.reset(new priv);
6240}
6241
6242/// Test whether a given base class has changed. A base class has
6243/// changed if it's in both in deleted *and* inserted bases.
6244///
6245///@param d the declaration for the base class to consider.
6246///
6247/// @return the new base class if the given base class has changed, or
6248/// NULL if it hasn't.
6251{
6252 string qname = d->get_base_class()->get_qualified_name();
6253 string_base_diff_sptr_map::const_iterator it =
6254 changed_bases_.find(qname);
6255
6256 return (it == changed_bases_.end())
6258 : it->second->second_base();
6259
6260}
6261
6262/// Count the number of bases classes whose changes got filtered out.
6263///
6264/// @return the number of bases classes whose changes got filtered
6265/// out.
6266size_t
6268{
6269 size_t num_filtered = 0;
6270 for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
6271 i != sorted_changed_bases_.end();
6272 ++i)
6273 {
6274 diff_sptr diff = *i;
6275 if (diff && diff->is_filtered_out())
6276 ++num_filtered;
6277 }
6278 return num_filtered;
6279}
6280
6281/// Populate the vector of children node of the @ref diff base type
6282/// sub-object of this instance of @ref class_diff.
6283///
6284/// The children node can then later be retrieved using
6285/// diff::children_node().
6286void
6288{
6290
6291 // base class changes.
6292 for (base_diff_sptrs_type::const_iterator i =
6293 get_priv()->sorted_changed_bases_.begin();
6294 i != get_priv()->sorted_changed_bases_.end();
6295 ++i)
6296 if (diff_sptr d = *i)
6298}
6299
6300/// Constructor of class_diff
6301///
6302/// @param first_scope the first class of the diff.
6303///
6304/// @param second_scope the second class of the diff.
6305///
6306/// @param ctxt the diff context to use.
6308 class_decl_sptr second_scope,
6309 diff_context_sptr ctxt)
6310 : class_or_union_diff(first_scope, second_scope, ctxt)
6311 // We don't initialize the priv_ data member here. This is an
6312 // optimization to reduce memory consumption (and also execution
6313 // time) for cases where there are a lot of instances of
6314 // class_diff in the same equivalence class. In compute_diff(),
6315 // the priv_ is set to the priv_ of the canonical diff node.
6316 // See PR libabigail/17948.
6317{}
6318
6319class_diff::~class_diff()
6320{}
6321
6322/// Getter of the private data of the @ref class_diff type.
6323///
6324/// Note that due to an optimization, the private data of @ref
6325/// class_diff can be shared among several instances of class_diff, so
6326/// you should never try to access class_diff::priv directly.
6327///
6328/// When class_diff::priv is shared, this function returns the correct
6329/// shared one.
6330///
6331/// @return the (possibly) shared private data of the current instance
6332/// of class_diff.
6333const class_diff::priv_ptr&
6334class_diff::get_priv() const
6335{
6336 if (priv_)
6337 return priv_;
6338
6339 // If the current class_diff::priv member is empty, then look for
6340 // the shared one, from the canonical type.
6341 class_diff *canonical =
6342 dynamic_cast<class_diff*>(get_canonical_diff());
6343 ABG_ASSERT(canonical);
6344 ABG_ASSERT(canonical->priv_);
6345
6346 return canonical->priv_;
6347}
6348
6349/// @return the pretty representation of the current instance of @ref
6350/// class_diff.
6351const string&
6353{
6354 if (diff::priv_->pretty_representation_.empty())
6355 {
6356 std::ostringstream o;
6357 o << "class_diff["
6358 << first_subject()->get_pretty_representation()
6359 << ", "
6360 << second_subject()->get_pretty_representation()
6361 << "]";
6362 diff::priv_->pretty_representation_ = o.str();
6363 }
6364 return diff::priv_->pretty_representation_;
6365}
6366
6367/// Return true iff the current diff node carries a change.
6368///
6369/// @return true iff the current diff node carries a change.
6370bool
6373
6374/// @return the kind of local change carried by the current diff node.
6375/// The value returned is zero if the current node carries no local
6376/// change.
6377enum change_kind
6379{
6380 ir::change_kind k = ir::NO_CHANGE_KIND;
6381 if (!equals(*first_class_decl(), *second_class_decl(), &k))
6382 return k & ir::ALL_LOCAL_CHANGES_MASK;
6383 return ir::NO_CHANGE_KIND;
6384}
6385
6386/// @return the first class invoveld in the diff.
6387shared_ptr<class_decl>
6389{return dynamic_pointer_cast<class_decl>(first_subject());}
6390
6391/// Getter of the second class involved in the diff.
6392///
6393/// @return the second class invoveld in the diff
6394shared_ptr<class_decl>
6396{return dynamic_pointer_cast<class_decl>(second_subject());}
6397
6398/// @return the edit script of the bases of the two classes.
6399const edit_script&
6401{return get_priv()->base_changes_;}
6402
6403/// Getter for the deleted base classes of the diff.
6404///
6405/// @return a map containing the deleted base classes, keyed with
6406/// their pretty representation.
6409{return get_priv()->deleted_bases_;}
6410
6411/// Getter for the inserted base classes of the diff.
6412///
6413/// @return a map containing the inserted base classes, keyed with
6414/// their pretty representation.
6417{return get_priv()->inserted_bases_;}
6418
6419/// Getter for the changed base classes of the diff.
6420///
6421/// @return a sorted vector containing the changed base classes
6424{return get_priv()->sorted_changed_bases_;}
6425
6426/// Getter for the vector of bases that "moved".
6427/// That is, the vector of base types which position changed. If this
6428/// vector is not empty, it means the bases of the underlying class
6429/// type got re-ordered.
6430///
6431/// @return the vector of bases that moved.
6432const vector<class_decl::base_spec_sptr>&
6434{return get_priv()->moved_bases_;}
6435
6436/// @return the edit script of the bases of the two classes.
6439{return get_priv()->base_changes_;}
6440
6441/// Produce a basic report about the changes between two class_decl.
6442///
6443/// @param out the output stream to report the changes to.
6444///
6445/// @param indent the string to use as an indentation prefix in the
6446/// report.
6447void
6448class_diff::report(ostream& out, const string& indent) const
6449{
6450 context()->get_reporter()->report(*this, out, indent);
6451}
6452
6453/// Compute the set of changes between two instances of class_decl.
6454///
6455/// Note that the two types must have been created in the same @ref
6456/// environment, otherwise, this function aborts.
6457///
6458/// @param first the first class_decl to consider.
6459///
6460/// @param second the second class_decl to consider.
6461///
6462/// @return changes the resulting changes.
6463///
6464/// @param ctxt the diff context to use.
6467 const class_decl_sptr second,
6468 diff_context_sptr ctxt)
6469{
6472
6473 class_diff_sptr changes(new class_diff(f, s, ctxt));
6474
6475 ctxt->initialize_canonical_diff(changes);
6476 ABG_ASSERT(changes->get_canonical_diff());
6477
6478 if (!ctxt->get_canonical_diff_for(first, second))
6479 {
6480 // Either first or second is a decl-only class; let's set the
6481 // canonical diff here in that case.
6482 diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6483 ABG_ASSERT(canonical_diff);
6484 ctxt->set_canonical_diff_for(first, second, canonical_diff);
6485 }
6486
6487 // Ok, so this is an optimization. Do not freak out if it looks
6488 // weird, because, well, it does look weird. This speeds up
6489 // greatly, for instance, the test case given at PR
6490 // libabigail/17948.
6491 //
6492 // We are setting the private data of the new instance of class_diff
6493 // (which is 'changes') to the private data of its canonical
6494 // instance. That is, we are sharing the private data of 'changes'
6495 // with the private data of its canonical instance to consume less
6496 // memory in cases where the equivalence class of 'changes' is huge.
6497 //
6498 // But if changes is its own canonical instance, then we initialize
6499 // its private data properly
6500 if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6501 // changes is its own canonical instance, so it gets a brand new
6502 // private data.
6503 changes->allocate_priv_data();
6504 else
6505 {
6506 // changes has a non-empty equivalence class so it's going to
6507 // share its private data with its canonical instance. Next
6508 // time class_diff::get_priv() is invoked, it's going to return
6509 // the shared private data of the canonical instance.
6510 return changes;
6511 }
6512
6513 // Compare base specs
6514 compute_diff(f->get_base_specifiers().begin(),
6515 f->get_base_specifiers().end(),
6516 s->get_base_specifiers().begin(),
6517 s->get_base_specifiers().end(),
6518 changes->base_changes());
6519
6520 // Do *not* compare member types because it generates lots of noise
6521 // and I doubt it's really useful.
6522#if 0
6523 compute_diff(f->get_member_types().begin(),
6524 f->get_member_types().end(),
6525 s->get_member_types().begin(),
6526 s->get_member_types().end(),
6527 changes->member_types_changes());
6528#endif
6529
6530 // Compare data member
6531 compute_diff(f->get_non_static_data_members().begin(),
6532 f->get_non_static_data_members().end(),
6533 s->get_non_static_data_members().begin(),
6534 s->get_non_static_data_members().end(),
6535 changes->data_members_changes());
6536
6537 // Compare virtual member functions
6538 compute_diff(f->get_virtual_mem_fns().begin(),
6539 f->get_virtual_mem_fns().end(),
6540 s->get_virtual_mem_fns().begin(),
6541 s->get_virtual_mem_fns().end(),
6542 changes->member_fns_changes());
6543
6544 // Compare member function templates
6545 compute_diff(f->get_member_function_templates().begin(),
6546 f->get_member_function_templates().end(),
6547 s->get_member_function_templates().begin(),
6548 s->get_member_function_templates().end(),
6549 changes->member_fn_tmpls_changes());
6550
6551 // Likewise, do not compare member class templates
6552#if 0
6553 compute_diff(f->get_member_class_templates().begin(),
6554 f->get_member_class_templates().end(),
6555 s->get_member_class_templates().begin(),
6556 s->get_member_class_templates().end(),
6557 changes->member_class_tmpls_changes());
6558#endif
6559
6560 changes->ensure_lookup_tables_populated();
6561
6562 return changes;
6563}
6564
6565//</class_diff stuff>
6566
6567// <base_diff stuff>
6568
6569/// Populate the vector of children node of the @ref diff base type
6570/// sub-object of this instance of @ref base_diff.
6571///
6572/// The children node can then later be retrieved using
6573/// diff::children_node().
6574void
6577
6578/// @param first the first base spec to consider.
6579///
6580/// @param second the second base spec to consider.
6581///
6582/// @param ctxt the context of the diff. Note that this context
6583/// object must stay alive at least during the life time of the
6584/// current instance of @ref base_diff. Otherwise memory corruption
6585/// issues occur.
6588 class_diff_sptr underlying,
6589 diff_context_sptr ctxt)
6590 : diff(first, second, ctxt),
6591 priv_(new priv(underlying))
6592{}
6593
6594/// Getter for the first base spec of the diff object.
6595///
6596/// @return the first base specifier for the diff object.
6599{return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6600
6601/// Getter for the second base spec of the diff object.
6602///
6603/// @return the second base specifier for the diff object.
6606{return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6607
6608/// Getter for the diff object for the diff of the underlying base
6609/// classes.
6610///
6611/// @return the diff object for the diff of the underlying base
6612/// classes.
6613const class_diff_sptr
6615{return priv_->underlying_class_diff_;}
6616
6617/// Setter for the diff object for the diff of the underlyng base
6618/// classes.
6619///
6620/// @param d the new diff object for the diff of the underlying base
6621/// classes.
6622void
6624{priv_->underlying_class_diff_ = d;}
6625
6626/// @return the pretty representation for the current instance of @ref
6627/// base_diff.
6628const string&
6630{
6631 if (diff::priv_->pretty_representation_.empty())
6632 {
6633 std::ostringstream o;
6634 o << "base_diff["
6635 << first_subject()->get_pretty_representation()
6636 << ", "
6637 << second_subject()->get_pretty_representation()
6638 << "]";
6639 diff::priv_->pretty_representation_ = o.str();
6640 }
6641 return diff::priv_->pretty_representation_;
6642}
6643
6644/// Return true iff the current diff node carries a change.
6645///
6646/// Return true iff the current diff node carries a change.
6647bool
6649{return first_base() != second_base();}
6650
6651/// @return the kind of local change carried by the current diff node.
6652/// The value returned is zero if the current node carries no local
6653/// change.
6654enum change_kind
6656{
6657 ir::change_kind k = ir::NO_CHANGE_KIND;
6658 if (!equals(*first_base(), *second_base(), &k))
6659 return k & ir::ALL_LOCAL_CHANGES_MASK;
6660 return ir::NO_CHANGE_KIND;
6661}
6662
6663/// Generates a report for the current instance of base_diff.
6664///
6665/// @param out the output stream to send the report to.
6666///
6667/// @param indent the string to use for indentation.
6668void
6669base_diff::report(ostream& out, const string& indent) const
6670{
6671 context()->get_reporter()->report(*this, out, indent);
6672}
6673
6674/// Constructs the diff object representing a diff between two base
6675/// class specifications.
6676///
6677/// Note that the two artifacts must have been created in the same
6678/// @ref environment, otherwise, this function aborts.
6679///
6680/// @param first the first base class specification.
6681///
6682/// @param second the second base class specification.
6683///
6684/// @param ctxt the content of the diff.
6685///
6686/// @return the resulting diff object.
6689 const class_decl::base_spec_sptr second,
6690 diff_context_sptr ctxt)
6691{
6692 class_diff_sptr cl = compute_diff(first->get_base_class(),
6693 second->get_base_class(),
6694 ctxt);
6695 base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6696
6697 ctxt->initialize_canonical_diff(changes);
6698
6699 return changes;
6700}
6701
6702// </base_diff stuff>
6703
6704
6705// <union_diff stuff>
6706
6707/// Clear the lookup tables useful for reporting.
6708///
6709/// This function must be updated each time a lookup table is added or
6710/// removed from the union_diff::priv.
6711void
6712union_diff::clear_lookup_tables(void)
6714
6715/// Tests if the lookup tables are empty.
6716///
6717/// @return true if the lookup tables are empty, false otherwise.
6718bool
6719union_diff::lookup_tables_empty(void) const
6721
6722/// If the lookup tables are not yet built, walk the differences and
6723/// fill them.
6724void
6725union_diff::ensure_lookup_tables_populated(void) const
6727
6728/// Allocate the memory for the priv_ pimpl data member of the @ref
6729/// union_diff class.
6730void
6731union_diff::allocate_priv_data()
6732{
6734}
6735
6736/// Constructor for the @ref union_diff type.
6737///
6738/// @param first_union the first object of the comparison.
6739///
6740/// @param second_union the second object of the comparison.
6741///
6742/// @param ctxt the context of the comparison.
6743union_diff::union_diff(union_decl_sptr first_union,
6744 union_decl_sptr second_union,
6745 diff_context_sptr ctxt)
6746 : class_or_union_diff(first_union, second_union, ctxt)
6747{}
6748
6749/// Destructor of the union_diff node.
6752
6753/// @return the first object of the comparison.
6754union_decl_sptr
6757
6758/// @return the second object of the comparison.
6759union_decl_sptr
6762
6763/// @return the pretty representation of the current diff node.
6764const string&
6766{
6767 if (diff::priv_->pretty_representation_.empty())
6768 {
6769 std::ostringstream o;
6770 o << "union_diff["
6771 << first_subject()->get_pretty_representation()
6772 << ", "
6773 << second_subject()->get_pretty_representation()
6774 << "]";
6775 diff::priv_->pretty_representation_ = o.str();
6776 }
6777 return diff::priv_->pretty_representation_;
6778}
6779
6780/// Report the changes carried by the current @ref union_diff node in
6781/// a textual format.
6782///
6783/// @param out the output stream to write the textual report to.
6784///
6785/// @param indent the number of white space to use as indentation.
6786void
6787union_diff::report(ostream& out, const string& indent) const
6788{
6789 context()->get_reporter()->report(*this, out, indent);
6790}
6791
6792/// Compute the difference between two @ref union_decl types.
6793///
6794/// Note that the two types must hav been created in the same
6795/// environment, otherwise, this function aborts.
6796///
6797/// @param first the first @ref union_decl to consider.
6798///
6799/// @param second the second @ref union_decl to consider.
6800///
6801/// @param ctxt the context of the diff to use.
6802union_diff_sptr
6803compute_diff(const union_decl_sptr first,
6804 const union_decl_sptr second,
6805 diff_context_sptr ctxt)
6806{
6807 union_diff_sptr changes(new union_diff(first, second, ctxt));
6808
6809 ctxt->initialize_canonical_diff(changes);
6810 ABG_ASSERT(changes->get_canonical_diff());
6811
6812 // Ok, so this is an optimization. Do not freak out if it looks
6813 // weird, because, well, it does look weird. This speeds up
6814 // greatly, for instance, the test case given at PR
6815 // libabigail/17948.
6816 //
6817 // We are setting the private data of the new instance of class_diff
6818 // (which is 'changes') to the private data of its canonical
6819 // instance. That is, we are sharing the private data of 'changes'
6820 // with the private data of its canonical instance to consume less
6821 // memory in cases where the equivalence class of 'changes' is huge.
6822 //
6823 // But if changes is its own canonical instance, then we initialize
6824 // its private data properly.
6825 if (is_union_diff(changes->get_canonical_diff()) == changes.get())
6826 // changes is its own canonical instance, so it gets a brand new
6827 // private data.
6828 changes->allocate_priv_data();
6829 else
6830 {
6831 // changes has a non-empty equivalence class so it's going to
6832 // share its private data with its canonical instance. Next
6833 // time class_diff::get_priv() is invoked, it's going to return
6834 // the shared private data of the canonical instance.
6835 return changes;
6836 }
6837
6838 // Compare data member
6839 compute_diff(first->get_non_static_data_members().begin(),
6840 first->get_non_static_data_members().end(),
6841 second->get_non_static_data_members().begin(),
6842 second->get_non_static_data_members().end(),
6843 changes->data_members_changes());
6844
6845#if 0
6846 // Compare member functions
6847 compute_diff(first->get_mem_fns().begin(),
6848 first->get_mem_fns().end(),
6849 second->get_mem_fns().begin(),
6850 second->get_mem_fns().end(),
6851 changes->member_fns_changes());
6852
6853 // Compare member function templates
6854 compute_diff(first->get_member_function_templates().begin(),
6855 first->get_member_function_templates().end(),
6856 second->get_member_function_templates().begin(),
6857 second->get_member_function_templates().end(),
6858 changes->member_fn_tmpls_changes());
6859#endif
6860
6861 changes->ensure_lookup_tables_populated();
6862
6863 return changes;
6864}
6865
6866// </union_diff stuff>
6867
6868//<scope_diff stuff>
6869
6870/// Clear the lookup tables that are useful for reporting.
6871///
6872/// This function must be updated each time a lookup table is added or
6873/// removed.
6874void
6875scope_diff::clear_lookup_tables()
6876{
6877 priv_->deleted_types_.clear();
6878 priv_->deleted_decls_.clear();
6879 priv_->inserted_types_.clear();
6880 priv_->inserted_decls_.clear();
6881 priv_->changed_types_.clear();
6882 priv_->changed_decls_.clear();
6883 priv_->removed_types_.clear();
6884 priv_->removed_decls_.clear();
6885 priv_->added_types_.clear();
6886 priv_->added_decls_.clear();
6887}
6888
6889/// Tests if the lookup tables are empty.
6890///
6891/// This function must be updated each time a lookup table is added or
6892/// removed.
6893///
6894/// @return true iff all the lookup tables are empty.
6895bool
6896scope_diff::lookup_tables_empty() const
6897{
6898 return (priv_->deleted_types_.empty()
6899 && priv_->deleted_decls_.empty()
6900 && priv_->inserted_types_.empty()
6901 && priv_->inserted_decls_.empty()
6902 && priv_->changed_types_.empty()
6903 && priv_->changed_decls_.empty()
6904 && priv_->removed_types_.empty()
6905 && priv_->removed_decls_.empty()
6906 && priv_->added_types_.empty()
6907 && priv_->added_decls_.empty());
6908}
6909
6910/// If the lookup tables are not yet built, walk the member_changes_
6911/// member and fill the lookup tables.
6912void
6913scope_diff::ensure_lookup_tables_populated()
6914{
6915 if (!lookup_tables_empty())
6916 return;
6917
6918 edit_script& e = priv_->member_changes_;
6919
6920 // Populate deleted types & decls lookup tables.
6921 for (const auto& deletion : e.deletions())
6922 {
6923 unsigned i = deletion.index();
6924 decl_base_sptr decl = deleted_member_at(i);
6925 string qname = decl->get_qualified_name();
6926 if (is_type(decl))
6927 {
6928 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6929 if (klass_decl && klass_decl->get_is_declaration_only())
6930 continue;
6931
6932 // Unique types are artifically put in a scope because they
6933 // have to belong somewhere, but they should not be
6934 // considered added/removed from any scope because they are
6935 // artificial and always present in the system.
6936 if (is_unique_type(is_type(decl)))
6937 continue;
6938
6939 ABG_ASSERT(priv_->deleted_types_.find(qname)
6940 == priv_->deleted_types_.end());
6941 priv_->deleted_types_[qname] = decl;
6942 }
6943 else
6944 {
6945 ABG_ASSERT(priv_->deleted_decls_.find(qname)
6946 == priv_->deleted_decls_.end());
6947 priv_->deleted_decls_[qname] = decl;
6948 }
6949 }
6950
6951 // Populate inserted types & decls as well as chagned types & decls
6952 // lookup tables.
6953 for (vector<insertion>::const_iterator it = e.insertions().begin();
6954 it != e.insertions().end();
6955 ++it)
6956 {
6957 for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6958 i != it->inserted_indexes().end();
6959 ++i)
6960 {
6961 decl_base_sptr decl = inserted_member_at(i);
6962 string qname = decl->get_qualified_name();
6963 if (is_type(decl))
6964 {
6965 class_decl_sptr klass_decl =
6966 dynamic_pointer_cast<class_decl>(decl);
6967 if (klass_decl && klass_decl->get_is_declaration_only())
6968 continue;
6969
6970 // Unique types are artifically put in a scope because they
6971 // have to belong somewhere, but they should not be
6972 // considered added/removed from any scope because they are
6973 // artificial and always present in the system.
6974 if (is_unique_type(is_type(decl)))
6975 continue;
6976
6977 ABG_ASSERT(priv_->inserted_types_.find(qname)
6978 == priv_->inserted_types_.end());
6979 string_decl_base_sptr_map::const_iterator j =
6980 priv_->deleted_types_.find(qname);
6981 if (j != priv_->deleted_types_.end())
6982 {
6983 if (*j->second != *decl)
6984 priv_->changed_types_[qname] =
6985 compute_diff(j->second, decl, context());
6986 priv_->deleted_types_.erase(j);
6987 }
6988 else
6989 priv_->inserted_types_[qname] = decl;
6990 }
6991 else
6992 {
6993 ABG_ASSERT(priv_->inserted_decls_.find(qname)
6994 == priv_->inserted_decls_.end());
6995 string_decl_base_sptr_map::const_iterator j =
6996 priv_->deleted_decls_.find(qname);
6997 if (j != priv_->deleted_decls_.end())
6998 {
6999 if (*j->second != *decl)
7000 priv_->changed_decls_[qname] =
7001 compute_diff(j->second, decl, context());
7002 priv_->deleted_decls_.erase(j);
7003 }
7004 else
7005 priv_->inserted_decls_[qname] = decl;
7006 }
7007 }
7008 }
7009
7010 sort_string_diff_sptr_map(priv_->changed_decls_,
7011 priv_->sorted_changed_decls_);
7012 sort_string_diff_sptr_map(priv_->changed_types_,
7013 priv_->sorted_changed_types_);
7014
7015 // Populate removed types/decls lookup tables
7016 for (string_decl_base_sptr_map::const_iterator i =
7017 priv_->deleted_types_.begin();
7018 i != priv_->deleted_types_.end();
7019 ++i)
7020 {
7021 string_decl_base_sptr_map::const_iterator r =
7022 priv_->inserted_types_.find(i->first);
7023 if (r == priv_->inserted_types_.end())
7024 priv_->removed_types_[i->first] = i->second;
7025 }
7026 for (string_decl_base_sptr_map::const_iterator i =
7027 priv_->deleted_decls_.begin();
7028 i != priv_->deleted_decls_.end();
7029 ++i)
7030 {
7031 string_decl_base_sptr_map::const_iterator r =
7032 priv_->inserted_decls_.find(i->first);
7033 if (r == priv_->inserted_decls_.end())
7034 priv_->removed_decls_[i->first] = i->second;
7035 }
7036
7037 // Populate added types/decls.
7038 for (string_decl_base_sptr_map::const_iterator i =
7039 priv_->inserted_types_.begin();
7040 i != priv_->inserted_types_.end();
7041 ++i)
7042 {
7043 string_decl_base_sptr_map::const_iterator r =
7044 priv_->deleted_types_.find(i->first);
7045 if (r == priv_->deleted_types_.end())
7046 priv_->added_types_[i->first] = i->second;
7047 }
7048 for (string_decl_base_sptr_map::const_iterator i =
7049 priv_->inserted_decls_.begin();
7050 i != priv_->inserted_decls_.end();
7051 ++i)
7052 {
7053 string_decl_base_sptr_map::const_iterator r =
7054 priv_->deleted_decls_.find(i->first);
7055 if (r == priv_->deleted_decls_.end())
7056 priv_->added_decls_[i->first] = i->second;
7057 }
7058}
7059
7060/// Populate the vector of children node of the @ref diff base type
7061/// sub-object of this instance of @ref scope_diff.
7062///
7063/// The children node can then later be retrieved using
7064/// diff::children_node().
7065void
7067{
7068 for (diff_sptrs_type::const_iterator i = changed_types().begin();
7069 i != changed_types().end();
7070 ++i)
7071 if (*i)
7073
7074 for (diff_sptrs_type::const_iterator i = changed_decls().begin();
7075 i != changed_decls().end();
7076 ++i)
7077 if (*i)
7079}
7080
7081/// Constructor for scope_diff
7082///
7083/// @param first_scope the first scope to consider for the diff.
7084///
7085/// @param second_scope the second scope to consider for the diff.
7086///
7087/// @param ctxt the diff context to use. Note that this context
7088/// object must stay alive at least during the life time of the
7089/// current instance of @ref scope_diff. Otherwise memory corruption
7090/// issues occur.
7092 scope_decl_sptr second_scope,
7093 diff_context_sptr ctxt)
7094 : diff(first_scope, second_scope, ctxt),
7095 priv_(new priv)
7096{}
7097
7098/// Getter for the first scope of the diff.
7099///
7100/// @return the first scope of the diff.
7101const scope_decl_sptr
7103{return dynamic_pointer_cast<scope_decl>(first_subject());}
7104
7105/// Getter for the second scope of the diff.
7106///
7107/// @return the second scope of the diff.
7108const scope_decl_sptr
7110{return dynamic_pointer_cast<scope_decl>(second_subject());}
7111
7112/// Accessor of the edit script of the members of a scope.
7113///
7114/// This edit script is computed using the equality operator that
7115/// applies to shared_ptr<decl_base>.
7116///
7117/// That has interesting consequences. For instance, consider two
7118/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7119/// S0'. C0 and C0' have the same qualified name, but have different
7120/// members. The edit script will consider that C0 has been deleted
7121/// from S0 and that S0' has been inserted. This is a low level
7122/// canonical representation of the changes; a higher level
7123/// representation would give us a simpler way to say "the class C0
7124/// has been modified into C0'". But worry not. We do have such
7125/// higher representation as well; that is what changed_types() and
7126/// changed_decls() is for.
7127///
7128/// @return the edit script of the changes encapsulatd in this
7129/// instance of scope_diff.
7130const edit_script&
7132{return priv_->member_changes_;}
7133
7134/// Accessor of the edit script of the members of a scope.
7135///
7136/// This edit script is computed using the equality operator that
7137/// applies to shared_ptr<decl_base>.
7138///
7139/// That has interesting consequences. For instance, consider two
7140/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
7141/// S0'. C0 and C0' have the same qualified name, but have different
7142/// members. The edit script will consider that C0 has been deleted
7143/// from S0 and that S0' has been inserted. This is a low level
7144/// canonical representation of the changes; a higher level
7145/// representation would give us a simpler way to say "the class C0
7146/// has been modified into C0'". But worry not. We do have such
7147/// higher representation as well; that is what changed_types() and
7148/// changed_decls() is for.
7149///
7150/// @return the edit script of the changes encapsulatd in this
7151/// instance of scope_diff.
7154{return priv_->member_changes_;}
7155
7156/// Accessor that eases the manipulation of the edit script associated
7157/// to this instance. It returns the scope member that is reported
7158/// (in the edit script) as deleted at a given index.
7159///
7160/// @param i the index (in the edit script) of an element of the first
7161/// scope that has been reported as being delete.
7162///
7163/// @return the scope member that has been reported by the edit script
7164/// as being deleted at index i.
7165const decl_base_sptr
7167{
7168 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
7169 return scope->get_member_decls()[i];
7170}
7171
7172/// Accessor that eases the manipulation of the edit script associated
7173/// to this instance. It returns the scope member (of the first scope
7174/// of this diff instance) that is reported (in the edit script) as
7175/// deleted at a given iterator.
7176///
7177/// @param i the iterator of an element of the first scope that has
7178/// been reported as being delete.
7179///
7180/// @return the scope member of the first scope of this diff that has
7181/// been reported by the edit script as being deleted at iterator i.
7182const decl_base_sptr
7183scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
7184{return deleted_member_at(i->index());}
7185
7186/// Accessor that eases the manipulation of the edit script associated
7187/// to this instance. It returns the scope member (of the second
7188/// scope of this diff instance) that is reported as being inserted
7189/// from a given index.
7190///
7191/// @param i the index of an element of the second scope this diff
7192/// that has been reported by the edit script as being inserted.
7193///
7194/// @return the scope member of the second scope of this diff that has
7195/// been reported as being inserted from index i.
7196const decl_base_sptr
7198{
7199 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
7200 return scope->get_member_decls()[i];
7201}
7202
7203/// Accessor that eases the manipulation of the edit script associated
7204/// to this instance. It returns the scope member (of the second
7205/// scope of this diff instance) that is reported as being inserted
7206/// from a given iterator.
7207///
7208/// @param i the iterator of an element of the second scope this diff
7209/// that has been reported by the edit script as being inserted.
7210///
7211/// @return the scope member of the second scope of this diff that has
7212/// been reported as being inserted from iterator i.
7213const decl_base_sptr
7214scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
7215{return inserted_member_at(*i);}
7216
7217/// @return a sorted vector of the types which content has changed
7218/// from the first scope to the other.
7219const diff_sptrs_type&
7221{return priv_->sorted_changed_types_;}
7222
7223/// @return a sorted vector of the decls which content has changed
7224/// from the first scope to the other.
7225const diff_sptrs_type&
7227{return priv_->sorted_changed_decls_;}
7228
7230scope_diff::removed_types() const
7231{return priv_->removed_types_;}
7232
7234scope_diff::removed_decls() const
7235{return priv_->removed_decls_;}
7236
7238scope_diff::added_types() const
7239{return priv_->added_types_;}
7240
7242scope_diff::added_decls() const
7243{return priv_->added_decls_;}
7244
7245/// @return the pretty representation for the current instance of @ref
7246/// scope_diff.
7247const string&
7249{
7250 if (diff::priv_->pretty_representation_.empty())
7251 {
7252 std::ostringstream o;
7253 o << "scope_diff["
7254 << first_subject()->get_pretty_representation()
7255 << ", "
7256 << second_subject()->get_pretty_representation()
7257 << "]";
7258 diff::priv_->pretty_representation_ = o.str();
7259 }
7260 return diff::priv_->pretty_representation_;
7261}
7262
7263/// Return true iff the current diff node carries a change.
7264///
7265/// Return true iff the current diff node carries a change.
7266bool
7268{
7269 // TODO: add the number of really removed/added stuff.
7270 return changed_types().size() + changed_decls().size();
7271}
7272
7273/// @return the kind of local change carried by the current diff node.
7274/// The value returned is zero if the current node carries no local
7275/// change.
7276enum change_kind
7278{
7279 ir::change_kind k = ir::NO_CHANGE_KIND;
7280 if (!equals(*first_scope(), *second_scope(), &k))
7281 return k & ir::ALL_LOCAL_CHANGES_MASK;
7282 return ir::NO_CHANGE_KIND;
7283}
7284
7285/// Report the changes of one scope against another.
7286///
7287/// @param out the out stream to report the changes to.
7288///
7289/// @param indent the string to use for indentation.
7290void
7291scope_diff::report(ostream& out, const string& indent) const
7292{
7293 context()->get_reporter()->report(*this, out, indent);
7294}
7295
7296/// Compute the diff between two scopes.
7297///
7298/// Note that the two decls must have been created in the same @ref
7299/// environment, otherwise, this function aborts.
7300///
7301/// @param first the first scope to consider in computing the diff.
7302///
7303/// @param second the second scope to consider in the diff
7304/// computation. The second scope is diffed against the first scope.
7305///
7306/// @param d a pointer to the diff object to populate with the
7307/// computed diff.
7308///
7309/// @return return the populated \a d parameter passed to this
7310/// function.
7311///
7312/// @param ctxt the diff context to use.
7315 const scope_decl_sptr second,
7317 diff_context_sptr ctxt)
7318{
7319 ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
7320
7321 compute_diff(first->get_member_decls().begin(),
7322 first->get_member_decls().end(),
7323 second->get_member_decls().begin(),
7324 second->get_member_decls().end(),
7325 d->member_changes());
7326
7327 d->ensure_lookup_tables_populated();
7328 d->context(ctxt);
7329
7330 return d;
7331}
7332
7333/// Compute the diff between two scopes.
7334///
7335/// Note that the two decls must have been created in the same @ref
7336/// environment, otherwise, this function aborts.
7337///
7338/// @param first_scope the first scope to consider in computing the diff.
7339///
7340/// @param second_scope the second scope to consider in the diff
7341/// computation. The second scope is diffed against the first scope.
7342///
7343/// @param ctxt the diff context to use.
7344///
7345/// @return return the resulting diff
7348 const scope_decl_sptr second_scope,
7349 diff_context_sptr ctxt)
7350{
7351 scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
7352 d = compute_diff(first_scope, second_scope, d, ctxt);
7353 ctxt->initialize_canonical_diff(d);
7354 return d;
7355}
7356
7357//</scope_diff stuff>
7358
7359// <fn_parm_diff stuff>
7360
7361/// Constructor for the fn_parm_diff type.
7362///
7363/// @param first the first subject of the diff.
7364///
7365/// @param second the second subject of the diff.
7366///
7367/// @param ctxt the context of the diff. Note that this context
7368/// object must stay alive at least during the life time of the
7369/// current instance of @ref fn_parm_diff. Otherwise memory
7370/// corruption issues occur.
7371fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
7372 const function_decl::parameter_sptr second,
7373 diff_context_sptr ctxt)
7374 : decl_diff_base(first, second, ctxt),
7375 priv_(new priv)
7376{
7377 ABG_ASSERT(first->get_index() == second->get_index());
7378 priv_->type_diff = compute_diff(first->get_type(),
7379 second->get_type(),
7380 ctxt);
7381 ABG_ASSERT(priv_->type_diff);
7382}
7383
7384/// Getter for the first subject of this diff node.
7385///
7386/// @return the first function_decl::parameter_sptr subject of this
7387/// diff node.
7390{return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
7391
7392/// Getter for the second subject of this diff node.
7393///
7394/// @return the second function_decl::parameter_sptr subject of this
7395/// diff node.
7398{return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7399
7400/// Getter for the diff representing the changes on the type of the
7401/// function parameter involved in the current instance of @ref
7402/// fn_parm_diff.
7403///
7404/// @return a diff_sptr representing the changes on the type of the
7405/// function parameter we are interested in.
7408{return priv_->type_diff;}
7409
7410/// Build and return a textual representation of the current instance
7411/// of @ref fn_parm_diff.
7412///
7413/// @return the string representing the current instance of
7414/// fn_parm_diff.
7415const string&
7417{
7418 if (diff::priv_->pretty_representation_.empty())
7419 {
7420 std::ostringstream o;
7421 o << "function_parameter_diff["
7422 << first_subject()->get_pretty_representation()
7423 << ", "
7424 << second_subject()->get_pretty_representation()
7425 << "]";
7426 diff::priv_->pretty_representation_ = o.str();
7427 }
7428 return diff::priv_->pretty_representation_;
7429}
7430
7431/// Return true iff the current diff node carries a change.
7432///
7433/// @return true iff the current diff node carries a change.
7434bool
7437
7438/// Check if the current diff node carries a local change.
7439///
7440/// @return the kind of local change carried by the current diff node.
7441/// The value returned is zero if the current node carries no local
7442/// change.
7443enum change_kind
7445{
7446 ir::change_kind k = ir::NO_CHANGE_KIND;
7447 if (!equals(*first_parameter(), *second_parameter(), &k))
7448 return k & ir::ALL_LOCAL_CHANGES_MASK;
7449 return ir::NO_CHANGE_KIND;
7450}
7451
7452/// Emit a textual report about the current fn_parm_diff instance.
7453///
7454/// @param out the output stream to emit the textual report to.
7455///
7456/// @param indent the indentation string to use in the report.
7457void
7458fn_parm_diff::report(ostream& out, const string& indent) const
7459{
7460 context()->get_reporter()->report(*this, out, indent);
7461}
7462
7463/// Populate the vector of children nodes of the @ref diff base type
7464/// sub-object of this instance of @ref fn_parm_diff.
7465///
7466/// The children nodes can then later be retrieved using
7467/// diff::children_nodes()
7468void
7474
7475/// Compute the difference between two function_decl::parameter_sptr;
7476/// that is, between two function parameters. Return a resulting
7477/// fn_parm_diff_sptr that represents the changes.
7478///
7479/// Note that the two decls must have been created in the same @ref
7480/// environment, otherwise, this function aborts.
7481///
7482/// @param first the first subject of the diff.
7483///
7484/// @param second the second subject of the diff.
7485///
7486/// @param ctxt the context of the diff.
7487///
7488/// @return fn_parm_diff_sptr the resulting diff node.
7491 const function_decl::parameter_sptr second,
7492 diff_context_sptr ctxt)
7493{
7494 if (!first || !second)
7495 return fn_parm_diff_sptr();
7496
7497 fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7498 ctxt->initialize_canonical_diff(result);
7499
7500 return result;
7501}
7502// </fn_parm_diff stuff>
7503
7504// <function_type_diff stuff>
7505
7506void
7507function_type_diff::ensure_lookup_tables_populated()
7508{
7509 priv_->return_type_diff_ =
7510 compute_diff(first_function_type()->get_return_type(),
7511 second_function_type()->get_return_type(),
7512 context());
7513
7514 string parm_name;
7516 for (vector<deletion>::const_iterator i =
7517 priv_->parm_changes_.deletions().begin();
7518 i != priv_->parm_changes_.deletions().end();
7519 ++i)
7520 {
7521 parm = *(first_function_type()->get_first_parm()
7522 + i->index());
7523 parm_name = parm->get_name_id();
7524 // If for a reason the type name is empty we want to know and
7525 // fix that.
7526 ABG_ASSERT(!parm_name.empty());
7527 priv_->deleted_parms_[parm_name] = parm;
7528 priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7529 }
7530
7531 for (vector<insertion>::const_iterator i =
7532 priv_->parm_changes_.insertions().begin();
7533 i != priv_->parm_changes_.insertions().end();
7534 ++i)
7535 {
7536 for (vector<unsigned>::const_iterator j =
7537 i->inserted_indexes().begin();
7538 j != i->inserted_indexes().end();
7539 ++j)
7540 {
7541 parm = *(second_function_type()->get_first_parm() + *j);
7542 parm_name = parm->get_name_id();
7543 // If for a reason the type name is empty we want to know and
7544 // fix that.
7545 ABG_ASSERT(!parm_name.empty());
7546 {
7547 string_parm_map::const_iterator k =
7548 priv_->deleted_parms_.find(parm_name);
7549 if (k != priv_->deleted_parms_.end())
7550 {
7551 if (*k->second != *parm)
7552 priv_->subtype_changed_parms_[parm_name] =
7553 compute_diff(k->second, parm, context());
7554 priv_->deleted_parms_.erase(parm_name);
7555 }
7556 else
7557 priv_->added_parms_[parm_name] = parm;
7558 }
7559 {
7560 unsigned_parm_map::const_iterator k =
7561 priv_->deleted_parms_by_id_.find(parm->get_index());
7562 if (k != priv_->deleted_parms_by_id_.end())
7563 {
7564 if (*k->second != *parm
7565 && (k->second->get_name_id() != parm_name))
7566 priv_->changed_parms_by_id_[parm->get_index()] =
7567 compute_diff(k->second, parm, context());
7568 priv_->added_parms_.erase(parm_name);
7569 priv_->deleted_parms_.erase(k->second->get_name_id());
7570 priv_->deleted_parms_by_id_.erase(parm->get_index());
7571 }
7572 else
7573 priv_->added_parms_by_id_[parm->get_index()] = parm;
7574 }
7575 }
7576 }
7577
7578 sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7579 priv_->sorted_subtype_changed_parms_);
7580 sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7581 priv_->sorted_changed_parms_by_id_);
7582 sort_string_parm_map(priv_->deleted_parms_,
7583 priv_->sorted_deleted_parms_);
7584
7585 sort_string_parm_map(priv_->added_parms_,
7586 priv_->sorted_added_parms_);
7587}
7588
7589/// In the vector of deleted parameters, get the one that is at a given
7590/// index.
7591///
7592/// @param i the index of the deleted parameter to get.
7593///
7594/// @return the parameter returned.
7596function_type_diff::deleted_parameter_at(int i) const
7597{return first_function_type()->get_parameters()[i];}
7598
7599/// Getter for the sorted vector of deleted parameters.
7600///
7601/// @return the sorted vector of deleted parameters.
7602const vector<function_decl::parameter_sptr>&
7604{return priv_->sorted_deleted_parms_;}
7605
7606/// Getter for the sorted vector of added parameters .
7607///
7608/// @return the sorted vector of added parameters.
7609const vector<function_decl::parameter_sptr>&
7611{return priv_->sorted_added_parms_;}
7612
7613/// In the vector of inserted parameters, get the one that is at a
7614/// given index.
7615///
7616/// @param i the index of the inserted parameter to get.
7617///
7618/// @return the parameter returned.
7620function_type_diff::inserted_parameter_at(int i) const
7621{return second_function_type()->get_parameters()[i];}
7622
7623/// Consutrctor of the @ref function_type type.
7624///
7625/// @param first the first @ref function_type subject of the diff to
7626/// create.
7627///
7628/// @param second the second @ref function_type subject of the diff to
7629/// create.
7630///
7631/// @param ctxt the diff context to be used by the newly created
7632/// instance of function_type_diff. Note that this context object
7633/// must stay alive at least during the life time of the current
7634/// instance of @ref function_type_diff. Otherwise memory corruption
7635/// issues occur.
7637 const function_type_sptr second,
7638 diff_context_sptr ctxt)
7639 : type_diff_base(first, second, ctxt),
7640 priv_(new priv)
7641{}
7642
7643/// Getter for the first subject of the diff.
7644///
7645/// @return the first function type involved in the diff.
7648{return dynamic_pointer_cast<function_type>(first_subject());}
7649
7650/// Getter for the second subject of the diff.
7651///
7652/// @return the second function type involved in the diff.
7655{return dynamic_pointer_cast<function_type>(second_subject());}
7656
7657/// Getter for the diff of the return types of the two function types
7658/// of the current diff.
7659///
7660/// @return the diff of the return types of the two function types of
7661/// the current diff.
7662const diff_sptr
7664{return priv_->return_type_diff_;}
7665
7666/// Getter for the map of function parameter changes of the current diff.
7667///
7668/// @return a map of function parameter changes of the current diff.
7671{return priv_->subtype_changed_parms_;}
7672
7673/// Getter for the map of parameters that got removed.
7674///
7675/// @return the map of parameters that got removed.
7676const string_parm_map&
7678{return priv_->deleted_parms_;}
7679
7680/// Getter for the map of parameters that got added.
7681///
7682/// @return the map of parameters that got added.
7683const string_parm_map&
7685{return priv_->added_parms_;}
7686
7687/// Build and return a copy of a pretty representation of the current
7688/// instance of @ref function_type_diff.
7689///
7690/// @return a copy of the pretty representation of the current
7691/// instance of @ref function_type_diff.
7692const string&
7694{
7695 if (diff::priv_->pretty_representation_.empty())
7696 {
7697 std::ostringstream o;
7698 o << "function_type_diff["
7700 << ", "
7702 << "]";
7703 diff::priv_->pretty_representation_ = o.str();
7704 }
7705 return diff::priv_->pretty_representation_;
7706}
7707
7708/// Test if the current diff node carries changes.
7709///
7710/// @return true iff the current diff node carries changes.
7711bool
7714
7715/// Test if the current diff node carries local changes.
7716///
7717/// A local change is a change that is carried by this diff node, not
7718/// by any of its children nodes.
7719///
7720/// @return the kind of local change carried by the current diff node.
7721/// The value returned is zero if the current node carries no local
7722/// change.
7723enum change_kind
7725{
7726 ir::change_kind k = ir::NO_CHANGE_KIND;
7728 return k & ir::ALL_LOCAL_CHANGES_MASK;
7729 return ir::NO_CHANGE_KIND;
7730}
7731
7732/// Build and emit a textual report about the current @ref
7733/// function_type_diff instance.
7734///
7735/// @param out the output stream.
7736///
7737/// @param indent the indentation string to use.
7738void
7739function_type_diff::report(ostream& out, const string& indent) const
7740{
7741 context()->get_reporter()->report(*this, out, indent);
7742}
7743
7744/// Populate the vector of children node of the @ref diff base type
7745/// sub-object of this instance of @ref function_type_diff.
7746///
7747/// The children node can then later be retrieved using
7748/// diff::children_node().
7749void
7751{
7752 if (diff_sptr d = return_type_diff())
7754
7755 for (vector<fn_parm_diff_sptr>::const_iterator i =
7756 priv_->sorted_subtype_changed_parms_.begin();
7757 i != priv_->sorted_subtype_changed_parms_.end();
7758 ++i)
7759 if (diff_sptr d = *i)
7761
7762 for (vector<fn_parm_diff_sptr>::const_iterator i =
7763 priv_->sorted_changed_parms_by_id_.begin();
7764 i != priv_->sorted_changed_parms_by_id_.end();
7765 ++i)
7766 if (diff_sptr d = *i)
7768}
7769
7770/// Compute the diff between two instances of @ref function_type.
7771///
7772/// Note that the two types must have been created in the same @ref
7773/// environment, otherwise, this function aborts.
7774///
7775/// @param first the first @ref function_type to consider for the diff.
7776///
7777/// @param second the second @ref function_type to consider for the diff.
7778///
7779/// @param ctxt the diff context to use.
7780///
7781/// @return the resulting diff between the two @ref function_type.
7784 const function_type_sptr second,
7785 diff_context_sptr ctxt)
7786{
7787 if (!first || !second)
7788 {
7789 // TODO: implement this for either first or second being NULL.
7790 return function_type_diff_sptr();
7791 }
7792
7793 function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7794
7795 diff_utils::compute_diff(first->get_first_parm(),
7796 first->get_parameters().end(),
7797 second->get_first_parm(),
7798 second->get_parameters().end(),
7799 result->priv_->parm_changes_);
7800
7801 result->ensure_lookup_tables_populated();
7802
7803 ctxt->initialize_canonical_diff(result);
7804
7805 return result;
7806}
7807// </function_type_diff stuff>
7808
7809// <function_decl_diff stuff>
7810
7811/// Build the lookup tables of the diff, if necessary.
7812void
7813function_decl_diff::ensure_lookup_tables_populated()
7814{
7815}
7816
7817/// Populate the vector of children node of the @ref diff base type
7818/// sub-object of this instance of @ref function_decl_diff.
7819///
7820/// The children node can then later be retrieved using
7821/// diff::children_node().
7822void
7824{
7825 if (diff_sptr d = type_diff())
7827}
7828
7829/// Constructor for function_decl_diff
7830///
7831/// @param first the first function considered by the diff.
7832///
7833/// @param second the second function considered by the diff.
7834///
7835/// @param ctxt the context of the diff. Note that this context
7836/// object must stay alive at least during the life time of the
7837/// current instance of @ref function_decl_diff. Otherwise memory
7838/// corruption issues occur.
7840 const function_decl_sptr second,
7841 diff_context_sptr ctxt)
7842 : decl_diff_base(first, second, ctxt),
7843 priv_(new priv)
7844{
7845}
7846
7847/// @return the first function considered by the diff.
7850{return dynamic_pointer_cast<function_decl>(first_subject());}
7851
7852/// @return the second function considered by the diff.
7855{return dynamic_pointer_cast<function_decl>(second_subject());}
7856
7858function_decl_diff::type_diff() const
7859{return priv_->type_diff_;}
7860
7861/// @return the pretty representation for the current instance of @ref
7862/// function_decl_diff.
7863const string&
7865{
7866 if (diff::priv_->pretty_representation_.empty())
7867 {
7868 std::ostringstream o;
7869 o << "function_diff["
7870 << first_subject()->get_pretty_representation()
7871 << ", "
7872 << second_subject()->get_pretty_representation()
7873 << "]";
7874 diff::priv_->pretty_representation_ = o.str();
7875 }
7876 return diff::priv_->pretty_representation_;
7877}
7878
7879/// Return true iff the current diff node carries a change.
7880///
7881/// @return true iff the current diff node carries a change.
7882bool
7885
7886/// @return the kind of local change carried by the current diff node.
7887/// The value returned is zero if the current node carries no local
7888/// change.
7889enum change_kind
7891{
7892 ir::change_kind k = ir::NO_CHANGE_KIND;
7894 return k & ir::ALL_LOCAL_CHANGES_MASK;
7895 return ir::NO_CHANGE_KIND;
7896}
7897
7898/// Serialize a report of the changes encapsulated in the current
7899/// instance of @ref function_decl_diff over to an output stream.
7900///
7901/// @param out the output stream to serialize the report to.
7902///
7903/// @param indent the string to use an an indentation prefix.
7904void
7905function_decl_diff::report(ostream& out, const string& indent) const
7906{
7907 context()->get_reporter()->report(*this, out, indent);
7908}
7909
7910/// Compute the diff between two function_decl.
7911///
7912/// Note that the two decls must have been created in the same @ref
7913/// environment, otherwise, this function aborts.
7914///
7915/// @param first the first function_decl to consider for the diff
7916///
7917/// @param second the second function_decl to consider for the diff
7918///
7919/// @param ctxt the diff context to use.
7920///
7921/// @return the computed diff
7924 const function_decl_sptr second,
7925 diff_context_sptr ctxt)
7926{
7927 if (!first || !second)
7928 {
7929 // TODO: implement this for either first or second being NULL.
7930 return function_decl_diff_sptr();
7931 }
7932
7933 function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7934 second->get_type(),
7935 ctxt);
7936
7937 function_decl_diff_sptr result(new function_decl_diff(first, second,
7938 ctxt));
7939 result->priv_->type_diff_ = type_diff;
7940
7941 result->ensure_lookup_tables_populated();
7942
7943 ctxt->initialize_canonical_diff(result);
7944
7945 return result;
7946}
7947
7948// </function_decl_diff stuff>
7949
7950// <type_decl_diff stuff>
7951
7952/// Constructor for type_decl_diff.
7953///
7954/// @param first the first subject of the diff.
7955///
7956/// @param second the second subject of the diff.
7957///
7958/// @param ctxt the context of the diff. Note that this context
7959/// object must stay alive at least during the life time of the
7960/// current instance of @ref type_decl_diff. Otherwise memory
7961/// corruption issues occur.
7962type_decl_diff::type_decl_diff(const type_decl_sptr first,
7963 const type_decl_sptr second,
7964 diff_context_sptr ctxt)
7965 : type_diff_base(first, second, ctxt)
7966{}
7967
7968/// Getter for the first subject of the type_decl_diff.
7969///
7970/// @return the first type_decl involved in the diff.
7971const type_decl_sptr
7973{return dynamic_pointer_cast<type_decl>(first_subject());}
7974
7975/// Getter for the second subject of the type_decl_diff.
7976///
7977/// @return the second type_decl involved in the diff.
7978const type_decl_sptr
7980{return dynamic_pointer_cast<type_decl>(second_subject());}
7981
7982/// @return the pretty representation for the current instance of @ref
7983/// type_decl_diff.
7984const string&
7986{
7987 if (diff::priv_->pretty_representation_.empty())
7988 {
7989 std::ostringstream o;
7990 o << "type_decl_diff["
7991 << first_subject()->get_pretty_representation()
7992 << ", "
7993 << second_subject()->get_pretty_representation()
7994 << "]";
7995 diff::priv_->pretty_representation_ = o.str();
7996 }
7997 return diff::priv_->pretty_representation_;
7998}
7999/// Return true iff the current diff node carries a change.
8000///
8001/// @return true iff the current diff node carries a change.
8002bool
8005
8006/// @return the kind of local change carried by the current diff node.
8007/// The value returned is zero if the current node carries no local
8008/// change.
8009enum change_kind
8011{
8012 ir::change_kind k = ir::NO_CHANGE_KIND;
8013 if (!equals(*first_type_decl(), *second_type_decl(), &k))
8014 return k & ir::ALL_LOCAL_CHANGES_MASK;
8015 return ir::NO_CHANGE_KIND;
8016}
8017/// Ouputs a report of the differences between of the two type_decl
8018/// involved in the type_decl_diff.
8019///
8020/// @param out the output stream to emit the report to.
8021///
8022/// @param indent the string to use for indentatino indent.
8023void
8024type_decl_diff::report(ostream& out, const string& indent) const
8025{
8026 context()->get_reporter()->report(*this, out, indent);
8027}
8028
8029/// Compute a diff between two type_decl.
8030///
8031/// Note that the two types must have been created in the same @ref
8032/// environment, otherwise, this function aborts.
8033///
8034/// This function doesn't actually compute a diff. As a type_decl is
8035/// very simple (unlike compound constructs like function_decl or
8036/// class_decl) it's easy to just compare the components of the
8037/// type_decl to know what has changed. Thus this function just
8038/// builds and return a type_decl_diff object. The
8039/// type_decl_diff::report function will just compare the components
8040/// of the the two type_decl and display where and how they differ.
8041///
8042/// @param first a pointer to the first type_decl to
8043/// consider.
8044///
8045/// @param second a pointer to the second type_decl to consider.
8046///
8047/// @param ctxt the diff context to use.
8048///
8049/// @return a pointer to the resulting type_decl_diff.
8052 const type_decl_sptr second,
8053 diff_context_sptr ctxt)
8054{
8055 type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
8056
8057 // We don't need to actually compute a diff here as a type_decl
8058 // doesn't have complicated sub-components. type_decl_diff::report
8059 // just walks the members of the type_decls and display information
8060 // about the ones that have changed. On a similar note,
8061 // type_decl_diff::length returns 0 if the two type_decls are equal,
8062 // and 1 otherwise.
8063
8064 ctxt->initialize_canonical_diff(result);
8065
8066 return result;
8067}
8068
8069// </type_decl_diff stuff>
8070
8071// <typedef_diff stuff>
8072
8073/// Populate the vector of children node of the @ref diff base type
8074/// sub-object of this instance of @ref typedef_diff.
8075///
8076/// The children node can then later be retrieved using
8077/// diff::children_node().
8078void
8081
8082/// Constructor for typedef_diff.
8083///
8084/// @param first the first subject of the diff.
8085///
8086/// @param second the second subject of the diff.
8087///
8088/// @param underlying the underlying diff of the @ref typedef_diff.
8089/// That is the diff between the underlying types of @p first and @p
8090/// second.
8091///
8092/// @param ctxt the context of the diff. Note that this context
8093/// object must stay alive at least during the life time of the
8094/// current instance of @ref typedef_diff. Otherwise memory
8095/// corruption issues occur.
8096typedef_diff::typedef_diff(const typedef_decl_sptr first,
8097 const typedef_decl_sptr second,
8098 const diff_sptr underlying,
8099 diff_context_sptr ctxt)
8100 : type_diff_base(first, second, ctxt),
8101 priv_(new priv(underlying))
8102{}
8103
8104/// Getter for the firt typedef_decl involved in the diff.
8105///
8106/// @return the first subject of the diff.
8109{return dynamic_pointer_cast<typedef_decl>(first_subject());}
8110
8111/// Getter for the second typedef_decl involved in the diff.
8112///
8113/// @return the second subject of the diff.
8116{return dynamic_pointer_cast<typedef_decl>(second_subject());}
8117
8118/// Getter for the diff between the two underlying types of the
8119/// typedefs.
8120///
8121/// @return the diff object reprensenting the difference between the
8122/// two underlying types of the typedefs.
8123const diff_sptr
8125{return priv_->underlying_type_diff_;}
8126
8127/// Setter for the diff between the two underlying types of the
8128/// typedefs.
8129///
8130/// @param d the new diff object reprensenting the difference between
8131/// the two underlying types of the typedefs.
8132void
8134{priv_->underlying_type_diff_ = d;}
8135
8136/// @return the pretty representation for the current instance of @ref
8137/// typedef_diff.
8138const string&
8140{
8141 if (diff::priv_->pretty_representation_.empty())
8142 {
8143 std::ostringstream o;
8144 o << "typedef_diff["
8145 << first_subject()->get_pretty_representation()
8146 << ", "
8147 << second_subject()->get_pretty_representation()
8148 << "]";
8149 diff::priv_->pretty_representation_ = o.str();
8150 }
8151 return diff::priv_->pretty_representation_;
8152}
8153
8154/// Return true iff the current diff node carries a change.
8155///
8156/// @return true iff the current diff node carries a change.
8157bool
8159{
8160 decl_base_sptr second = second_typedef_decl();
8161 return !(*first_typedef_decl() == *second);
8162}
8163
8164/// @return the kind of local change carried by the current diff node.
8165/// The value returned is zero if the current node carries no local
8166/// change.
8167enum change_kind
8169{
8170 ir::change_kind k = ir::NO_CHANGE_KIND;
8172 return k & ir::ALL_LOCAL_CHANGES_MASK;
8173 return ir::NO_CHANGE_KIND;
8174}
8175
8176/// Reports the difference between the two subjects of the diff in a
8177/// serialized form.
8178///
8179/// @param out the output stream to emit the report to.
8180///
8181/// @param indent the indentation string to use.
8182void
8183typedef_diff::report(ostream& out, const string& indent) const
8184{
8185 context()->get_reporter()->report(*this, out, indent);
8186}
8187
8188/// Compute a diff between two typedef_decl.
8189///
8190/// Note that the two types must have been created in the same @ref
8191/// environment, otherwise, this function aborts.
8192///
8193/// @param first a pointer to the first typedef_decl to consider.
8194///
8195/// @param second a pointer to the second typedef_decl to consider.
8196///
8197/// @param ctxt the diff context to use.
8198///
8199/// @return a pointer to the the resulting typedef_diff.
8202 const typedef_decl_sptr second,
8203 diff_context_sptr ctxt)
8204{
8205 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
8206 second->get_underlying_type(),
8207 ctxt);
8208 typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
8209
8210 ctxt->initialize_canonical_diff(result);
8211
8212 return result;
8213}
8214
8215/// Return the leaf underlying diff node of a @ref typedef_diff node.
8216///
8217/// If the underlying diff node of a @ref typedef_diff node is itself
8218/// a @ref typedef_diff node, then recursively look at the underlying
8219/// diff nodes to get the first one that is not a a @ref typedef_diff
8220/// node. This is what a leaf underlying diff node means.
8221///
8222/// Otherwise, if the underlying diff node of @ref typedef_diff is
8223/// *NOT* a @ref typedef_diff node, then just return the underlying
8224/// diff node.
8225///
8226/// And if the diff node considered is not a @ref typedef_diff node,
8227/// then just return it.
8228///
8229/// @return the leaf underlying diff node of a @p diff.
8230const diff*
8232{
8233 const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
8234 if (!d)
8235 return diff;
8236
8237 if (const typedef_diff* deef =
8238 dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
8240
8241 return d->underlying_type_diff().get();
8242}
8243
8244// </typedef_diff stuff>
8245
8246// <translation_unit_diff stuff>
8247
8248/// Constructor for translation_unit_diff.
8249///
8250/// @param first the first translation unit to consider for this diff.
8251///
8252/// @param second the second translation unit to consider for this diff.
8253///
8254/// @param ctxt the context of the diff. Note that this context
8255/// object must stay alive at least during the life time of the
8256/// current instance of @ref translation_unit_diff. Otherwise memory
8257/// corruption issues occur.
8259 translation_unit_sptr second,
8260 diff_context_sptr ctxt)
8261 : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
8262 priv_(new priv(first, second))
8263{
8264}
8265
8266/// Getter for the first translation unit of this diff.
8267///
8268/// @return the first translation unit of this diff.
8271{return priv_->first_;}
8272
8273/// Getter for the second translation unit of this diff.
8274///
8275/// @return the second translation unit of this diff.
8278{return priv_->second_;}
8279
8280/// Return true iff the current diff node carries a change.
8281///
8282/// @return true iff the current diff node carries a change.
8283bool
8286
8287/// @return the kind of local change carried by the current diff node.
8288/// The value returned is zero if the current node carries no local
8289/// change.
8290enum change_kind
8292{return ir::NO_CHANGE_KIND;}
8293
8294/// Report the diff in a serialized form.
8295///
8296/// @param out the output stream to serialize the report to.
8297///
8298/// @param indent the prefix to use as indentation for the report.
8299void
8300translation_unit_diff::report(ostream& out, const string& indent) const
8301{scope_diff::report(out, indent);}
8302
8303/// Compute the diff between two translation_units.
8304///
8305/// Note that the two translation units must have been created in the
8306/// same @ref environment, otherwise, this function aborts.
8307///
8308/// @param first the first translation_unit to consider.
8309///
8310/// @param second the second translation_unit to consider.
8311///
8312/// @param ctxt the diff context to use. If null, this function will
8313/// create a new context and set to the diff object returned.
8314///
8315/// @return the newly created diff object.
8318 const translation_unit_sptr second,
8319 diff_context_sptr ctxt)
8320{
8321 ABG_ASSERT(first && second);
8322
8323 if (!ctxt)
8324 ctxt.reset(new diff_context);
8325
8326 // TODO: handle first or second having empty contents.
8327 translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
8328 ctxt));
8329 scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
8330
8331 compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
8332 static_pointer_cast<scope_decl>(second->get_global_scope()),
8333 sc_diff,
8334 ctxt);
8335
8336 ctxt->initialize_canonical_diff(tu_diff);
8337
8338 return tu_diff;
8339}
8340
8341// </translation_unit_diff stuff>
8342
8343// <diff_maps stuff>
8344
8345/// The private data of the @ref diff_maps type.
8346struct diff_maps::priv
8347{
8348 string_diff_ptr_map type_decl_diff_map_;
8349 string_diff_ptr_map enum_diff_map_;
8350 string_diff_ptr_map class_diff_map_;
8351 string_diff_ptr_map union_diff_map_;
8352 string_diff_ptr_map typedef_diff_map_;
8353 string_diff_ptr_map subrange_diff_map_;
8354 string_diff_ptr_map array_diff_map_;
8355 string_diff_ptr_map reference_diff_map_;
8356 string_diff_ptr_map function_type_diff_map_;
8357 string_diff_ptr_map function_decl_diff_map_;
8358 string_diff_ptr_map var_decl_diff_map_;
8359 string_diff_ptr_map distinct_diff_map_;
8360 string_diff_ptr_map fn_parm_diff_map_;
8361 diff_artifact_set_map_type impacted_artifacts_map_;
8362}; // end struct diff_maps::priv
8363
8364/// Default constructor of the @ref diff_maps type.
8366 : priv_(new diff_maps::priv())
8367{}
8368
8369diff_maps::~diff_maps() = default;
8370
8371/// Getter of the map that contains basic type diffs.
8372///
8373/// @return the map that contains basic type diffs.
8376{return priv_->type_decl_diff_map_;}
8377
8378/// Getter of the map that contains basic type diffs.
8379///
8380/// @return the map that contains basic type diffs.
8383{return priv_->type_decl_diff_map_;}
8384
8385/// Getter of the map that contains enum type diffs.
8386///
8387/// @return the map that contains enum type diffs.
8390{return priv_->enum_diff_map_;}
8391
8392/// Getter of the map that contains enum type diffs.
8393///
8394/// @return the map that contains enum type diffs.
8397{return priv_->enum_diff_map_;}
8398
8399/// Getter of the map that contains class type diffs.
8400///
8401/// @return the map that contains class type diffs.
8404{return priv_->class_diff_map_;}
8405
8406/// Getter of the map that contains class type diffs.
8407///
8408/// @return the map that contains class type diffs.
8411{return priv_->class_diff_map_;}
8412
8413/// Getter of the map that contains union type diffs.
8414///
8415/// @return the map that contains union type diffs.
8418{return priv_->union_diff_map_;}
8419
8420/// Getter of the map that contains union type diffs.
8421///
8422/// @return the map that contains union type diffs.
8425{return priv_->union_diff_map_;}
8426
8427/// Getter of the map that contains typedef type diffs.
8428///
8429/// @return the map that contains typedef type diffs.
8432{return priv_->typedef_diff_map_;}
8433
8434/// Getter of the map that contains typedef type diffs.
8435///
8436/// @return the map that contains typedef type diffs.
8439{return priv_->typedef_diff_map_;}
8440
8441/// Getter of the map that contains subrange type diffs.
8442///
8443/// @return the map that contains subrange type diffs.
8446{return priv_->subrange_diff_map_;}
8447
8448/// Getter of the map that contains subrange type diffs.
8449///
8450/// @return the map that contains subrange type diffs.
8453{return priv_->subrange_diff_map_;}
8454
8455/// Getter of the map that contains array type diffs.
8456///
8457/// @return the map that contains array type diffs.
8460{return priv_->array_diff_map_;}
8461
8462/// Getter of the map that contains array type diffs.
8463///
8464/// @return the map that contains array type diffs.
8467{return priv_->array_diff_map_;}
8468
8469/// Getter of the map that contains reference type diffs.
8470///
8471/// @return the map that contains reference type diffs.
8474{return priv_->reference_diff_map_;}
8475
8476/// Getter of the map that contains reference type diffs.
8477///
8478/// @return the map that contains reference type diffs.
8481{{return priv_->reference_diff_map_;}}
8482
8483/// Getter of the map that contains function parameter diffs.
8484///
8485/// @return the map that contains function parameter diffs.
8488{return priv_->fn_parm_diff_map_;}
8489
8490/// Getter of the map that contains function parameter diffs.
8491///
8492/// @return the map that contains function parameter diffs.
8495{return priv_->fn_parm_diff_map_;}
8496
8497/// Getter of the map that contains function type diffs.
8498///
8499/// @return the map that contains function type diffs.
8502{return priv_->function_type_diff_map_;}
8503
8504/// Getter of the map that contains function type diffs.
8505///
8506/// @return the map that contains function type diffs.
8509{return priv_->function_type_diff_map_;}
8510
8511/// Getter of the map that contains function decl diffs.
8512///
8513/// @return the map that contains function decl diffs.
8516{return priv_->function_decl_diff_map_;}
8517
8518/// Getter of the map that contains function decl diffs.
8519///
8520/// @return the map that contains function decl diffs.
8523{return priv_->function_decl_diff_map_;}
8524
8525/// Getter of the map that contains var decl diffs.
8526///
8527/// @return the map that contains var decl diffs.
8530{return priv_->var_decl_diff_map_;}
8531
8532/// Getter of the map that contains var decl diffs.
8533///
8534/// @return the map that contains var decl diffs.
8537{return priv_->var_decl_diff_map_;}
8538
8539/// Getter of the map that contains distinct diffs.
8540///
8541/// @return the map that contains distinct diffs.
8544{return priv_->distinct_diff_map_;}
8545
8546/// Getter of the map that contains distinct diffs.
8547///
8548/// @return the map that contains distinct diffs.
8551{return priv_->distinct_diff_map_;}
8552
8553/// Insert a new diff node into the current instance of @ref diff_maps.
8554///
8555/// @param dif the new diff node to insert into the @ref diff_maps.
8556///
8557/// @param impacted_iface the interface (global function or variable)
8558/// currently being analysed that led to analysing the diff node @p
8559/// dif. In other words, this is the interface impacted by the diff
8560/// node @p dif. Note that this can be nil in cases where we are
8561/// directly analysing changes to a type that is not reachable from
8562/// any global function or variable.
8563///
8564/// @return true iff the diff node could be added to the current
8565/// instance of @ref diff_maps.
8566bool
8568 const type_or_decl_base_sptr& impacted_iface)
8569{
8570 string n = get_pretty_representation(dif->first_subject(),
8571 /*internal=*/true);
8572 if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8573 get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8574 else if (const enum_diff *d = is_enum_diff(dif))
8575 get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8576 else if (const class_diff *d = is_class_diff(dif))
8577 get_class_diff_map()[n] = const_cast<class_diff*>(d);
8578 else if (const union_diff *d = is_union_diff(dif))
8579 get_union_diff_map()[n] = const_cast<union_diff*>(d);
8580 else if (const typedef_diff *d = is_typedef_diff(dif))
8581 get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8582 else if (const subrange_diff *d = is_subrange_diff(dif))
8583 get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8584 else if (const array_diff *d = is_array_diff(dif))
8585 get_array_diff_map()[n] = const_cast<array_diff*>(d);
8586 else if (const reference_diff *d = is_reference_diff(dif))
8587 get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8588 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8589 get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8590 else if (const function_type_diff *d = is_function_type_diff(dif))
8591 get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8592 else if (const var_diff *d = is_var_diff(dif))
8593 get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8594 else if (const function_decl_diff *d = is_function_decl_diff(dif))
8595 get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8596 else if (const distinct_diff *d = is_distinct_diff(dif))
8597 get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8598 else if (is_base_diff(dif))
8599 // we silently drop this case.
8600 return true;
8601 else
8603
8604 // Update the map that associates this diff node to the set of
8605 // interfaces it impacts.
8606
8607 if (impacted_iface)
8608 {
8609 diff_artifact_set_map_type::iterator i =
8610 priv_->impacted_artifacts_map_.find(dif);
8611
8612 if (i == priv_->impacted_artifacts_map_.end())
8613 {
8615 set.insert(impacted_iface);
8616 priv_->impacted_artifacts_map_[dif] = set;
8617 }
8618 else
8619 i->second.insert(impacted_iface);
8620 }
8621
8622 return true;
8623}
8624
8625/// Lookup the interfaces that are impacted by a given leaf diff node.
8626///
8627/// @param d the diff node to consider.
8628///
8629/// @return the set of artifacts impacted by @p d.
8632{
8633 diff_artifact_set_map_type::iterator i =
8634 priv_->impacted_artifacts_map_.find(d);
8635
8636 if (i == priv_->impacted_artifacts_map_.end())
8637 return 0;
8638
8639 return &i->second;
8640}
8641
8642//
8643// </diff_maps stuff>
8644
8645/// Constructor for the @ref diff_stat type.
8646///
8647/// @param ctxt the context of the corpus diff. Note that this
8648/// context object must stay alive at least during the life time of
8649/// the current instance of @ref corpus_diff::diff_stats. Otherwise
8650/// memory corruption issues occur.
8651corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8652 : priv_(new priv(ctxt))
8653{}
8654
8655/// Getter for the number of functions removed.
8656///
8657/// @return the number of functions removed.
8658size_t
8660{return priv_->num_func_removed;}
8661
8662/// Setter for the number of functions removed.
8663///
8664/// @param n the new number of functions removed.
8665void
8667{priv_->num_func_removed = n;}
8668
8669/// Getter for the number of removed functions that have been filtered
8670/// out.
8671///
8672/// @return the number of removed functions that have been filtered
8673/// out.
8674size_t
8676{
8677 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8678 return num_func_removed();
8679 return priv_->num_removed_func_filtered_out;
8680}
8681
8682/// Setter for the number of removed functions that have been filtered
8683/// out.
8684///
8685/// @param t the new value.
8686void
8688{priv_->num_removed_func_filtered_out = t;}
8689
8690/// Getter for the net number of function removed.
8691///
8692/// This is the difference between the number of functions removed and
8693/// the number of functons removed that have been filtered out.
8694///
8695/// @return the net number of function removed.
8696size_t
8698{
8699 ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8700 return num_func_removed() - num_removed_func_filtered_out();
8701}
8702
8703/// Getter for the number of functions added.
8704///
8705/// @return the number of functions added.
8706size_t
8708{return priv_->num_func_added;}
8709
8710/// Setter for the number of functions added.
8711///
8712/// @param n the new number of functions added.
8713void
8715{priv_->num_func_added = n;}
8716
8717/// Getter for the number of added function that have been filtered out.
8718///
8719/// @return the number of added function that have been filtered out.
8720size_t
8722{
8723 if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8724 return num_func_added();
8725 return priv_->num_added_func_filtered_out;
8726}
8727
8728/// Setter for the number of added function that have been filtered
8729/// out.
8730///
8731/// @param n the new value.
8732void
8734{priv_->num_added_func_filtered_out = n;}
8735
8736/// Getter for the net number of added functions.
8737///
8738/// The net number of added functions is the difference between the
8739/// number of added functions and the number of added functions that
8740/// have been filtered out.
8741///
8742/// @return the net number of added functions.
8743size_t
8745{
8746 ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8747 return num_func_added() - num_added_func_filtered_out();
8748}
8749
8750/// Getter for the number of functions that have a change in one of
8751/// their sub-types.
8752///
8753/// @return the number of functions that have a change in one of their
8754/// sub-types.
8755size_t
8757{return priv_->num_func_changed;}
8758
8759/// Setter for the number of functions that have a change in one of
8760/// their sub-types.
8761///
8762/// @@param n the new number of functions that have a change in one of
8763/// their sub-types.
8764void
8766{priv_->num_func_changed = n;}
8767
8768/// Getter for the number of functions that have a change in one of
8769/// their sub-types, and that have been filtered out.
8770///
8771/// @return the number of functions that have a change in one of their
8772/// sub-types, and that have been filtered out.
8773size_t
8775{return priv_->num_changed_func_filtered_out;}
8776
8777/// Setter for the number of functions that have a change in one of
8778/// their sub-types, and that have been filtered out.
8779///
8780/// @param n the new number of functions that have a change in one of their
8781/// sub-types, and that have been filtered out.
8782void
8784{priv_->num_changed_func_filtered_out = n;}
8785
8786/// Getter for the number of functions that carry virtual member
8787/// offset changes.
8788///
8789/// @return the number of functions that carry virtual member changes.
8790size_t
8792{return priv_->num_func_with_virt_offset_changes;}
8793
8794/// Setter for the number of functions that carry virtual member
8795/// offset changes.
8796///
8797/// @param n the new number of functions that carry virtual member
8798/// offset. changes.
8799void
8801{priv_->num_func_with_virt_offset_changes = n;}
8802
8803/// Getter for the number of functions that have a change in their
8804/// sub-types, minus the number of these functions that got filtered
8805/// out from the diff.
8806///
8807/// @return for the the number of functions that have a change in
8808/// their sub-types, minus the number of these functions that got
8809/// filtered out from the diff.
8810size_t
8812{return num_func_changed() - num_changed_func_filtered_out();}
8813
8814/// Getter for the number of variables removed.
8815///
8816/// @return the number of variables removed.
8817size_t
8819{return priv_->num_vars_removed;}
8820
8821/// Setter for the number of variables removed.
8822///
8823/// @param n the new number of variables removed.
8824void
8826{priv_->num_vars_removed = n;}
8827
8828/// Getter for the number removed variables that have been filtered
8829/// out.
8830///
8831/// @return the number removed variables that have been filtered out.
8832size_t
8834{
8835 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
8836 return num_vars_removed();
8837 return priv_->num_removed_vars_filtered_out;
8838}
8839
8840/// Setter for the number of removed variables that have been filtered
8841/// out.
8842///
8843/// @param n the new value.
8844void
8846{priv_->num_removed_vars_filtered_out = n;}
8847
8848/// Getter for the net number of removed variables.
8849///
8850/// The net number of removed variables is the difference between the
8851/// number of removed variables and the number of removed variables
8852/// that have been filtered out.
8853///
8854/// @return the net number of removed variables.
8855size_t
8857{
8858 ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
8859 return num_vars_removed() - num_removed_vars_filtered_out();
8860}
8861
8862/// Getter for the number of variables added.
8863///
8864/// @return the number of variables added.
8865size_t
8867{return priv_->num_vars_added;}
8868
8869/// Setter for the number of variables added.
8870///
8871/// @param n the new number of variables added.
8872void
8874{priv_->num_vars_added = n;}
8875
8876/// Getter for the number of added variables that have been filtered
8877/// out.
8878///
8879/// @return the number of added variables that have been filtered out.
8880size_t
8882{
8883 if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8884 return num_vars_added();
8885 return priv_->num_added_vars_filtered_out;
8886}
8887
8888/// Setter for the number of added variables that have been filtered
8889/// out.
8890///
8891/// @param n the new value.
8892void
8894{priv_->num_added_vars_filtered_out = n;}
8895
8896/// Getter for the net number of added variables.
8897///
8898/// The net number of added variables is the difference between the
8899/// number of added variables and the number of added variables that
8900/// have been filetered out.
8901///
8902/// @return the net number of added variables.
8903size_t
8905{
8906 ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8907 return num_vars_added() - num_added_vars_filtered_out();
8908}
8909
8910/// Getter for the number of variables that have a change in one of
8911/// their sub-types.
8912///
8913/// @return the number of variables that have a change in one of their
8914/// sub-types.
8915size_t
8917{return priv_->num_vars_changed;}
8918
8919/// Setter for the number of variables that have a change in one of
8920/// their sub-types.
8921///
8922/// @param n the new number of variables that have a change in one of
8923/// their sub-types.
8924void
8926{priv_->num_vars_changed = n;}
8927
8928/// Getter for the number of variables that have a change in one of
8929/// their sub-types, and that have been filtered out.
8930///
8931/// @return the number of functions that have a change in one of their
8932/// sub-types, and that have been filtered out.
8933size_t
8935{return priv_->num_changed_vars_filtered_out;}
8936
8937/// Setter for the number of variables that have a change in one of
8938/// their sub-types, and that have been filtered out.
8939///
8940/// @param n the new number of variables that have a change in one of their
8941/// sub-types, and that have been filtered out.
8942void
8944{priv_->num_changed_vars_filtered_out = n;}
8945
8946/// Getter for the number of variables that have a change in their
8947/// sub-types, minus the number of these variables that got filtered
8948/// out from the diff.
8949///
8950/// @return for the the number of variables that have a change in
8951/// their sub-types, minus the number of these variables that got
8952/// filtered out from the diff.
8953size_t
8955{return num_vars_changed() - num_changed_vars_filtered_out();}
8956
8957/// Getter for the number of function symbols (not referenced by any
8958/// debug info) that got removed.
8959///
8960/// @return the number of function symbols (not referenced by any
8961/// debug info) that got removed.
8962size_t
8964{return priv_->num_func_syms_removed;}
8965
8966/// Setter for the number of function symbols (not referenced by any
8967/// debug info) that got removed.
8968///
8969/// @param n the number of function symbols (not referenced by any
8970/// debug info) that got removed.
8971void
8973{priv_->num_func_syms_removed = n;}
8974
8975/// Getter for the number of removed function symbols, not referenced
8976/// by debug info, that have been filtered out.
8977///
8978/// @return the number of removed function symbols, not referenced by
8979/// debug info, that have been filtered out.
8980size_t
8982{
8983 if (priv_->ctxt()
8984 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8985 return num_func_syms_removed();
8986 return priv_->num_removed_func_syms_filtered_out;
8987}
8988
8989/// Setter for the number of removed function symbols, not referenced
8990/// by debug info, that have been filtered out.
8991///
8992/// @param n the new the number of removed function symbols, not
8993/// referenced by debug info, that have been filtered out.
8994void
8996{priv_->num_removed_func_syms_filtered_out = n;}
8997
8998/// Getter of the net number of removed function symbols that are not
8999/// referenced by any debug info.
9000///
9001/// This is the difference between the total number of removed
9002/// function symbols and the number of removed function symbols that
9003/// have been filteted out. Both numbers are for symbols not
9004/// referenced by debug info.
9005///
9006/// return the net number of removed function symbols that are not
9007/// referenced by any debug info.
9008size_t
9010{
9011 ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
9012 return num_func_syms_removed() - num_removed_func_syms_filtered_out();
9013}
9014
9015/// Getter for the number of function symbols (not referenced by any
9016/// debug info) that got added.
9017///
9018/// @return the number of function symbols (not referenced by any
9019/// debug info) that got added.
9020size_t
9022{return priv_->num_func_syms_added;}
9023
9024/// Setter for the number of function symbols (not referenced by any
9025/// debug info) that got added.
9026///
9027/// @param n the new number of function symbols (not referenced by any
9028/// debug info) that got added.
9029void
9031{priv_->num_func_syms_added = n;}
9032
9033/// Getter for the number of added function symbols, not referenced by
9034/// any debug info, that have been filtered out.
9035///
9036/// @return the number of added function symbols, not referenced by
9037/// any debug info, that have been filtered out.
9038size_t
9040{
9041 if (priv_->ctxt()
9042 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9043 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9044 return num_func_syms_added();
9045 return priv_->num_added_func_syms_filtered_out;
9046}
9047
9048/// Setter for the number of added function symbols, not referenced by
9049/// any debug info, that have been filtered out.
9050///
9051/// @param n the new number of added function symbols, not referenced
9052/// by any debug info, that have been filtered out.
9053void
9055{priv_->num_added_func_syms_filtered_out = n;}
9056
9057/// Getter of the net number of added function symbols that are not
9058/// referenced by any debug info.
9059///
9060/// This is the difference between the total number of added
9061/// function symbols and the number of added function symbols that
9062/// have been filteted out. Both numbers are for symbols not
9063/// referenced by debug info.
9064///
9065/// return the net number of added function symbols that are not
9066/// referenced by any debug info.
9067size_t
9069{
9070 ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
9071 return num_func_syms_added()- num_added_func_syms_filtered_out();
9072}
9073
9074/// Getter for the number of variable symbols (not referenced by any
9075/// debug info) that got removed.
9076///
9077/// @return the number of variable symbols (not referenced by any
9078/// debug info) that got removed.
9079size_t
9081{return priv_->num_var_syms_removed;}
9082
9083/// Setter for the number of variable symbols (not referenced by any
9084/// debug info) that got removed.
9085///
9086/// @param n the number of variable symbols (not referenced by any
9087/// debug info) that got removed.
9088void
9090{priv_->num_var_syms_removed = n;}
9091
9092/// Getter for the number of removed variable symbols, not referenced
9093/// by any debug info, that have been filtered out.
9094///
9095/// @return the number of removed variable symbols, not referenced
9096/// by any debug info, that have been filtered out.
9097size_t
9099{
9100 if (priv_->ctxt()
9101 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
9102 return num_var_syms_removed();
9103 return priv_->num_removed_var_syms_filtered_out;
9104}
9105
9106/// Setter for the number of removed variable symbols, not referenced
9107/// by any debug info, that have been filtered out.
9108///
9109/// @param n the number of removed variable symbols, not referenced by
9110/// any debug info, that have been filtered out.
9111void
9113{priv_->num_removed_var_syms_filtered_out = n;}
9114
9115/// Getter of the net number of removed variable symbols that are not
9116/// referenced by any debug info.
9117///
9118/// This is the difference between the total number of removed
9119/// variable symbols and the number of removed variable symbols that
9120/// have been filteted out. Both numbers are for symbols not
9121/// referenced by debug info.
9122///
9123/// return the net number of removed variable symbols that are not
9124/// referenced by any debug info.
9125size_t
9127{
9128 ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
9129 return num_var_syms_removed() - num_removed_var_syms_filtered_out();
9130}
9131
9132/// Getter for the number of variable symbols (not referenced by any
9133/// debug info) that got added.
9134///
9135/// @return the number of variable symbols (not referenced by any
9136/// debug info) that got added.
9137size_t
9139{return priv_->num_var_syms_added;}
9140
9141/// Setter for the number of variable symbols (not referenced by any
9142/// debug info) that got added.
9143///
9144/// @param n the new number of variable symbols (not referenced by any
9145/// debug info) that got added.
9146void
9148{priv_->num_var_syms_added = n;}
9149
9150/// Getter for the number of added variable symbols, not referenced by
9151/// any debug info, that have been filtered out.
9152///
9153/// @return the number of added variable symbols, not referenced by
9154/// any debug info, that have been filtered out.
9155size_t
9157{
9158 if (priv_->ctxt()
9159 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
9160 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
9161 return num_var_syms_added();
9162 return priv_->num_added_var_syms_filtered_out;
9163}
9164
9165/// Setter for the number of added variable symbols, not referenced by
9166/// any debug info, that have been filtered out.
9167///
9168/// @param n the new number of added variable symbols, not referenced
9169/// by any debug info, that have been filtered out.
9170void
9172{priv_->num_added_var_syms_filtered_out = n;}
9173
9174/// Getter of the net number of added variable symbols that are not
9175/// referenced by any debug info.
9176///
9177/// This is the difference between the total number of added
9178/// variable symbols and the number of added variable symbols that
9179/// have been filteted out. Both numbers are for symbols not
9180/// referenced by debug info.
9181///
9182/// return the net number of added variable symbols that are not
9183/// referenced by any debug info.
9184size_t
9186{
9187 ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
9188 return num_var_syms_added() - num_added_var_syms_filtered_out();
9189}
9190
9191/// Getter of the number of leaf type change diff nodes.
9192///
9193/// @return the number of leaf type change diff nodes.
9194size_t
9196{return priv_->num_leaf_changes;}
9197
9198/// Setter of the number of leaf type change diff nodes.
9199///
9200/// @param n the new number of leaf type change diff nodes.
9201void
9203{priv_->num_leaf_changes = n;}
9204
9205/// Getter of the number of leaf type change diff nodes that have been
9206/// filtered out.
9207///
9208/// @return the number of leaf type change diff nodes that have been
9209size_t
9211{return priv_->num_leaf_changes_filtered_out;}
9212
9213/// Setter of the number of leaf type change diff nodes that have been
9214/// filtered out.
9215///
9216/// @param n the new number of leaf type change diff nodes that have
9217/// been filtered out.
9218void
9220{priv_->num_leaf_changes_filtered_out = n;}
9221
9222/// Getter of the net number of leaf change diff nodes.
9223///
9224/// This is the difference between the total number of leaf change
9225/// diff nodes, and the number of the leaf change diff nodes that have
9226/// been filtered out.
9227///
9228/// A leaf change is either a type change, a function change or a
9229/// variable change.
9230size_t
9232{
9233 ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
9234 return num_leaf_changes() - num_leaf_changes_filtered_out();
9235}
9236
9237/// Getter for the number of leaf type change diff nodes.
9238///
9239/// @return the number of leaf type changes diff nodes.
9240size_t
9242{return priv_->num_leaf_type_changes;}
9243
9244/// Setter for the number of leaf type change diff nodes.
9245///
9246/// @param n the new number of leaf type change diff nodes.
9247void
9249{priv_->num_leaf_type_changes = n;}
9250
9251/// Getter for the number of filtered out leaf type change diff nodes.
9252///
9253/// @return the number of filtered out leaf type change diff nodes.
9254size_t
9256{return priv_->num_leaf_type_changes_filtered_out;}
9257
9258/// Setter for the number of filtered out leaf type change diff nodes.
9259/// @param n the new number of filtered out leaf type change diff nodes.
9260void
9262{priv_->num_leaf_type_changes_filtered_out = n;}
9263
9264/// Getter for the net number of leaf type change diff nodes.
9265///
9266/// This is the difference between the number of leaf type changes and
9267/// the number of filtered out leaf type changes.
9268///
9269/// @return the net number of leaf type change diff nodes.
9270size_t
9272{return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
9273
9274/// Getter for the number of leaf function change diff nodes.
9275///
9276/// @return the number of leaf function change diff nodes.
9277size_t
9279{return priv_->num_leaf_func_changes;}
9280
9281/// Setter for the number of leaf function change diff nodes.
9282///
9283/// @param n the new number of leaf function change diff nodes.
9284void
9286{priv_->num_leaf_func_changes = n;}
9287
9288/// Getter for the number of leaf function change diff nodes that were
9289/// filtered out.
9290///
9291/// @return the number of leaf function change diff nodes that were
9292/// filtered out.
9293size_t
9295{return priv_->num_leaf_func_changes_filtered_out;}
9296
9297/// Setter for the number of leaf function change diff nodes that were
9298/// filtered out.
9299///
9300/// @param n the new number of leaf function change diff nodes that
9301/// were filtered out.
9302void
9304{priv_->num_leaf_func_changes_filtered_out = n;}
9305
9306/// Getter for the net number of leaf function change diff nodes.
9307///
9308/// This is the difference between the number of leaf function change
9309/// diff nodes and the number of filtered out leaf function change
9310/// diff nodes.
9311///
9312/// @return the net number of leaf function change diff nodes.
9313size_t
9315{return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
9316
9317/// Getter for the number of leaf variable change diff nodes.
9318///
9319/// @return the number of leaf variable change diff nodes.
9320size_t
9322{return priv_->num_leaf_var_changes;}
9323
9324/// Setter for the number of leaf variable change diff nodes.
9325///
9326/// @param n the number of leaf variable change diff nodes.
9327void
9329{priv_->num_leaf_var_changes = n;}
9330
9331/// Getter of the number of added types that are unreachable from the
9332/// public interface of the ABI corpus.
9333///
9334/// Public interface means the set of defined and publicly exported
9335/// functions and variables of the ABI corpus.
9336///
9337/// @return the number of added types that are unreachable from the
9338/// public interface of the ABI corpus.
9339size_t
9341{return priv_->num_added_unreachable_types;}
9342
9343/// Setter of the number of added types that are unreachable from the
9344/// public interface (global functions or variables) of the ABI
9345/// corpus.
9346///
9347/// Public interface means the set of defined and publicly exported
9348/// functions and variables of the ABI corpus.
9349///
9350/// @param n the new number of added types that are unreachable from
9351/// the public interface of the ABI corpus.
9352void
9354{priv_->num_added_unreachable_types = n;}
9355
9356/// Getter of the number of added types that are unreachable from
9357/// public interfaces and that are filtered out by suppression
9358/// specifications.
9359///
9360/// @return the number of added types that are unreachable from public
9361/// interfaces and that are filtered out by suppression
9362/// specifications.
9363size_t
9365{return priv_->num_added_unreachable_types_filtered_out;}
9366
9367/// Setter of the number of added types that are unreachable from
9368/// public interfaces and that are filtered out by suppression
9369/// specifications.
9370///
9371/// @param n the new number of added types that are unreachable from
9372/// public interfaces and that are filtered out by suppression
9373/// specifications.
9374void
9376{priv_->num_added_unreachable_types_filtered_out = n;}
9377
9378/// Getter of the number of added types that are unreachable from
9379/// public interfaces and that are *NOT* filtered out by suppression
9380/// specifications.
9381///
9382/// @return the number of added types that are unreachable from public
9383/// interfaces and that are *NOT* filtered out by suppression
9384/// specifications.
9385size_t
9387{
9388 ABG_ASSERT(num_added_unreachable_types()
9389 >=
9390 num_added_unreachable_types_filtered_out());
9391
9392 return (num_added_unreachable_types()
9393 -
9394 num_added_unreachable_types_filtered_out());
9395}
9396
9397/// Getter of the number of removed types that are unreachable from
9398/// the public interface of the ABI corpus.
9399///
9400/// Public interface means the set of defined and publicly exported
9401/// functions and variables of the ABI corpus.
9402///
9403/// @return the number of removed types that are unreachable from
9404/// the public interface of the ABI corpus.
9405size_t
9407{return priv_->num_removed_unreachable_types;}
9408
9409/// Setter of the number of removed types that are unreachable from
9410/// the public interface of the ABI corpus.
9411///
9412/// Public interface means the set of defined and publicly exported
9413/// functions and variables of the ABI corpus.
9414///
9415///@param n the new number of removed types that are unreachable from
9416/// the public interface of the ABI corpus.
9417void
9419{priv_->num_removed_unreachable_types = n;}
9420
9421/// Getter of the number of removed types that are not reachable from
9422/// public interfaces and that have been filtered out by suppression
9423/// specifications.
9424///
9425/// @return the number of removed types that are not reachable from
9426/// public interfaces and that have been filtered out by suppression
9427/// specifications.
9428size_t
9430{return priv_->num_removed_unreachable_types_filtered_out;}
9431
9432/// Setter of the number of removed types that are not reachable from
9433/// public interfaces and that have been filtered out by suppression
9434/// specifications.
9435///
9436/// @param n the new number of removed types that are not reachable
9437/// from public interfaces and that have been filtered out by
9438/// suppression specifications.
9439void
9441{priv_->num_removed_unreachable_types_filtered_out = n;}
9442
9443/// Getter of the number of removed types that are not reachable from
9444/// public interfaces and that have *NOT* been filtered out by
9445/// suppression specifications.
9446///
9447/// @return the number of removed types that are not reachable from
9448/// public interfaces and that have *NOT* been filtered out by
9449/// suppression specifications.
9450size_t
9452{
9453 ABG_ASSERT(num_removed_unreachable_types()
9454 >=
9455 num_removed_unreachable_types_filtered_out());
9456
9457 return (num_removed_unreachable_types()
9458 -
9459 num_removed_unreachable_types_filtered_out());
9460}
9461
9462/// Getter of the number of changed types that are unreachable from
9463/// the public interface of the ABI corpus.
9464///
9465/// Public interface means the set of defined and publicly exported
9466/// functions and variables of the ABI corpus.
9467///
9468/// @return the number of changed types that are unreachable from the
9469/// public interface of the ABI corpus.
9470size_t
9472{return priv_->num_changed_unreachable_types;}
9473
9474/// Setter of the number of changed types that are unreachable from
9475/// the public interface of the ABI corpus.
9476///
9477/// Public interface means the set of defined and publicly exported
9478/// functions and variables of the ABI corpus.
9479///
9480///@param n the new number of changed types that are unreachable from
9481/// the public interface of the ABI corpus.
9482void
9484{priv_->num_changed_unreachable_types = n;}
9485
9486/// Getter of the number of changed types that are unreachable from
9487/// public interfaces and that have been filtered out by suppression
9488/// specifications.
9489///
9490/// @return the number of changed types that are unreachable from
9491/// public interfaces and that have been filtered out by suppression
9492/// specifications.
9493size_t
9495{return priv_->num_changed_unreachable_types_filtered_out;}
9496
9497/// Setter of the number of changed types that are unreachable from
9498/// public interfaces and that have been filtered out by suppression
9499/// specifications.
9500///
9501/// @param n the new number of changed types that are unreachable from
9502/// public interfaces and that have been filtered out by suppression
9503/// specifications.
9504void
9506{priv_->num_changed_unreachable_types_filtered_out = n;}
9507
9508/// Getter of the number of changed types that are unreachable from
9509/// public interfaces and that have *NOT* been filtered out by
9510/// suppression specifications.
9511///
9512/// @return the number of changed types that are unreachable from
9513/// public interfaces and that have *NOT* been filtered out by
9514/// suppression specifications.
9515size_t
9517{
9518 ABG_ASSERT(num_changed_unreachable_types()
9519 >=
9520 num_changed_unreachable_types_filtered_out());
9521
9522 return (num_changed_unreachable_types()
9523 -
9524 num_changed_unreachable_types_filtered_out());
9525}
9526
9527/// Getter for the number of leaf variable changes diff nodes that
9528/// have been filtered out.
9529///
9530/// @return the number of leaf variable changes diff nodes that have
9531/// been filtered out.
9532size_t
9534{return priv_->num_leaf_var_changes_filtered_out;}
9535
9536/// Setter for the number of leaf variable changes diff nodes that
9537/// have been filtered out.
9538///
9539/// @param n the number of leaf variable changes diff nodes that have
9540/// been filtered out.
9541void
9543{priv_->num_leaf_var_changes_filtered_out = n;}
9544
9545/// Getter for the net number of leaf variable change diff nodes.
9546///
9547/// This the difference between the number of leaf variable change
9548/// diff nodes and the number of filtered out leaf variable change
9549/// diff nodes.
9550///
9551/// @return the net number of leaf variable change diff nodes.
9552size_t
9554{return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9555
9556
9557// <corpus_diff stuff>
9558
9559/// Getter of the context associated with this corpus.
9560///
9561/// @return a smart pointer to the context associate with the corpus.
9564{return ctxt_.lock();}
9565
9566/// Tests if the lookup tables are empty.
9567///
9568/// @return true if the lookup tables are empty, false otherwise.
9569bool
9571{
9572 return (deleted_fns_.empty()
9573 && added_fns_.empty()
9574 && changed_fns_map_.empty()
9575 && deleted_vars_.empty()
9576 && added_vars_.empty()
9577 && changed_vars_map_.empty());
9578}
9579
9580/// Clear the lookup tables useful for reporting an enum_diff.
9581void
9583{
9584 deleted_fns_.clear();
9585 added_fns_.clear();
9586 changed_fns_map_.clear();
9587 deleted_vars_.clear();
9588 added_vars_.clear();
9589 changed_vars_map_.clear();
9590}
9591
9592/// If the lookup tables are not yet built, walk the differences and
9593/// fill the lookup tables.
9594void
9596{
9597 if (!lookup_tables_empty())
9598 return;
9599
9600 diff_context_sptr ctxt = get_context();
9601
9602 {
9603 edit_script& e = fns_edit_script_;
9604
9605 for (vector<deletion>::const_iterator it = e.deletions().begin();
9606 it != e.deletions().end();
9607 ++it)
9608 {
9609 unsigned i = it->index();
9610 ABG_ASSERT(i < first_->get_functions().size());
9611
9612 const function_decl* deleted_fn = first_->get_functions()[i];
9613 string n = get_function_id_or_pretty_representation(deleted_fn);
9614 ABG_ASSERT(!n.empty());
9615 // The below is commented out because there can be several
9616 // functions with the same ID in the corpus. So several
9617 // functions with the same ID can be deleted.
9618 // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9619 deleted_fns_[n] = deleted_fn;
9620 }
9621
9622 for (vector<insertion>::const_iterator it = e.insertions().begin();
9623 it != e.insertions().end();
9624 ++it)
9625 {
9626 for (vector<unsigned>::const_iterator iit =
9627 it->inserted_indexes().begin();
9628 iit != it->inserted_indexes().end();
9629 ++iit)
9630 {
9631 unsigned i = *iit;
9632 const function_decl* added_fn = second_->get_functions()[i];
9633 string n = get_function_id_or_pretty_representation(added_fn);
9634 ABG_ASSERT(!n.empty());
9635 // The below is commented out because there can be several
9636 // functions with the same ID in the corpus. So several
9637 // functions with the same ID can be added.
9638 // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9639 string_function_ptr_map::const_iterator j =
9640 deleted_fns_.find(n);
9641 if (j != deleted_fns_.end())
9642 {
9643 function_decl_sptr f(const_cast<function_decl*>(j->second),
9644 noop_deleter());
9645 function_decl_sptr s(const_cast<function_decl*>(added_fn),
9646 noop_deleter());
9647 function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9648 if (*j->second != *added_fn)
9649 changed_fns_map_[j->first] = d;
9650 deleted_fns_.erase(j);
9651 }
9652 else
9653 added_fns_[n] = added_fn;
9654 }
9655 }
9656 sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9657
9658 // Now walk the allegedly deleted functions; check if their
9659 // underlying symbols are deleted as well; otherwise, consider
9660 // that the function in question hasn't been deleted.
9661
9662 vector<string> to_delete;
9663 for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9664 i != deleted_fns_.end();
9665 ++i)
9666 if (second_->lookup_function_symbol(*i->second->get_symbol()))
9667 to_delete.push_back(i->first);
9668
9669 for (vector<string>::const_iterator i = to_delete.begin();
9670 i != to_delete.end();
9671 ++i)
9672 deleted_fns_.erase(*i);
9673
9674 // Do something similar for added functions.
9675
9676 to_delete.clear();
9677 for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9678 i != added_fns_.end();
9679 ++i)
9680 {
9681 if (first_->lookup_function_symbol(*i->second->get_symbol()))
9682 to_delete.push_back(i->first);
9683 else if (! i->second->get_symbol()->get_version().is_empty()
9684 && i->second->get_symbol()->get_version().is_default())
9685 // We are looking for a symbol that has a default version,
9686 // and which seems to be newly added. Let's see if the same
9687 // symbol with *no* version was already present in the
9688 // former corpus. If yes, then the symbol shouldn't be
9689 // considered as 'added'.
9690 {
9691 elf_symbol::version empty_version;
9692 if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
9693 empty_version))
9694 to_delete.push_back(i->first);
9695 }
9696 }
9697
9698 for (vector<string>::const_iterator i = to_delete.begin();
9699 i != to_delete.end();
9700 ++i)
9701 added_fns_.erase(*i);
9702 }
9703
9704 {
9705 edit_script& e = vars_edit_script_;
9706
9707 for (vector<deletion>::const_iterator it = e.deletions().begin();
9708 it != e.deletions().end();
9709 ++it)
9710 {
9711 unsigned i = it->index();
9712 ABG_ASSERT(i < first_->get_variables().size());
9713
9714 const var_decl_sptr deleted_var = first_->get_variables()[i];
9715 string n = deleted_var->get_id();
9716 ABG_ASSERT(!n.empty());
9717 ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
9718 deleted_vars_[n] = deleted_var;
9719 }
9720
9721 for (vector<insertion>::const_iterator it = e.insertions().begin();
9722 it != e.insertions().end();
9723 ++it)
9724 {
9725 for (vector<unsigned>::const_iterator iit =
9726 it->inserted_indexes().begin();
9727 iit != it->inserted_indexes().end();
9728 ++iit)
9729 {
9730 unsigned i = *iit;
9731 const var_decl_sptr added_var = second_->get_variables()[i];
9732 string n = added_var->get_id();
9733 ABG_ASSERT(!n.empty());
9734 {
9735 string_var_ptr_map::const_iterator k = added_vars_.find(n);
9736 if ( k != added_vars_.end())
9737 {
9738 ABG_ASSERT(is_member_decl(k->second)
9739 && get_member_is_static(k->second));
9740 continue;
9741 }
9742 }
9743 string_var_ptr_map::const_iterator j =
9744 deleted_vars_.find(n);
9745 if (j != deleted_vars_.end())
9746 {
9747 if (*j->second != *added_var)
9748 {
9749 var_decl_sptr f = j->second;
9750 var_decl_sptr s = added_var;
9751 changed_vars_map_[n] = compute_diff(f, s, ctxt);
9752 }
9753 deleted_vars_.erase(j);
9754 }
9755 else
9756 added_vars_[n] = added_var;
9757 }
9758 }
9759 sort_string_var_diff_sptr_map(changed_vars_map_,
9760 sorted_changed_vars_);
9761
9762 // Now walk the allegedly deleted variables; check if their
9763 // underlying symbols are deleted as well; otherwise consider
9764 // that the variable in question hasn't been deleted.
9765
9766 vector<string> to_delete;
9767 for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
9768 i != deleted_vars_.end();
9769 ++i)
9770 if (second_->lookup_variable_symbol(*i->second->get_symbol()))
9771 to_delete.push_back(i->first);
9772
9773 for (vector<string>::const_iterator i = to_delete.begin();
9774 i != to_delete.end();
9775 ++i)
9776 deleted_vars_.erase(*i);
9777
9778 // Do something similar for added variables.
9779
9780 to_delete.clear();
9781 for (string_var_ptr_map::const_iterator i = added_vars_.begin();
9782 i != added_vars_.end();
9783 ++i)
9784 if (first_->lookup_variable_symbol(*i->second->get_symbol()))
9785 to_delete.push_back(i->first);
9786 else if (! i->second->get_symbol()->get_version().is_empty()
9787 && i->second->get_symbol()->get_version().is_default())
9788 // We are looking for a symbol that has a default version,
9789 // and which seems to be newly added. Let's see if the same
9790 // symbol with *no* version was already present in the
9791 // former corpus. If yes, then the symbol shouldn't be
9792 // considered as 'added'.
9793 {
9794 elf_symbol::version empty_version;
9795 if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
9796 empty_version))
9797 to_delete.push_back(i->first);
9798 }
9799
9800 for (vector<string>::const_iterator i = to_delete.begin();
9801 i != to_delete.end();
9802 ++i)
9803 added_vars_.erase(*i);
9804 }
9805
9806 // Massage the edit script for added/removed function symbols that
9807 // were not referenced by any debug info and turn them into maps of
9808 // {symbol_name, symbol}.
9809 {
9810 edit_script& e = unrefed_fn_syms_edit_script_;
9811 for (vector<deletion>::const_iterator it = e.deletions().begin();
9812 it != e.deletions().end();
9813 ++it)
9814 {
9815 unsigned i = it->index();
9816 ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
9817 elf_symbol_sptr deleted_sym =
9818 first_->get_unreferenced_function_symbols()[i];
9819 if (!second_->lookup_function_symbol(*deleted_sym))
9820 deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
9821 }
9822
9823 for (vector<insertion>::const_iterator it = e.insertions().begin();
9824 it != e.insertions().end();
9825 ++it)
9826 {
9827 for (vector<unsigned>::const_iterator iit =
9828 it->inserted_indexes().begin();
9829 iit != it->inserted_indexes().end();
9830 ++iit)
9831 {
9832 unsigned i = *iit;
9833 ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
9834 elf_symbol_sptr added_sym =
9835 second_->get_unreferenced_function_symbols()[i];
9836 if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
9837 == deleted_unrefed_fn_syms_.end()))
9838 {
9839 if (!first_->lookup_function_symbol(*added_sym))
9840 {
9841 bool do_add = true;
9842 if (! added_sym->get_version().is_empty()
9843 && added_sym->get_version().is_default())
9844 {
9845 // So added_seem has a default version. If
9846 // the former corpus had a symbol with the
9847 // same name as added_sym but with *no*
9848 // version, then added_sym shouldn't be
9849 // considered as a newly added symbol.
9850 elf_symbol::version empty_version;
9851 if (first_->lookup_function_symbol(added_sym->get_name(),
9852 empty_version))
9853 do_add = false;
9854 }
9855
9856 if (do_add)
9857 added_unrefed_fn_syms_[added_sym->get_id_string()] =
9858 added_sym;
9859 }
9860 }
9861 else
9862 deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
9863 }
9864 }
9865 }
9866
9867 // Massage the edit script for added/removed variable symbols that
9868 // were not referenced by any debug info and turn them into maps of
9869 // {symbol_name, symbol}.
9870 {
9871 edit_script& e = unrefed_var_syms_edit_script_;
9872 for (vector<deletion>::const_iterator it = e.deletions().begin();
9873 it != e.deletions().end();
9874 ++it)
9875 {
9876 unsigned i = it->index();
9877 ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9878 elf_symbol_sptr deleted_sym =
9879 first_->get_unreferenced_variable_symbols()[i];
9880 if (!second_->lookup_variable_symbol(*deleted_sym))
9881 deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9882 }
9883
9884 for (vector<insertion>::const_iterator it = e.insertions().begin();
9885 it != e.insertions().end();
9886 ++it)
9887 {
9888 for (vector<unsigned>::const_iterator iit =
9889 it->inserted_indexes().begin();
9890 iit != it->inserted_indexes().end();
9891 ++iit)
9892 {
9893 unsigned i = *iit;
9894 ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9895 elf_symbol_sptr added_sym =
9896 second_->get_unreferenced_variable_symbols()[i];
9897 if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9898 == deleted_unrefed_var_syms_.end())
9899 {
9900 if (!first_->lookup_variable_symbol(*added_sym))
9901 {
9902 bool do_add = true;
9903 if (! added_sym->get_version().is_empty()
9904 && added_sym->get_version().is_default())
9905 {
9906 // So added_seem has a default version. If
9907 // the former corpus had a symbol with the
9908 // same name as added_sym but with *no*
9909 // version, then added_sym shouldn't be
9910 // considered as a newly added symbol.
9911 elf_symbol::version empty_version;
9912 if (first_->lookup_variable_symbol(added_sym->get_name(),
9913 empty_version))
9914 do_add = false;
9915 }
9916
9917 if (do_add)
9918 added_unrefed_var_syms_[added_sym->get_id_string()] =
9919 added_sym;
9920 }
9921 }
9922 else
9923 deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9924 }
9925 }
9926 }
9927
9928 // Handle the unreachable_types_edit_script_
9929 {
9930 edit_script& e = unreachable_types_edit_script_;
9931
9932 // Populate the map of deleted unreachable types from the
9933 // deletions of the edit script.
9934 for (vector<deletion>::const_iterator it = e.deletions().begin();
9935 it != e.deletions().end();
9936 ++it)
9937 {
9938 unsigned i = it->index();
9939 type_base_sptr t
9940 (first_->get_types_not_reachable_from_public_interfaces()[i]);
9941
9942 if (!is_user_defined_type(t))
9943 continue;
9944
9945 string repr =
9946 abigail::ir::get_pretty_representation(t, /*internal=*/false);
9947 deleted_unreachable_types_[repr] = t;
9948 }
9949
9950 // Populate the map of added and change unreachable types from the
9951 // insertions of the edit script.
9952 for (vector<insertion>::const_iterator it = e.insertions().begin();
9953 it != e.insertions().end();
9954 ++it)
9955 {
9956 for (vector<unsigned>::const_iterator iit =
9957 it->inserted_indexes().begin();
9958 iit != it->inserted_indexes().end();
9959 ++iit)
9960 {
9961 unsigned i = *iit;
9962 type_base_sptr t
9963 (second_->get_types_not_reachable_from_public_interfaces()[i]);
9964
9965 if (!is_user_defined_type(t))
9966 continue;
9967
9968 string repr =
9969 abigail::ir::get_pretty_representation(t, /*internal=*/false);
9970
9971 // Let's see if the inserted type we are looking at was
9972 // reported as deleted as well.
9973 //
9974 // If it's been deleted and a different version of it has
9975 // now been added, it means it's been *changed*. In that
9976 // case we'll compute the diff of that change and store it
9977 // in the map of changed unreachable types.
9978 //
9979 // Otherwise, it means the type's been added so we'll add
9980 // it to the set of added unreachable types.
9981
9982 string_type_base_sptr_map::const_iterator j =
9983 deleted_unreachable_types_.find(repr);
9984 if (j != deleted_unreachable_types_.end())
9985 {
9986 // So there was another type of the same pretty
9987 // representation which was reported as deleted.
9988 // Let's see if they are different or not ...
9989 decl_base_sptr old_type = is_decl(j->second);
9990 decl_base_sptr new_type = is_decl(t);
9991 if (old_type != new_type)
9992 {
9993 // The previously added type is different from this
9994 // one that is added. That means the initial type
9995 // was changed. Let's compute its diff and store it
9996 // as a changed type.
9997 diff_sptr d = compute_diff(old_type, new_type, ctxt);
9998 ABG_ASSERT(d->has_changes());
9999 changed_unreachable_types_[repr]= d;
10000 }
10001
10002 // In any case, the type was both deleted and added,
10003 // so we cannot have it marked as being deleted. So
10004 // let's remove it from the deleted types.
10005 deleted_unreachable_types_.erase(j);
10006 }
10007 else
10008 // The type wasn't previously reported as deleted, so
10009 // it's really added.
10010 added_unreachable_types_[repr] = t;
10011 }
10012 }
10013
10014 // Handle anonymous enums that got changed. An anonymous enum is
10015 // designated by its flat textual representation. So a change to
10016 // any of its enumerators results in a different enum. That is
10017 // represented by a deletion of the previous anonymous enum, and
10018 // the addition of a new one. For the user however, it's the same
10019 // enum that changed. Let's massage this "added/removed" pattern
10020 // to show what the user expects, namely, a changed anonymous
10021 // enum.
10022 {
10023 std::set<type_base_sptr> deleted_anon_types;
10024 std::set<type_base_sptr> added_anon_types;
10025
10026 for (auto entry : deleted_unreachable_types_)
10027 {
10028 if ((is_enum_type(entry.second)
10029 && is_enum_type(entry.second)->get_is_anonymous())
10030 || (is_class_or_union_type(entry.second)
10031 && is_class_or_union_type(entry.second)->get_is_anonymous()))
10032 deleted_anon_types.insert(entry.second);
10033 }
10034
10035
10036 for (auto entry : added_unreachable_types_)
10037 if ((is_enum_type(entry.second)
10038 && is_enum_type(entry.second)->get_is_anonymous())
10039 || (is_class_or_union_type(entry.second)
10040 && is_class_or_union_type(entry.second)->get_is_anonymous()))
10041 added_anon_types.insert(entry.second);
10042
10043 string_type_base_sptr_map added_anon_types_to_erase;
10044 string_type_base_sptr_map removed_anon_types_to_erase;
10045 enum_type_decl_sptr deleted_enum;
10046 class_or_union_sptr deleted_class;
10047
10048 // Look for deleted anonymous types (enums, unions, structs &
10049 // classes) which have enumerators or data members present in an
10050 // added anonymous type ...
10051 for (auto deleted: deleted_anon_types)
10052 {
10053 deleted_enum = is_enum_type(deleted);
10054 deleted_class = is_class_or_union_type(deleted);
10055
10056 // For enums, look for any enumerator of 'deleted_enum' that
10057 // is also present in an added anonymous enum.
10058 if (deleted_enum)
10059 {
10060 for (auto enr : deleted_enum->get_enumerators())
10061 {
10062 bool this_enum_got_changed = false;
10063 for (auto t : added_anon_types)
10064 {
10065 if (enum_type_decl_sptr added_enum = is_enum_type(t))
10066 if (is_enumerator_present_in_enum(enr, *added_enum))
10067 {
10068 // So the enumerator 'enr' from the
10069 // 'deleted_enum' enum is also present in the
10070 // 'added_enum' enum so we assume that
10071 // 'deleted_enum' and 'added_enum' are the same
10072 // enum that got changed. Let's represent it
10073 // using a diff node.
10074 diff_sptr d = compute_diff(deleted_enum,
10075 added_enum, ctxt);
10076 ABG_ASSERT(d->has_changes());
10077 string repr =
10079 /*internal=*/false);
10080 changed_unreachable_types_[repr]= d;
10081 this_enum_got_changed = true;
10082 string r1 =
10084 /*internal=*/false);
10085 string r2 =
10087 /*internal=*/false);
10088 removed_anon_types_to_erase[r1] = deleted_enum;
10089 added_anon_types_to_erase[r2] = added_enum;
10090 break;
10091 }
10092 }
10093 if (this_enum_got_changed)
10094 break;
10095 }
10096 }
10097 else if (deleted_class)
10098 {
10099 // For unions, structs & classes, look for any data
10100 // member of 'deleted_class' that is also present in an
10101 // added anonymous class.
10102 for (auto dm : deleted_class->get_data_members())
10103 {
10104 bool this_class_got_changed = false;
10105 for (auto klass : added_anon_types)
10106 {
10107 if (class_or_union_sptr added_class =
10109 if (class_or_union_types_of_same_kind(deleted_class,
10110 added_class)
10111 && lookup_data_member(added_class, dm))
10112 {
10113 // So the data member 'dm' from the
10114 // 'deleted_class' class is also present in
10115 // the 'added_class' class so we assume that
10116 // 'deleted_class' and 'added_class' are the
10117 // same anonymous class that got changed.
10118 // Let's represent it using a diff node.
10119 diff_sptr d = compute_diff(is_type(deleted_class),
10120 is_type(added_class),
10121 ctxt);
10122 ABG_ASSERT(d->has_changes());
10123 string repr =
10125 /*internal=*/false);
10126 changed_unreachable_types_[repr]= d;
10127 this_class_got_changed = true;
10128 string r1 =
10130 /*internal=*/false);
10131 string r2 =
10133 /*internal=*/false);
10134 removed_anon_types_to_erase[r1] = deleted_class;
10135 added_anon_types_to_erase[r2] = added_class;
10136 break;
10137 }
10138 }
10139 if (this_class_got_changed)
10140 break;
10141 }
10142 }
10143 }
10144
10145 // Now remove the added/removed anonymous types from their maps,
10146 // as they are now represented as a changed type, not an added
10147 // and removed anonymous type.
10148 for (auto entry : added_anon_types_to_erase)
10149 added_unreachable_types_.erase(entry.first);
10150
10151 for (auto entry : removed_anon_types_to_erase)
10152 deleted_unreachable_types_.erase(entry.first);
10153 }
10154 }
10155}
10156
10157/// Test if a change reports about a given @ref function_decl that is
10158/// changed in a certain way is suppressed by a given suppression
10159/// specifiation
10160///
10161/// @param fn the @ref function_decl to consider.
10162///
10163/// @param suppr the suppression specification to consider.
10164///
10165/// @param k the kind of change that happened to @p fn.
10166///
10167/// @param ctxt the context of the current diff.
10168///
10169/// @return true iff the suppression specification @p suppr suppresses
10170/// change reports about function @p fn, if that function changes in
10171/// the way expressed by @p k.
10172static bool
10173function_is_suppressed(const function_decl* fn,
10174 const suppression_sptr suppr,
10176 const diff_context_sptr ctxt)
10177{
10179 if (!fn_suppr)
10180 return false;
10181 return fn_suppr->suppresses_function(fn, k, ctxt);
10182}
10183
10184/// Test if a change reports about a given @ref var_decl that is
10185/// changed in a certain way is suppressed by a given suppression
10186/// specifiation
10187///
10188/// @param fn the @ref var_decl to consider.
10189///
10190/// @param suppr the suppression specification to consider.
10191///
10192/// @param k the kind of change that happened to @p fn.
10193///
10194/// @param ctxt the context of the current diff.
10195///
10196/// @return true iff the suppression specification @p suppr suppresses
10197/// change reports about variable @p fn, if that variable changes in
10198/// the way expressed by @p k.
10199static bool
10200variable_is_suppressed(const var_decl_sptr& var,
10201 const suppression_sptr suppr,
10203 const diff_context_sptr ctxt)
10204{
10206 if (!var_suppr)
10207 return false;
10208 return var_suppr->suppresses_variable(var, k, ctxt);
10209}
10210
10211/// Apply suppression specifications for this corpus diff to the set
10212/// of added/removed functions/variables, as well as to types not
10213/// reachable from global functions/variables.
10214void
10216{
10217 diff_context_sptr ctxt = get_context();
10218
10219 const suppressions_type& suppressions = ctxt->suppressions();
10220 for (suppressions_type::const_iterator i = suppressions.begin();
10221 i != suppressions.end();
10222 ++i)
10223 {
10224 // Added/Deleted functions.
10226 {
10227 // Added functions
10228 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10229 e != added_fns_.end();
10230 ++e)
10231 if (function_is_suppressed(e->second, fn_suppr,
10233 ctxt))
10234 suppressed_added_fns_[e->first] = e->second;
10235
10236 // Deleted functions.
10237 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10238 e != deleted_fns_.end();
10239 ++e)
10240 if (function_is_suppressed(e->second, fn_suppr,
10242 ctxt))
10243 suppressed_deleted_fns_[e->first] = e->second;
10244
10245 // Added function symbols not referenced by any debug info
10246 for (string_elf_symbol_map::const_iterator e =
10247 added_unrefed_fn_syms_.begin();
10248 e != added_unrefed_fn_syms_.end();
10249 ++e)
10250 if (fn_suppr->suppresses_function_symbol(e->second,
10252 ctxt))
10253 suppressed_added_unrefed_fn_syms_[e->first] = e->second;
10254
10255 // Removed function symbols not referenced by any debug info
10256 for (string_elf_symbol_map::const_iterator e =
10257 deleted_unrefed_fn_syms_.begin();
10258 e != deleted_unrefed_fn_syms_.end();
10259 ++e)
10260 if (fn_suppr->suppresses_function_symbol(e->second,
10262 ctxt))
10263 suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
10264 }
10265 // Added/Delete virtual member functions changes that might be
10266 // suppressed by a type_suppression that matches the enclosing
10267 // class of the virtual member function.
10268 else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
10269 {
10270 // Added virtual functions
10271 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10272 e != added_fns_.end();
10273 ++e)
10274 if (is_member_function(e->second)
10275 && get_member_function_is_virtual(e->second))
10276 {
10277 const function_decl *f = e->second;
10278 class_decl_sptr c =
10279 is_class_type(is_method_type(f->get_type())->get_class_type());
10280 ABG_ASSERT(c);
10281 if (type_suppr->suppresses_type(c, ctxt))
10282 suppressed_added_fns_[e->first] = e->second;
10283 }
10284 // Deleted virtual functions
10285 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10286 e != deleted_fns_.end();
10287 ++e)
10288 if (is_member_function(e->second)
10289 && get_member_function_is_virtual(e->second))
10290 {
10291 const function_decl *f = e->second;
10292 class_decl_sptr c =
10293 is_class_type(is_method_type(f->get_type())->get_class_type());
10294 ABG_ASSERT(c);
10295 if (type_suppr->suppresses_type(c, ctxt))
10296 suppressed_deleted_fns_[e->first] = e->second;
10297 }
10298
10299 // Apply this type suppression to deleted types
10300 // non-reachable from a public interface.
10301 for (string_type_base_sptr_map::const_iterator e =
10302 deleted_unreachable_types_.begin();
10303 e != deleted_unreachable_types_.end();
10304 ++e)
10305 if (type_suppr->suppresses_type(e->second, ctxt))
10306 suppressed_deleted_unreachable_types_[e->first] = e->second;
10307
10308 // Apply this type suppression to added types
10309 // non-reachable from a public interface.
10310 for (string_type_base_sptr_map::const_iterator e =
10311 added_unreachable_types_.begin();
10312 e != added_unreachable_types_.end();
10313 ++e)
10314 if (type_suppr->suppresses_type(e->second, ctxt))
10315 suppressed_added_unreachable_types_[e->first] = e->second;
10316 }
10317 // Added/Deleted variables
10318 else if (variable_suppression_sptr var_suppr =
10320 {
10321 // Added variables
10322 for (string_var_ptr_map::const_iterator e = added_vars_.begin();
10323 e != added_vars_.end();
10324 ++e)
10325 if (variable_is_suppressed(e->second, var_suppr,
10327 ctxt))
10328 suppressed_added_vars_[e->first] = e->second;
10329
10330 //Deleted variables
10331 for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
10332 e != deleted_vars_.end();
10333 ++e)
10334 if (variable_is_suppressed(e->second, var_suppr,
10336 ctxt))
10337 suppressed_deleted_vars_[e->first] = e->second;
10338
10339 // Added variable symbols not referenced by any debug info
10340 for (string_elf_symbol_map::const_iterator e =
10341 added_unrefed_var_syms_.begin();
10342 e != added_unrefed_var_syms_.end();
10343 ++e)
10344 if (var_suppr->suppresses_variable_symbol(e->second,
10346 ctxt))
10347 suppressed_added_unrefed_var_syms_[e->first] = e->second;
10348
10349 // Removed variable symbols not referenced by any debug info
10350 for (string_elf_symbol_map::const_iterator e =
10351 deleted_unrefed_var_syms_.begin();
10352 e != deleted_unrefed_var_syms_.end();
10353 ++e)
10354 if (var_suppr->suppresses_variable_symbol(e->second,
10356 ctxt))
10357 suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
10358 }
10359 }
10360}
10361
10362/// Test if the change reports for a given deleted function have
10363/// been deleted.
10364///
10365/// @param fn the function to consider.
10366///
10367/// @return true iff the change reports for a give given deleted
10368/// function have been deleted.
10369bool
10371{
10372 if (!fn)
10373 return false;
10374
10375 string_function_ptr_map::const_iterator i =
10376 suppressed_deleted_fns_.find(fn->get_id());
10377
10378 return (i != suppressed_deleted_fns_.end());
10379}
10380
10381/// Test if an added type that is unreachable from public interface
10382/// has been suppressed by a suppression specification.
10383///
10384/// @param t the added unreachable type to be considered.
10385///
10386/// @return true iff @p t has been suppressed by a suppression
10387/// specification.
10388bool
10390{
10391 if (!t)
10392 return false;
10393
10394 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10395 string_type_base_sptr_map::const_iterator i =
10396 suppressed_added_unreachable_types_.find(repr);
10397 if (i == suppressed_added_unreachable_types_.end())
10398 return false;
10399
10400 return true;
10401}
10402
10403/// Test if a deleted type that is unreachable from public interface
10404/// has been suppressed by a suppression specification.
10405///
10406/// @param t the deleted unreachable type to be considered.
10407///
10408/// @return true iff @p t has been suppressed by a suppression
10409/// specification.
10410bool
10412{
10413 if (!t)
10414 return false;
10415
10416 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10417 string_type_base_sptr_map::const_iterator i =
10418 suppressed_deleted_unreachable_types_.find(repr);
10419 if (i == suppressed_deleted_unreachable_types_.end())
10420 return false;
10421
10422 return true;
10423}
10424
10425/// Test if the change reports for a give given added function has
10426/// been deleted.
10427///
10428/// @param fn the function to consider.
10429///
10430/// @return true iff the change reports for a give given added
10431/// function has been deleted.
10432bool
10434{
10435 if (!fn)
10436 return false;
10437
10438 string_function_ptr_map::const_iterator i =
10439 suppressed_added_fns_.find(fn->get_id());
10440
10441 return (i != suppressed_added_fns_.end());
10442}
10443
10444/// Test if the change reports for a give given deleted variable has
10445/// been deleted.
10446///
10447/// @param var the variable to consider.
10448///
10449/// @return true iff the change reports for a give given deleted
10450/// variable has been deleted.
10451bool
10453{
10454 if (!var)
10455 return false;
10456
10457 string_var_ptr_map::const_iterator i =
10458 suppressed_deleted_vars_.find(var->get_id());
10459
10460 return (i != suppressed_deleted_vars_.end());
10461}
10462
10463/// Test if the change reports for a given added variable have been
10464/// suppressed.
10465///
10466/// @param var the variable to consider.
10467///
10468/// @return true iff the change reports for a given deleted
10469/// variable has been deleted.
10470bool
10472{
10473 if (!var)
10474 return false;
10475
10476 string_var_ptr_map::const_iterator i =
10477 suppressed_added_vars_.find(var->get_id());
10478
10479 return (i != suppressed_added_vars_.end());
10480}
10481
10482/// Test if the change reports for a given deleted function symbol
10483/// (that is not referenced by any debug info) has been suppressed.
10484///
10485/// @param var the function to consider.
10486///
10487/// @return true iff the change reports for a given deleted function
10488/// symbol has been suppressed.
10489bool
10491{
10492 if (!s)
10493 return false;
10494
10495 string_elf_symbol_map::const_iterator i =
10496 suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10497
10498 return (i != suppressed_deleted_unrefed_fn_syms_.end());
10499}
10500
10501/// Test if the change reports for a given added function symbol
10502/// (that is not referenced by any debug info) has been suppressed.
10503///
10504/// @param var the function to consider.
10505///
10506/// @return true iff the change reports for a given added function
10507/// symbol has been suppressed.
10508bool
10510{
10511 if (!s)
10512 return false;
10513
10514 string_elf_symbol_map::const_iterator i =
10515 suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10516
10517 return (i != suppressed_added_unrefed_fn_syms_.end());
10518}
10519
10520/// Test if the change reports for a given deleted variable symbol
10521/// (that is not referenced by any debug info) has been suppressed.
10522///
10523/// @param var the variable to consider.
10524///
10525/// @return true iff the change reports for a given deleted variable
10526/// symbol has been suppressed.
10527bool
10529{
10530 if (!s)
10531 return false;
10532
10533 string_elf_symbol_map::const_iterator i =
10534 suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10535
10536 return (i != suppressed_deleted_unrefed_var_syms_.end());
10537}
10538
10539/// Test if the change reports for a given added variable symbol
10540/// (that is not referenced by any debug info) has been suppressed.
10541///
10542/// @param var the variable to consider.
10543///
10544/// @return true iff the change reports for a given added variable
10545/// symbol has been suppressed.
10546bool
10548{
10549 if (!s)
10550 return false;
10551
10552 string_elf_symbol_map::const_iterator i =
10553 suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10554
10555 return (i != suppressed_added_unrefed_var_syms_.end());
10556}
10557
10558#ifdef do_count_diff_map_changes
10559#undef do_count_diff_map_changes
10560#endif
10561#define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10562 { \
10563 string_diff_ptr_map::const_iterator i; \
10564 for (i = diff_map.begin(); \
10565 i != diff_map.end(); \
10566 ++i) \
10567 { \
10568 if (const var_diff* d = is_var_diff(i->second)) \
10569 if (is_data_member(d->first_var())) \
10570 continue; \
10571 \
10572 if (i->second->has_local_changes()) \
10573 ++n_changes; \
10574 if (!i->second->get_canonical_diff()->to_be_reported()) \
10575 ++n_filtered; \
10576 } \
10577 }
10578
10579/// Count the number of leaf changes as well as the number of the
10580/// changes that have been filtered out.
10581///
10582/// @param num_changes out parameter. This is set to the total number
10583/// of leaf changes.
10584///
10585/// @param num_filtered out parameter. This is set to the number of
10586/// leaf changes that have been filtered out.
10587void
10588corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10589{
10590 count_leaf_type_changes(num_changes, num_filtered);
10591
10592 // Now count the non-type changes.
10593 do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10594 num_changes, num_filtered);
10595 do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10596 num_changes, num_filtered);
10597}
10598
10599/// Count the number of leaf *type* changes as well as the number of
10600/// the leaf type changes that have been filtered out.
10601///
10602/// @param num_changes out parameter. This is set to the total number
10603/// of leaf type changes.
10604///
10605/// @param num_filtered out parameter. This is set to the number of
10606/// leaf type changes that have been filtered out.
10607void
10609 size_t &num_filtered)
10610{
10611 do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10612 num_changes, num_filtered);
10613 do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10614 num_changes, num_filtered);
10615 do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10616 num_changes, num_filtered);
10617 do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10618 num_changes, num_filtered);
10619 do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10620 num_changes, num_filtered);
10621 do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10622 num_changes, num_filtered);
10623 do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10624 num_changes, num_filtered);
10625 do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10626 num_changes, num_filtered);
10627 do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10628 num_changes, num_filtered);
10629}
10630
10631/// Count the number of types not reachable from the interface (i.e,
10632/// not reachable from global functions or variables).
10633///
10634/// @param num_added this is set to the number of added types not
10635/// reachable from the interface.
10636///
10637/// @param num_deleted this is set to the number of deleted types not
10638/// reachable from the interface.
10639///
10640/// @param num_changed this is set to the number of changed types not
10641/// reachable from the interface.
10642///
10643/// @param num_filtered_added this is set to the number of added types
10644/// not reachable from the interface and that have been filtered out
10645/// by suppression specifications.
10646///
10647/// @param num_filtered_deleted this is set to the number of deleted
10648/// types not reachable from the interface and that have been filtered
10649/// out by suppression specifications.
10650///
10651/// @param num_filtered_changed this is set to the number of changed
10652/// types not reachable from the interface and that have been filtered
10653/// out by suppression specifications.
10654void
10656 size_t &num_deleted,
10657 size_t &num_changed,
10658 size_t &num_filtered_added,
10659 size_t &num_filtered_deleted,
10660 size_t &num_filtered_changed)
10661{
10662 num_added = added_unreachable_types_.size();
10663 num_deleted = deleted_unreachable_types_.size();
10664 num_changed = changed_unreachable_types_.size();
10665 num_filtered_added = suppressed_added_unreachable_types_.size();
10666 num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10667
10668 for (vector<diff_sptr>::const_iterator i =
10671 ++i)
10672 if (!(*i)->to_be_reported())
10673 ++num_filtered_changed;
10674}
10675
10676/// Get the map of diff nodes representing changed unreachable types.
10677///
10678/// @return the map of diff nodes representing changed unreachable
10679/// types.
10682{return changed_unreachable_types_;}
10683
10684/// Get the sorted vector of diff nodes representing changed
10685/// unreachable types.
10686///
10687/// Upon the first invocation of this method, if the vector is empty,
10688/// this function gets the diff nodes representing changed
10689/// unreachable, sort them, and return the sorted vector.
10690///
10691/// @return the sorted vector of diff nodes representing changed
10692/// unreachable types.
10693const vector<diff_sptr>&
10695{
10696if (changed_unreachable_types_sorted_.empty())
10697 if (!changed_unreachable_types_.empty())
10698 sort_string_diff_sptr_map(changed_unreachable_types_,
10699 changed_unreachable_types_sorted_);
10700
10701 return changed_unreachable_types_sorted_;
10702}
10703
10704/// Compute the diff stats.
10705///
10706/// To know the number of functions that got filtered out, this
10707/// function applies the categorizing filters to the diff sub-trees of
10708/// each function changes diff, prior to calculating the stats.
10709///
10710/// @param num_removed the number of removed functions.
10711///
10712/// @param num_added the number of added functions.
10713///
10714/// @param num_changed the number of changed functions.
10715///
10716/// @param num_filtered_out the number of changed functions that are
10717/// got filtered out from the report
10718void
10720{
10721 stat.num_func_removed(deleted_fns_.size());
10722 stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
10723 stat.num_func_added(added_fns_.size());
10724 stat.num_added_func_filtered_out(suppressed_added_fns_.size());
10725 stat.num_func_changed(changed_fns_map_.size());
10726
10727 stat.num_vars_removed(deleted_vars_.size());
10728 stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
10729 stat.num_vars_added(added_vars_.size());
10730 stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
10731 stat.num_vars_changed(changed_vars_map_.size());
10732
10733 diff_context_sptr ctxt = get_context();
10734
10736 if (ctxt->perform_change_categorization())
10737 {
10738 if (get_context()->do_log())
10739 {
10740 std::cerr << "in apply_filters_and_compute_diff_stats:"
10741 << "applying filters to "
10742 << changed_fns_.size()
10743 << " changed fns ...\n";
10744 t.start();
10745 }
10746 // Walk the changed function diff nodes to apply the categorization
10747 // filters.
10749 for (function_decl_diff_sptrs_type::const_iterator i =
10750 changed_fns_.begin();
10751 i != changed_fns_.end();
10752 ++i)
10753 {
10754 diff_sptr diff = *i;
10755 ctxt->maybe_apply_filters(diff);
10756 }
10757
10758 if (get_context()->do_log())
10759 {
10760 t.stop();
10761 std::cerr << "in apply_filters_and_compute_diff_stats:"
10762 << "filters to changed fn applied!:" << t << "\n";
10763
10764 std::cerr << "in apply_filters_and_compute_diff_stats:"
10765 << "applying filters to "
10766 << sorted_changed_vars_.size()
10767 << " changed vars ...\n";
10768 t.start();
10769 }
10770
10771 // Walk the changed variable diff nodes to apply the categorization
10772 // filters.
10773 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10774 i != sorted_changed_vars_.end();
10775 ++i)
10776 {
10777 diff_sptr diff = *i;
10778 ctxt->maybe_apply_filters(diff);
10779 }
10780
10781 if (get_context()->do_log())
10782 {
10783 t.stop();
10784 std::cerr << "in apply_filters_and_compute_diff_stats:"
10785 << "filters to changed vars applied!:" << t << "\n";
10786
10787 std::cerr << "in apply_filters_and_compute_diff_stats:"
10788 << "applying filters to unreachable types ...\n";
10789 t.start();
10790 }
10791
10792 // walk the changed unreachable types to apply categorization
10793 // filters
10795 ctxt->maybe_apply_filters(diff);
10796
10797 for (auto& entry : changed_unreachable_types())
10798 ctxt->maybe_apply_filters(entry.second);
10799
10800 if (get_context()->do_log())
10801 {
10802 t.stop();
10803 std::cerr << "in apply_filters_and_compute_diff_stats:"
10804 << "filters to unreachable types applied!:" << t << "\n";
10805
10806 std::cerr << "in apply_filters_and_compute_diff_stats:"
10807 << "categorizing redundant changed sub nodes ...\n";
10808 t.start();
10809 }
10810
10811 categorize_redundant_changed_sub_nodes();
10812
10813 if (get_context()->do_log())
10814 {
10815 t.stop();
10816 std::cerr << "in apply_filters_and_compute_diff_stats:"
10817 << "redundant changed sub nodes categorized!:" << t << "\n";
10818
10819 std::cerr << "in apply_filters_and_compute_diff_stats:"
10820 << "count changed fns ...\n";
10821 t.start();
10822 }
10823 }
10824
10825 // Walk the changed function diff nodes to count the number of
10826 // filtered-out functions and the number of functions with virtual
10827 // offset changes.
10828 for (function_decl_diff_sptrs_type::const_iterator i =
10829 changed_fns_.begin();
10830 i != changed_fns_.end();
10831 ++i)
10832 {
10833 if ((*i)->is_filtered_out())
10834 {
10836 (stat.num_changed_func_filtered_out() + 1);
10837
10838 if ((*i)->has_local_changes())
10841 }
10842 else
10843 {
10844 if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
10847 }
10848
10849 if ((*i)->has_local_changes())
10851 (stat.num_leaf_func_changes() + 1);
10852 }
10853
10854 if (get_context()->do_log())
10855 {
10856 t.stop();
10857 std::cerr << "in apply_filters_and_compute_diff_stats:"
10858 << "changed fn counted!:" << t << "\n";
10859
10860 std::cerr << "in apply_filters_and_compute_diff_stats:"
10861 << "count changed vars ...\n";
10862 t.start();
10863 }
10864
10865 // Walk the changed variables diff nodes to count the number of
10866 // filtered-out variables.
10867 for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
10868 i != sorted_changed_vars_.end();
10869 ++i)
10870 {
10871 if ((*i)->is_filtered_out())
10872 {
10874 (stat.num_changed_vars_filtered_out() + 1);
10875
10876 if ((*i)->has_local_changes())
10879 }
10880 if ((*i)->has_local_changes())
10882 (stat.num_leaf_var_changes() + 1);
10883 }
10884
10885 if (get_context()->do_log())
10886 {
10887 t.stop();
10888 std::cerr << "in apply_filters_and_compute_diff_stats:"
10889 << "changed vars counted!:" << t << "\n";
10890
10891 std::cerr << "in apply_filters_and_compute_diff_stats:"
10892 << "count leaf changed types ...\n";
10893 t.start();
10894 }
10895
10896 stat.num_func_syms_added(added_unrefed_fn_syms_.size());
10897 stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
10898 stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
10899 stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
10900 stat.num_var_syms_added(added_unrefed_var_syms_.size());
10901 stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
10902 stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
10903 stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
10904
10905 // Walk the general leaf type diff nodes to count them
10906 {
10907 size_t num_type_changes = 0, num_type_filtered = 0;
10908 count_leaf_type_changes(num_type_changes, num_type_filtered);
10909
10910 stat.num_leaf_type_changes(num_type_changes);
10911 stat.num_leaf_type_changes_filtered_out(num_type_filtered);
10912 }
10913
10914 if (get_context()->do_log())
10915 {
10916 t.stop();
10917 std::cerr << "in apply_filters_and_compute_diff_stats:"
10918 << "changed leaf types counted!:" << t << "\n";
10919
10920 std::cerr << "in apply_filters_and_compute_diff_stats:"
10921 << "count leaf changed artefacts ...\n";
10922 t.start();
10923 }
10924
10925 // Walk the general leaf artefacts diff nodes to count them
10926 {
10927 size_t num_changes = 0, num_filtered = 0;
10928 count_leaf_changes(num_changes, num_filtered);
10929
10930 stat.num_leaf_changes(num_changes);
10931 stat.num_leaf_changes_filtered_out(num_filtered);
10932 }
10933
10934 if (get_context()->do_log())
10935 {
10936 t.stop();
10937 std::cerr << "in apply_filters_and_compute_diff_stats:"
10938 << "changed leaf artefacts counted!:" << t << "\n";
10939
10940 std::cerr << "in apply_filters_and_compute_diff_stats:"
10941 << "count unreachable types ...\n";
10942 t.start();
10943 }
10944
10945 // Walk the unreachable types to count them
10946 {
10947 size_t num_added_unreachable_types = 0,
10948 num_changed_unreachable_types = 0,
10949 num_deleted_unreachable_types = 0,
10950 num_added_unreachable_types_filtered = 0,
10951 num_changed_unreachable_types_filtered = 0,
10952 num_deleted_unreachable_types_filtered = 0;
10953
10954 count_unreachable_types(num_added_unreachable_types,
10955 num_deleted_unreachable_types,
10956 num_changed_unreachable_types,
10957 num_added_unreachable_types_filtered,
10958 num_deleted_unreachable_types_filtered,
10959 num_changed_unreachable_types_filtered);
10960
10961 if (get_context()->do_log())
10962 {
10963 t.stop();
10964 std::cerr << "in apply_filters_and_compute_diff_stats:"
10965 << "unreachable types counted!:" << t << "\n";
10966 }
10967
10968 stat.num_added_unreachable_types(num_added_unreachable_types);
10969 stat.num_removed_unreachable_types(num_deleted_unreachable_types);
10970 stat.num_changed_unreachable_types(num_changed_unreachable_types);
10972 (num_added_unreachable_types_filtered);
10974 (num_deleted_unreachable_types_filtered);
10976 (num_changed_unreachable_types_filtered);
10977 }
10978}
10979
10980/// Emit the summary of the functions & variables that got
10981/// removed/changed/added.
10982///
10983/// TODO: This should be handled by the reporters, just like what is
10984/// done for reporter_base::diff_to_be_reported.
10985///
10986/// @param out the output stream to emit the stats to.
10987///
10988/// @param indent the indentation string to use in the summary.
10989void
10991 ostream& out,
10992 const string& indent)
10993{
10994 /// Report added/removed/changed functions.
10995 size_t net_num_leaf_changes =
10997 s.net_num_func_added() +
11000 s.net_num_vars_added() +
11007
11008 if (!sonames_equal_)
11009 out << indent << "ELF SONAME changed\n";
11010
11011 if (!architectures_equal_)
11012 out << indent << "ELF architecture changed\n";
11013
11014 diff_context_sptr ctxt = get_context();
11015
11016 if (ctxt->show_leaf_changes_only())
11017 {
11018 out << "Leaf changes summary: ";
11019 out << net_num_leaf_changes << " artifact";
11020 if (net_num_leaf_changes > 1)
11021 out << "s";
11022 out << " changed";
11023
11024 if (size_t num_filtered = s.num_leaf_changes_filtered_out())
11025 out << " (" << num_filtered << " filtered out)";
11026 out << "\n";
11027
11028 out << indent << "Changed leaf types summary: "
11031 out << " (" << s.num_leaf_type_changes_filtered_out()
11032 << " filtered out)";
11033 out << " leaf type";
11034 if (s.num_leaf_type_changes() > 1)
11035 out << "s";
11036 out << " changed\n";
11037
11038 // function changes summary
11039 out << indent << "Removed/Changed/Added functions summary: ";
11040 out << s.net_num_func_removed() << " Removed";
11042 out << " ("
11044 << " filtered out)";
11045 out << ", ";
11046
11047 out << s.net_num_leaf_func_changes() << " Changed";
11049 out << " ("
11051 << " filtered out)";
11052 out << ", ";
11053
11054 out << s.net_num_func_added()<< " Added ";
11055 if (s.net_num_func_added() <= 1)
11056 out << "function";
11057 else
11058 out << "functions";
11060 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11061 out << "\n";
11062
11063 // variables changes summary
11064 out << indent << "Removed/Changed/Added variables summary: ";
11065 out << s.net_num_vars_removed() << " Removed";
11067 out << " (" << s.num_removed_vars_filtered_out()
11068 << " filtered out)";
11069 out << ", ";
11070
11071 out << s.net_num_leaf_var_changes() << " Changed";
11073 out << " ("
11075 << " filtered out)";
11076 out << ", ";
11077
11078 out << s.net_num_vars_added() << " Added ";
11079 if (s.net_num_vars_added() <= 1)
11080 out << "variable";
11081 else
11082 out << "variables";
11084 out << " (" << s.num_added_vars_filtered_out()
11085 << " filtered out)";
11086 out << "\n";
11087 }
11088 else // if (ctxt->show_leaf_changes_only())
11089 {
11090 size_t total_nb_function_changes = s.num_func_removed()
11091 + s.num_func_changed() + s.num_func_added();
11092
11093 // function changes summary
11094 out << indent << "Functions changes summary: ";
11095 out << s.net_num_func_removed() << " Removed";
11097 out << " ("
11099 << " filtered out)";
11100 out << ", ";
11101
11102 out << s.net_num_func_changed() << " Changed";
11104 out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
11105 out << ", ";
11106
11107 out << s.net_num_func_added() << " Added";
11109 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
11110 if (total_nb_function_changes <= 1)
11111 out << " function";
11112 else
11113 out << " functions";
11114 out << "\n";
11115
11116 // variables changes summary
11117 size_t total_nb_variable_changes = s.num_vars_removed()
11118 + s.num_vars_changed() + s.num_vars_added();
11119
11120 out << indent << "Variables changes summary: ";
11121 out << s.net_num_vars_removed() << " Removed";
11123 out << " (" << s.num_removed_vars_filtered_out()
11124 << " filtered out)";
11125 out << ", ";
11126
11127 out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
11129 out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
11130 out << ", ";
11131
11132 out << s.net_num_vars_added() << " Added";
11134 out << " (" << s.num_added_vars_filtered_out()
11135 << " filtered out)";
11136 if (total_nb_variable_changes <= 1)
11137 out << " variable";
11138 else
11139 out << " variables";
11140 out << "\n";
11141 }
11142
11143 // Show statistics about types not reachable from global
11144 // functions/variables.
11145 if (ctxt->show_unreachable_types())
11146 {
11147 size_t total_nb_unreachable_type_changes =
11151
11152 // Show summary of unreachable types
11153 out << indent << "Unreachable types summary: "
11155 << " removed";
11158 << " filtered out)";
11159 out << ", ";
11160
11162 << " changed";
11165 << " filtered out)";
11166 out << ", ";
11167
11169 << " added";
11172 << " filtered out)";
11173 if (total_nb_unreachable_type_changes <= 1)
11174 out << " type";
11175 else
11176 out << " types";
11177 out << "\n";
11178 }
11179
11180 if (ctxt->show_symbols_unreferenced_by_debug_info()
11181 && (s.num_func_syms_removed()
11182 || s.num_func_syms_added()
11184 || s.num_var_syms_added()))
11185 {
11186 // function symbols changes summary.
11187
11188 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11189 && s.num_func_syms_removed() == 0
11190 && s.num_func_syms_added() != 0)
11191 // If the only unreferenced function symbol change is function
11192 // syms that got added, but we were forbidden to show function
11193 // syms being added, do nothing.
11194 ;
11195 else
11196 {
11197 out << indent
11198 << "Function symbols changes summary: "
11199 << s.net_num_removed_func_syms() << " Removed";
11201 out << " (" << s.num_removed_func_syms_filtered_out()
11202 << " filtered out)";
11203 out << ", ";
11204 out << s.net_num_added_func_syms() << " Added";
11206 out << " (" << s.num_added_func_syms_filtered_out()
11207 << " filtered out)";
11208 out << " function symbol";
11210 out << "s";
11211 out << " not referenced by debug info\n";
11212 }
11213
11214 // variable symbol changes summary.
11215
11216 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
11217 && s.num_var_syms_removed() == 0
11218 && s.num_var_syms_added() != 0)
11219 // If the only unreferenced variable symbol change is variable
11220 // syms that got added, but we were forbidden to show variable
11221 // syms being added, do nothing.
11222 ;
11223 else
11224 {
11225 out << indent
11226 << "Variable symbols changes summary: "
11227 << s.net_num_removed_var_syms() << " Removed";
11229 out << " (" << s.num_removed_var_syms_filtered_out()
11230 << " filtered out)";
11231 out << ", ";
11232 out << s.net_num_added_var_syms() << " Added";
11234 out << " (" << s.num_added_var_syms_filtered_out()
11235 << " filtered out)";
11236 out << " variable symbol";
11237 if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
11238 out << "s";
11239 out << " not referenced by debug info\n";
11240 }
11241 }
11242}
11243
11244/// Walk the changed functions and variables diff nodes to categorize
11245/// redundant nodes.
11246void
11248{
11250
11251 diff_context_sptr ctxt = get_context();
11252
11253 ctxt->forget_visited_diffs();
11254 for (function_decl_diff_sptrs_type::const_iterator i =
11255 changed_fns_.begin();
11256 i!= changed_fns_.end();
11257 ++i)
11258 {
11259 diff = *i;
11261 }
11262
11263 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11264 i!= sorted_changed_vars_.end();
11265 ++i)
11266 {
11267 diff_sptr diff = *i;
11269 }
11270
11271 for (diff_sptrs_type::const_iterator i =
11274 ++i)
11275 {
11276 diff_sptr diff = *i;
11278 }
11279}
11280
11281/// Walk the changed functions and variables diff nodes and clear the
11282/// redundancy categorization they might carry.
11283void
11285{
11287 for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
11288 i!= changed_fns_.end();
11289 ++i)
11290 {
11291 diff = *i;
11293 }
11294
11295 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11296 i!= sorted_changed_vars_.end();
11297 ++i)
11298 {
11299 diff = *i;
11301 }
11302}
11303
11304/// If the user asked to dump the diff tree node (for changed
11305/// variables and functions) on the error output stream, then just do
11306/// that.
11307///
11308/// This function is used for debugging purposes.
11309void
11311{
11312 diff_context_sptr ctxt = get_context();
11313
11314 if (!ctxt->dump_diff_tree()
11315 || ctxt->error_output_stream() == 0)
11316 return;
11317
11318 if (!changed_fns_.empty())
11319 {
11320 *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
11321 for (function_decl_diff_sptrs_type::const_iterator i =
11322 changed_fns_.begin();
11323 i != changed_fns_.end();
11324 ++i)
11325 {
11326 diff_sptr d = *i;
11327 print_diff_tree(d, *ctxt->error_output_stream());
11328 }
11329 }
11330
11331 if (!sorted_changed_vars_.empty())
11332 {
11333 *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
11334 for (var_diff_sptrs_type::const_iterator i =
11335 sorted_changed_vars_.begin();
11336 i != sorted_changed_vars_.end();
11337 ++i)
11338 {
11339 diff_sptr d = *i;
11340 print_diff_tree(d, *ctxt->error_output_stream());
11341 }
11342 }
11343
11344 if (!changed_unreachable_types_sorted().empty())
11345 {
11346 *ctxt->error_output_stream() << "\nchanged unreachable "
11347 "types diff tree: \n\n";
11348 for (vector<diff_sptr>::const_iterator i =
11351 ++i)
11352 {
11353 diff_sptr d = *i;
11354 print_diff_tree(d, *ctxt->error_output_stream());
11355 }
11356 }
11357}
11358
11359/// Populate the vector of children node of the @ref corpus_diff type.
11360///
11361/// The children node can then later be retrieved using
11362/// corpus_diff::children_node().
11363void
11365{
11366 for (function_decl_diff_sptrs_type::const_iterator i =
11367 changed_functions_sorted().begin();
11368 i != changed_functions_sorted().end();
11369 ++i)
11370 if (diff_sptr d = *i)
11372}
11373
11374/// Constructor for @ref corpus_diff.
11375///
11376/// @param first the first corpus of the diff.
11377///
11378/// @param second the second corpus of the diff.
11379///
11380/// @param ctxt the diff context to use. Note that this context
11381/// object must stay alive at least during the life time of the
11382/// current instance of @ref corpus_diff. Otherwise memory corruption
11383/// issues occur.
11385 corpus_sptr second,
11386 diff_context_sptr ctxt)
11387 : priv_(new priv(first, second, ctxt))
11388{}
11389
11390corpus_diff::~corpus_diff() = default;
11391
11392/// Finish building the current instance of @ref corpus_diff.
11393void
11395{
11396 if (priv_->finished_)
11397 return;
11399 priv_->finished_ = true;
11400}
11401
11402/// Test if logging was requested.
11403///
11404/// @return true iff logging was requested.
11405bool
11407{return context()->do_log();}
11408
11409/// Request logging, or not.
11410///
11411/// @param f true iff logging is requested.
11412void
11414{context()->do_log(f);}
11415
11416/// @return the first corpus of the diff.
11417corpus_sptr
11419{return priv_->first_;}
11420
11421/// @return the second corpus of the diff.
11422corpus_sptr
11424{return priv_->second_;}
11425
11426/// @return the children nodes of the current instance of corpus_diff.
11427const vector<diff*>&
11429{return priv_->children_;}
11430
11431/// Append a new child node to the vector of children nodes for the
11432/// current instance of @ref corpus_diff node.
11433///
11434/// Note that the vector of children nodes for the current instance of
11435/// @ref corpus_diff node must remain sorted, using
11436/// diff_less_than_functor.
11437///
11438/// @param d the new child node. Note that the life time of the
11439/// object held by @p d will thus equal the life time of the current
11440/// instance of @ref corpus_diff.
11441void
11443{
11444 ABG_ASSERT(d);
11445
11447 bool inserted = false;
11448 for (vector<diff*>::iterator i = priv_->children_.begin();
11449 i != priv_->children_.end();
11450 ++i)
11451 // Look for the point where to insert the diff child node.
11452 if (!is_less_than(d.get(), *i))
11453 {
11454 context()->keep_diff_alive(d);
11455 priv_->children_.insert(i, d.get());
11456 // As we have just inserted 'd' into the vector, the iterator
11457 // 'i' is invalidated. We must *NOT* use it anymore.
11458 inserted = true;
11459 break;
11460 }
11461
11462 if (!inserted)
11463 {
11464 context()->keep_diff_alive(d);
11465 // We didn't insert anything to the vector, presumably b/c it was
11466 // empty or had one element that was "less than" 'd'. We can thus
11467 // just append 'd' to the end of the vector.
11468 priv_->children_.push_back(d.get());
11469 }
11470}
11471
11472/// @return the bare edit script of the functions changed as recorded
11473/// by the diff.
11476{return priv_->fns_edit_script_;}
11477
11478/// @return the bare edit script of the variables changed as recorded
11479/// by the diff.
11482{return priv_->vars_edit_script_;}
11483
11484/// Test if the soname of the underlying corpus has changed.
11485///
11486/// @return true iff the soname has changed.
11487bool
11489{return !priv_->sonames_equal_;}
11490
11491/// Test if the architecture of the underlying corpus has changed.
11492///
11493/// @return true iff the architecture has changed.
11494bool
11496{return !priv_->architectures_equal_;}
11497
11498/// Getter for the deleted functions of the diff.
11499///
11500/// @return the the deleted functions of the diff.
11503{return priv_->deleted_fns_;}
11504
11505/// Getter for the added functions of the diff.
11506///
11507/// @return the added functions of the diff.
11510{return priv_->added_fns_;}
11511
11512/// Getter for the functions which signature didn't change, but which
11513/// do have some indirect changes in their parms.
11514///
11515/// @return a non-sorted map of functions which signature didn't
11516/// change, but which do have some indirect changes in their parms.
11517/// The key of the map is a unique identifier for the function; it's
11518/// usually made of the name and version of the underlying ELF symbol
11519/// of the function for corpora that were built from ELF files.
11522{return priv_->changed_fns_map_;}
11523
11524/// Getter for a sorted vector of functions which signature didn't
11525/// change, but which do have some indirect changes in their parms.
11526///
11527/// @return a sorted vector of functions which signature didn't
11528/// change, but which do have some indirect changes in their parms.
11531{return priv_->changed_fns_;}
11532
11533/// Getter for the variables that got deleted from the first subject
11534/// of the diff.
11535///
11536/// @return the map of deleted variable.
11537const string_var_ptr_map&
11539{return priv_->deleted_vars_;}
11540
11541/// Getter for the added variables of the diff.
11542///
11543/// @return the map of added variable.
11544const string_var_ptr_map&
11546{return priv_->added_vars_;}
11547
11548/// Getter for the non-sorted map of variables which signature didn't
11549/// change but which do have some indirect changes in some sub-types.
11550///
11551/// @return the non-sorted map of changed variables.
11554{return priv_->changed_vars_map_;}
11555
11556/// Getter for the sorted vector of variables which signature didn't
11557/// change but which do have some indirect changes in some sub-types.
11558///
11559/// @return a sorted vector of changed variables.
11562{return priv_->sorted_changed_vars_;}
11563
11564/// Getter for function symbols not referenced by any debug info and
11565/// that got deleted.
11566///
11567/// @return a map of elf function symbols not referenced by any debug
11568/// info and that got deleted.
11571{return priv_->deleted_unrefed_fn_syms_;}
11572
11573/// Getter for function symbols not referenced by any debug info and
11574/// that got added.
11575///
11576/// @return a map of elf function symbols not referenced by any debug
11577/// info and that got added.
11580{return priv_->added_unrefed_fn_syms_;}
11581
11582/// Getter for variable symbols not referenced by any debug info and
11583/// that got deleted.
11584///
11585/// @return a map of elf variable symbols not referenced by any debug
11586/// info and that got deleted.
11589{return priv_->deleted_unrefed_var_syms_;}
11590
11591/// Getter for variable symbols not referenced by any debug info and
11592/// that got added.
11593///
11594/// @return a map of elf variable symbols not referenced by any debug
11595/// info and that got added.
11598{return priv_->added_unrefed_var_syms_;}
11599
11600/// Getter for a map of deleted types that are not reachable from
11601/// global functions/variables.
11602///
11603/// @return a map that associates pretty representation of deleted
11604/// unreachable types and said types.
11607{return priv_->deleted_unreachable_types_;}
11608
11609/// Getter of a sorted vector of deleted types that are not reachable
11610/// from global functions/variables.
11611///
11612/// @return a sorted vector of deleted types that are not reachable
11613/// from global functions/variables. The types are lexicographically
11614/// sorted by considering their pretty representation.
11615const vector<type_base_sptr>&
11617{
11618 if (priv_->deleted_unreachable_types_sorted_.empty())
11619 if (!priv_->deleted_unreachable_types_.empty())
11620 sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
11621 priv_->deleted_unreachable_types_sorted_);
11622
11623 return priv_->deleted_unreachable_types_sorted_;
11624}
11625
11626/// Getter for a map of added types that are not reachable from global
11627/// functions/variables.
11628///
11629/// @return a map that associates pretty representation of added
11630/// unreachable types and said types.
11633{return priv_->added_unreachable_types_;}
11634
11635/// Getter of a sorted vector of added types that are not reachable
11636/// from global functions/variables.
11637///
11638/// @return a sorted vector of added types that are not reachable from
11639/// global functions/variables. The types are lexicographically
11640/// sorted by considering their pretty representation.
11641const vector<type_base_sptr>&
11643{
11644 if (priv_->added_unreachable_types_sorted_.empty())
11645 if (!priv_->added_unreachable_types_.empty())
11646 sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
11647 priv_->added_unreachable_types_sorted_);
11648
11649 return priv_->added_unreachable_types_sorted_;
11650}
11651
11652/// Getter for a map of changed types that are not reachable from
11653/// global functions/variables.
11654///
11655/// @return a map that associates pretty representation of changed
11656/// unreachable types and said types.
11659{return priv_->changed_unreachable_types_;}
11660
11661/// Getter of a sorted vector of changed types that are not reachable
11662/// from global functions/variables.
11663///
11664/// @return a sorted vector of changed types that are not reachable
11665/// from global functions/variables. The diffs are lexicographically
11666/// sorted by considering their pretty representation.
11667const vector<diff_sptr>&
11669{return priv_->changed_unreachable_types_sorted();}
11670
11671/// Getter of the diff context of this diff
11672///
11673/// @return the diff context for this diff.
11676{return priv_->get_context();}
11677
11678/// @return the pretty representation for the current instance of @ref
11679/// corpus_diff
11680const string&
11682{
11683 if (priv_->pretty_representation_.empty())
11684 {
11685 std::ostringstream o;
11686 o << "corpus_diff["
11687 << first_corpus()->get_path()
11688 << ", "
11689 << second_corpus()->get_path()
11690 << "]";
11691 priv_->pretty_representation_ = o.str();
11692 }
11693 return priv_->pretty_representation_;
11694}
11695/// Return true iff the current @ref corpus_diff node carries a
11696/// change.
11697///
11698/// @return true iff the current diff node carries a change.
11699bool
11701{
11702 return (soname_changed()
11704 || !(priv_->deleted_fns_.empty()
11705 && priv_->added_fns_.empty()
11706 && priv_->changed_fns_map_.empty()
11707 && priv_->deleted_vars_.empty()
11708 && priv_->added_vars_.empty()
11709 && priv_->changed_vars_map_.empty()
11710 && priv_->added_unrefed_fn_syms_.empty()
11711 && priv_->deleted_unrefed_fn_syms_.empty()
11712 && priv_->added_unrefed_var_syms_.empty()
11713 && priv_->deleted_unrefed_var_syms_.empty()
11714 && priv_->deleted_unreachable_types_.empty()
11715 && priv_->added_unreachable_types_.empty()
11716 && priv_->changed_unreachable_types_.empty()));
11717}
11718
11719/// Test if the current instance of @ref corpus_diff carries changes
11720/// that we are sure are incompatible. By incompatible change we mean
11721/// a change that "breaks" the ABI of the corpus we are looking at.
11722///
11723/// In concrete terms, this function considers the following changes
11724/// as being ABI incompatible for sure:
11725///
11726/// - a soname change
11727/// - if exported functions or variables got removed
11728///
11729/// Note that subtype changes *can* represent changes that break ABI
11730/// too. But they also can be changes that are OK, ABI-wise.
11731///
11732/// It's up to the user to provide suppression specifications to say
11733/// explicitely which subtype change is OK. The remaining sub-type
11734/// changes are then considered to be ABI incompatible. But to test
11735/// if such ABI incompatible subtype changes are present you need to
11736/// use the function @ref corpus_diff::has_net_subtype_changes()
11737///
11738/// @return true iff the current instance of @ref corpus_diff carries
11739/// changes that we are sure are ABI incompatible.
11740bool
11742{
11743 const diff_stats& stats = const_cast<corpus_diff*>(this)->
11745
11748 || stats.net_num_func_removed() != 0
11750 // If all reports about functions with sub-type changes
11751 // have been suppressed, then even those about functions
11752 // that are virtual don't matter anymore because the
11753 // user willingly requested to shut them down
11754 && stats.net_num_func_changed() != 0)
11755 || stats.net_num_vars_removed() != 0
11756 || stats.net_num_removed_func_syms() != 0
11757 || stats.net_num_removed_var_syms() != 0
11758 || stats.net_num_removed_unreachable_types() != 0);
11759
11760 // If stats.net_num_changed_unreachable_types() != 0 then walk the
11761 // corpus_diff::priv::changed_unreachable_types_, and see if there
11762 // is one that is harmful by bitwise and-ing their category with
11763 // abigail::comparison::get_default_harmful_categories_bitmap().
11766 {
11767 // The changed unreachable types can carry harmful changes.
11768 // Let's figure if they actually do.
11769
11770 diff_context_sptr ctxt = context();
11771 for (auto &entry : priv_->changed_unreachable_types())
11772 {
11773 diff_sptr dif = entry.second;
11774
11775 // Let's see if any of the categories of this diff node
11776 // belong to the "harmful" ones.
11777 if (dif->get_category() & get_default_harmful_categories_bitmap())
11778 {
11780 break;
11781 }
11782 }
11783 }
11784
11786}
11787
11788/// Test if the current instance of @ref corpus_diff carries subtype
11789/// changes whose reports are not suppressed by any suppression
11790/// specification. In effect, these are deemed incompatible ABI
11791/// changes.
11792///
11793/// @return true iff the the current instance of @ref corpus_diff
11794/// carries subtype changes that are deemed incompatible ABI changes.
11795bool
11797{
11798 const diff_stats& stats = const_cast<corpus_diff*>(this)->
11800
11801 return (stats.net_num_func_changed() != 0
11802 || stats.net_num_vars_changed() != 0
11803 || stats.net_num_removed_unreachable_types() != 0
11804 || stats.net_num_changed_unreachable_types() != 0);
11805}
11806
11807/// Test if the current instance of @ref corpus_diff carries changes
11808/// whose reports are not suppressed by any suppression specification.
11809/// In effect, these are deemed incompatible ABI changes.
11810///
11811/// @return true iff the the current instance of @ref corpus_diff
11812/// carries subtype changes that are deemed incompatible ABI changes.
11813bool
11815{return context()->get_reporter()->diff_has_net_changes(this);}
11816
11817/// Apply the different filters that are registered to be applied to
11818/// the diff tree; that includes the categorization filters. Also,
11819/// apply the suppression interpretation filters.
11820///
11821/// After the filters are applied, this function calculates some
11822/// statistics about the changes carried by the current instance of
11823/// @ref corpus_diff. These statistics are represented by an instance
11824/// of @ref corpus_diff::diff_stats.
11825///
11826/// This member function is called by the reporting function
11827/// corpus_diff::report().
11828///
11829/// Note that for a given instance of corpus_diff, this function
11830/// applies the filters and suppressions only the first time it is
11831/// invoked. Subsequent invocations just return the instance of
11832/// corpus_diff::diff_stats that was cached after the first
11833/// invocation.
11834///
11835/// @return a reference to the statistics about the changes carried by
11836/// the current instance of @ref corpus_diff.
11839{
11840 if (priv_->diff_stats_)
11841 return *priv_->diff_stats_;
11842
11844 if (do_log())
11845 {
11846 std::cerr << "Applying suppressions ...\n";
11847 t.start();
11848 }
11849
11850 apply_suppressions(this);
11851
11852 if (do_log())
11853 {
11854 t.stop();
11855 std::cerr << "suppressions applied!:" << t << "\n";
11856 }
11857
11858 priv_->diff_stats_.reset(new diff_stats(context()));
11859
11860 if (do_log())
11861 {
11862 std::cerr << "Marking leaf nodes ...\n";
11863 t.start();
11864 }
11865
11867
11868 if (do_log())
11869 {
11870 t.stop();
11871 std::cerr << "leaf nodes marked!:" << t << "\n";
11872 std::cerr << "Applying filters and computing diff stats ...\n";
11873 t.start();
11874 }
11875
11876 priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
11877
11878 if (do_log())
11879 {
11880 t.stop();
11881 std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
11882 }
11883
11884 return *priv_->diff_stats_;
11885}
11886
11887/// A visitor that marks leaf diff nodes by storing them in the
11888/// instance of @ref diff_maps returned by
11889/// corpus_diff::get_leaf_diffs() invoked on the current instance of
11890/// corpus_diff.
11891struct leaf_diff_node_marker_visitor : public diff_node_visitor
11892{
11893 /// This is called when the visitor visits a diff node.
11894 ///
11895 /// It basically tests if the diff node being visited is a leaf diff
11896 /// node - that is, it contains local changes. If it does, then the
11897 /// node is added to the set of maps that hold leaf diffs in the
11898 /// current corpus_diff.
11899 ///
11900 /// Note that only leaf nodes that are reachable from public
11901 /// interfaces (global functions or variables) are collected by this
11902 /// visitor.
11903 ///
11904 /// @param d the diff node being visited.
11905 virtual void
11906 visit_begin(diff *d)
11907 {
11908 if (d->has_local_changes()
11909 // A leaf basic (or class/union) type name change makes no
11910 // sense when showing just leaf changes. It only makes sense
11911 // when it can explain the details about a non-leaf change.
11912 // In other words, it doesn't make sense to say that an "int"
11913 // became "unsigned int". But it does make sense to say that
11914 // a typedef changed because its underlying type was 'int' and
11915 // is now an "unsigned int".
11917 // Similarly, a *local* change describing a type that changed
11918 // its nature doesn't make sense.
11919 && !is_distinct_diff(d)
11920 // Similarly, a pointer (or reference or array), a typedef or
11921 // qualified type change in itself doesn't make sense. It
11922 // would rather make sense to show that pointer change as part
11923 // of the variable change whose pointer type changed, for
11924 // instance.
11925 && !is_pointer_diff(d)
11926 && !is_reference_diff(d)
11928 && !is_typedef_diff(d)
11929 && !is_array_diff(d)
11930 // Similarly a parameter change in itself doesn't make sense.
11931 // It should have already been reported as part of the change
11932 // of the function it belongs to.
11933 && !is_fn_parm_diff(d)
11934 // An anonymous class or union diff doesn't make sense on its
11935 // own. It must have been described already by the diff of
11936 // the enclosing struct or union if 'd' is from an anonymous
11937 // data member, or from a typedef change if 'd' is from a
11938 // typedef change which underlying type is an anonymous
11939 // struct/union.
11941 // An anonymous subrange doesn't make sense either.
11943 // Don't show decl-only-ness changes either.
11945 // Sometime, we can encounter artifacts of bogus DWARF that
11946 // yield a diff node for a decl-only class (and empty class
11947 // with the is_declaration flag set) that carries a non-zero
11948 // size! And of course at some point that non-zero size
11949 // changes. We need to be able to detect that.
11951 {
11952 diff_context_sptr ctxt = d->context();
11953 const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
11954 ABG_ASSERT(corpus_diff_node);
11955
11956 if (diff *iface_diff = get_current_topmost_iface_diff())
11957 {
11958 type_or_decl_base_sptr iface = iface_diff->first_subject();
11959 // So, this diff node that is reachable from a global
11960 // function or variable carries a leaf change. Let's add
11961 // it to the set of of leaf diffs of corpus_diff_node.
11962 const_cast<corpus_diff*>(corpus_diff_node)->
11963 get_leaf_diffs().insert_diff_node(d, iface);
11964 }
11965 }
11966 }
11967}; // end struct leaf_diff_node_marker_visitor
11968
11969/// Walks the diff nodes associated to the current corpus diff and
11970/// mark those that carry local changes. They are said to be leaf
11971/// diff nodes.
11972///
11973/// The marked nodes are available from the
11974/// corpus_diff::get_leaf_diffs() function.
11975void
11977{
11978 if (!has_changes())
11979 return;
11980
11981 if (!context()->show_leaf_changes_only())
11982 return;
11983
11984 leaf_diff_node_marker_visitor v;
11985 context()->forget_visited_diffs();
11986 bool s = context()->visiting_a_node_twice_is_forbidden();
11987 context()->forbid_visiting_a_node_twice(true);
11988 if (context()->show_impacted_interfaces())
11989 context()->forbid_visiting_a_node_twice_per_interface(true);
11990 traverse(v);
11991 context()->forbid_visiting_a_node_twice(s);
11992 context()->forbid_visiting_a_node_twice_per_interface(false);
11993}
11994
11995/// Get the set of maps that contain leaf nodes. A leaf node being a
11996/// node with a local change.
11997///
11998/// @return the set of maps that contain leaf nodes. A leaf node
11999/// being a node with a local change.
12000diff_maps&
12002{return priv_->leaf_diffs_;}
12003
12004/// Get the set of maps that contain leaf nodes. A leaf node being a
12005/// node with a local change.
12006///
12007/// @return the set of maps that contain leaf nodes. A leaf node
12008/// being a node with a local change.
12009const diff_maps&
12011{return priv_->leaf_diffs_;}
12012
12013/// Report the diff in a serialized form.
12014///
12015/// @param out the stream to serialize the diff to.
12016///
12017/// @param indent the prefix to use for the indentation of this
12018/// serialization.
12019void
12020corpus_diff::report(ostream& out, const string& indent) const
12021{
12022 context()->get_reporter()->report(*this, out, indent);
12023}
12024
12025/// Traverse the diff sub-tree under the current instance corpus_diff.
12026///
12027/// @param v the visitor to invoke on each diff node of the sub-tree.
12028///
12029/// @return true if the traversing has to keep going on, false otherwise.
12030bool
12032{
12034
12035 v.visit_begin(this);
12036
12037 if (!v.visit(this, true))
12038 {
12039 v.visit_end(this);
12040 return false;
12041 }
12042
12043 for (function_decl_diff_sptrs_type::const_iterator i =
12044 changed_functions_sorted().begin();
12045 i != changed_functions_sorted().end();
12046 ++i)
12047 {
12048 if (diff_sptr d = *i)
12049 {
12050 const diff_context_sptr &ctxt = context();
12051 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12052 ctxt->forget_visited_diffs();
12053
12055
12056 if (!d->traverse(v))
12057 {
12058 v.visit_end(this);
12060 return false;
12061 }
12062 }
12063 }
12064
12065 for (var_diff_sptrs_type::const_iterator i =
12066 changed_variables_sorted().begin();
12067 i != changed_variables_sorted().end();
12068 ++i)
12069 {
12070 if (diff_sptr d = *i)
12071 {
12072 const diff_context_sptr &ctxt = context();
12073 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12074 ctxt->forget_visited_diffs();
12075
12077
12078 if (!d->traverse(v))
12079 {
12080 v.visit_end(this);
12082 return false;
12083 }
12084 }
12085 }
12086
12088
12089 // Traverse the changed unreachable type diffs. These diffs are on
12090 // types that are not reachable from global functions or variables.
12091 for (vector<diff_sptr>::const_iterator i =
12094 ++i)
12095 {
12096 if (diff_sptr d = *i)
12097 {
12098 const diff_context_sptr &ctxt = context();
12099 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
12100 ctxt->forget_visited_diffs();
12101
12102 if (!d->traverse(v))
12103 {
12104 v.visit_end(this);
12105 return false;
12106 }
12107 }
12108 }
12109
12110 v.visit_end(this);
12111 return true;
12112}
12113
12114/// Compute the diff between two instances of @ref corpus.
12115///
12116/// Note that the two corpora must have been created in the same @ref
12117/// environment, otherwise, this function aborts.
12118///
12119/// @param f the first @ref corpus to consider for the diff.
12120///
12121/// @param s the second @ref corpus to consider for the diff.
12122///
12123/// @param ctxt the diff context to use.
12124///
12125/// @return the resulting diff between the two @ref corpus.
12127compute_diff(const corpus_sptr f,
12128 const corpus_sptr s,
12129 diff_context_sptr ctxt)
12130{
12131 typedef corpus::functions::const_iterator fns_it_type;
12132 typedef corpus::variables::const_iterator vars_it_type;
12133 typedef elf_symbols::const_iterator symbols_it_type;
12134 typedef diff_utils::deep_ptr_eq_functor eq_type;
12135 typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
12136
12137 ABG_ASSERT(f && s);
12138
12139 if (!ctxt)
12140 ctxt.reset(new diff_context);
12141
12142 corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
12143
12144 ctxt->set_corpus_diff(r);
12145
12146 if(ctxt->show_soname_change())
12147 r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
12148 else
12149 r->priv_->sonames_equal_ = true;
12150
12151 r->priv_->architectures_equal_ =
12152 f->get_architecture_name() == s->get_architecture_name();
12153
12154 // Compute the diff of publicly defined and exported functions
12155 diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
12156 f->get_functions().end(),
12157 s->get_functions().begin(),
12158 s->get_functions().end(),
12159 r->priv_->fns_edit_script_);
12160
12161 // Compute the diff of publicly defined and exported variables.
12163 (f->get_variables().begin(), f->get_variables().end(),
12164 s->get_variables().begin(), s->get_variables().end(),
12165 r->priv_->vars_edit_script_);
12166
12167 // Compute the diff of function elf symbols not referenced by debug
12168 // info.
12170 (f->get_unreferenced_function_symbols().begin(),
12171 f->get_unreferenced_function_symbols().end(),
12172 s->get_unreferenced_function_symbols().begin(),
12173 s->get_unreferenced_function_symbols().end(),
12174 r->priv_->unrefed_fn_syms_edit_script_);
12175
12176 // Compute the diff of variable elf symbols not referenced by debug
12177 // info.
12179 (f->get_unreferenced_variable_symbols().begin(),
12180 f->get_unreferenced_variable_symbols().end(),
12181 s->get_unreferenced_variable_symbols().begin(),
12182 s->get_unreferenced_variable_symbols().end(),
12183 r->priv_->unrefed_var_syms_edit_script_);
12184
12185 if (ctxt->show_unreachable_types())
12186 // Compute the diff of types not reachable from public functions
12187 // or global variables that are exported.
12189 (f->get_types_not_reachable_from_public_interfaces().begin(),
12190 f->get_types_not_reachable_from_public_interfaces().end(),
12191 s->get_types_not_reachable_from_public_interfaces().begin(),
12192 s->get_types_not_reachable_from_public_interfaces().end(),
12193 r->priv_->unreachable_types_edit_script_);
12194
12195 r->priv_->ensure_lookup_tables_populated();
12196
12197 return r;
12198}
12199
12200// </corpus stuff>
12201
12202/// Compute the diff between two instances of @ref corpus_group.
12203///
12204/// Note that the two corpus_diff must have been created in the same
12205/// @ref environment, otherwise, this function aborts.
12206///
12207/// @param f the first @ref corpus_group to consider for the diff.
12208///
12209/// @param s the second @ref corpus_group to consider for the diff.
12210///
12211/// @param ctxt the diff context to use.
12212///
12213/// @return the resulting diff between the two @ref corpus_group.
12215compute_diff(const corpus_group_sptr& f,
12216 const corpus_group_sptr& s,
12217 diff_context_sptr ctxt)
12218{
12219
12220 corpus_sptr c1 = f;
12221 corpus_sptr c2 = s;
12222
12223 return compute_diff(c1, c2, ctxt);
12224}
12225
12226// <corpus_group stuff>
12227
12228// </corpus_group stuff>
12229// <diff_node_visitor stuff>
12230
12231/// The private data of the @diff_node_visitor type.
12232struct diff_node_visitor::priv
12233{
12234 diff* topmost_interface_diff;
12235 visiting_kind kind;
12236
12237 priv()
12238 : topmost_interface_diff(),
12239 kind()
12240 {}
12241
12242 priv(visiting_kind k)
12243 : topmost_interface_diff(),
12244 kind(k)
12245 {}
12246}; // end struct diff_node_visitor
12247
12248/// Default constructor of the @ref diff_node_visitor type.
12250 : priv_(new priv)
12251{}
12252
12253diff_node_visitor::~diff_node_visitor() = default;
12254
12255/// Constructor of the @ref diff_node_visitor type.
12256///
12257/// @param k how the visiting has to be performed.
12259 : priv_(new priv(k))
12260{}
12261
12262/// Getter for the visiting policy of the traversing code while
12263/// invoking this visitor.
12264///
12265/// @return the visiting policy used by the traversing code when
12266/// invoking this visitor.
12269{return priv_->kind;}
12270
12271/// Setter for the visiting policy of the traversing code while
12272/// invoking this visitor.
12273///
12274/// @param v a bit map representing the new visiting policy used by
12275/// the traversing code when invoking this visitor.
12276void
12279
12280/// Setter for the visiting policy of the traversing code while
12281/// invoking this visitor. This one makes a logical or between the
12282/// current policy and the bitmap given in argument and assigns the
12283/// current policy to the result.
12284///
12285/// @param v a bitmap representing the visiting policy to or with
12286/// the current policy.
12287void
12289{priv_->kind = priv_->kind | v;}
12290
12291/// Setter of the diff current topmost interface which is impacted by
12292/// the current diff node being visited.
12293///
12294/// @param d the current topmost interface diff impacted.
12295void
12297{priv_->topmost_interface_diff = d;}
12298
12299/// Getter of the diff current topmost interface which is impacted by
12300/// the current diff node being visited.
12301///
12302/// @return the current topmost interface diff impacted.
12303diff*
12305{return priv_->topmost_interface_diff;}
12306
12307/// This is called by the traversing code on a @ref diff node just
12308/// before visiting it. That is, before visiting it and its children
12309/// node.
12310///
12311/// @param d the diff node to visit.
12312void
12315
12316/// This is called by the traversing code on a @ref diff node just
12317/// after visiting it. That is after visiting it and its children
12318/// nodes.
12319///
12320/// @param d the diff node that got visited.
12321void
12324
12325/// This is called by the traversing code on a @ref corpus_diff node
12326/// just before visiting it. That is, before visiting it and its
12327/// children node.
12328///
12329/// @param p the corpus_diff node to visit.
12330///
12331void
12334
12335/// This is called by the traversing code on a @ref corpus_diff node
12336/// just after visiting it. That is after visiting it and its children
12337/// nodes.
12338///
12339/// @param d the diff node that got visited.
12340void
12343
12344/// Default visitor implementation
12345///
12346/// @return true
12347bool
12349{return true;}
12350
12351/// Default visitor implementation.
12352///
12353/// @return true
12354bool
12356{
12357 diff* d = dif;
12358 visit(d, pre);
12359
12360 return true;
12361}
12362
12363/// Default visitor implementation.
12364///
12365/// @return true
12366bool
12368{
12369 diff* d = dif;
12370 visit(d, pre);
12371
12372 return true;
12373}
12374
12375/// Default visitor implementation.
12376///
12377/// @return true
12378bool
12380{
12381 diff* d = dif;
12382 visit(d, pre);
12383
12384 return true;
12385}
12386
12387/// Default visitor implementation.
12388///
12389/// @return true
12390bool
12392{
12393 diff* d = dif;
12394 visit(d, pre);
12395
12396 return true;
12397}
12398
12399/// Default visitor implementation.
12400///
12401/// @return true
12402bool
12404{
12405 diff* d = dif;
12406 visit(d, pre);
12407
12408 return true;
12409}
12410
12411/// Default visitor implementation.
12412///
12413/// @return true
12414bool
12416{
12417 diff* d = dif;
12418 visit(d, pre);
12419
12420 return true;
12421}
12422
12423/// Default visitor implementation.
12424///
12425/// @return true
12426bool
12428{
12429 diff* d = dif;
12430 visit(d, pre);
12431
12432 return true;
12433}
12434
12435/// Default visitor implementation.
12436///
12437/// @return true
12438bool
12440{
12441 diff* d = dif;
12442 visit(d, pre);
12443
12444 return true;
12445}
12446
12447/// Default visitor implementation.
12448///
12449/// @return true
12450bool
12452{
12453 diff* d = dif;
12454 visit(d, pre);
12455
12456 return true;
12457}
12458
12459/// Default visitor implementation.
12460///
12461/// @return true
12462bool
12464{
12465 diff* d = dif;
12466 visit(d, pre);
12467
12468 return true;
12469}
12470
12471/// Default visitor implementation.
12472///
12473/// @return true
12474bool
12476{
12477 diff* d = dif;
12478 visit(d, pre);
12479
12480 return true;
12481}
12482
12483/// Default visitor implementation.
12484///
12485/// @return true
12486bool
12488{
12489 diff* d = dif;
12490 visit(d, pre);
12491
12492 return true;
12493}
12494
12495/// Default visitor implementation.
12496///
12497/// @return true
12498bool
12500{
12501 diff* d = dif;
12502 visit(d, pre);
12503
12504 return true;
12505}
12506
12507/// Default visitor implementation.
12508///
12509/// @return true
12510bool
12512{return true;}
12513
12514// </diff_node_visitor stuff>
12515
12516// <redundant diff node marking>
12517
12518// </redundant diff node marking>
12519
12520// <diff tree category propagation>
12521
12522/// A visitor to propagate the category of a node up to its parent
12523/// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
12524/// SUPPRESSED_CATEGORY because those are propagated using other
12525/// specific visitors.
12526struct category_propagation_visitor : public diff_node_visitor
12527{
12528 virtual void
12529 visit_end(diff* d)
12530 {
12531 // Has this diff node 'd' been already visited ?
12532 bool already_visited = d->context()->diff_has_been_visited(d);
12533
12534 // The canonical diff node of the class of equivalence of the diff
12535 // node 'd'.
12536 diff* canonical = d->get_canonical_diff();
12537
12538 // If this class of equivalence of diff node is being visited for
12539 // the first time, then update its canonical node's category too.
12540 bool update_canonical = !already_visited && canonical;
12541
12542 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12543 i != d->children_nodes().end();
12544 ++i)
12545 {
12546 // If we are visiting the class of equivalence of 'd' for the
12547 // first time, then let's look at the children of 'd' and
12548 // propagate their categories to 'd'.
12549 //
12550 // If the class of equivalence of 'd' has already been
12551 // visited, then let's look at the canonical diff nodes of the
12552 // children of 'd' and propagate their categories to 'd'.
12553 diff* diff = already_visited
12554 ? (*i)->get_canonical_diff()
12555 : *i;
12556
12558
12560 // Do not propagate redundant and suppressed categories. Those
12561 // are propagated in a specific pass elsewhere.
12562 c &= ~(REDUNDANT_CATEGORY
12568 // Also, if a (class) type has got a harmful name change, do not
12569 // propagate harmless name changes coming from its sub-types
12570 // (i.e, data members) to the class itself.
12572 c &= ~HARMLESS_DECL_NAME_CHANGE_CATEGORY;
12573
12574 d->add_to_category(c);
12575 if (!already_visited && canonical)
12576 if (update_canonical)
12577 canonical->add_to_category(c);
12578 }
12579
12582 {
12583 // The current diff node has either:
12584 //
12585 // 1/ a harmless "void pointer to pointer" change
12586 //
12587 // or:
12588 //
12589 // 2/ a harmless "enum to int" change.
12590 //
12591 // The change 1/ was most likely flagged locally as a
12592 // non-compatible distinct change, aka, a non-compatible
12593 // change between two types of different kinds. At a higher
12594 // level however, as we see that it's just a void pointer to
12595 // pointer change, we should unset the
12596 // NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY categorization.
12597 //
12598 // The change 2/ was most likely flagged locally (in the
12599 // children nodes of the current diff node) as a
12600 // non-compatible name change. At a higher level however, as
12601 // we see that it's just a harmless "enum to int" change,
12602 // let's unset the NON_COMPATIBLE_NAME_CHANGE_CATEGORY
12603 // categorization as well.
12604 diff_category c = d->get_category();
12605 c &= (~NON_COMPATIBLE_NAME_CHANGE_CATEGORY
12606 & ~NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY);
12607 d->set_category(c);
12608 }
12609
12611 {
12612 diff_category c = d->get_category();
12613 c &= ~NON_COMPATIBLE_NAME_CHANGE_CATEGORY;
12614 d->set_category(c);
12615 }
12616 }
12617};// end struct category_propagation_visitor
12618
12619/// Visit all the nodes of a given sub-tree. For each node that has a
12620/// particular category set, propagate that category set up to its
12621/// parent nodes.
12622///
12623/// @param diff_tree the diff sub-tree to walk for categorization
12624/// purpose;
12625void
12627{
12628 category_propagation_visitor v;
12629 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12630 diff_tree->context()->forbid_visiting_a_node_twice(true);
12631 diff_tree->context()->forget_visited_diffs();
12632 diff_tree->traverse(v);
12633 diff_tree->context()->forbid_visiting_a_node_twice(s);
12634}
12635
12636/// Visit all the nodes of a given sub-tree. For each node that has a
12637/// particular category set, propagate that category set up to its
12638/// parent nodes.
12639///
12640/// @param diff_tree the diff sub-tree to walk for categorization
12641/// purpose;
12642void
12644{propagate_categories(diff_tree.get());}
12645
12646/// Visit all the nodes of a given corpus tree. For each node that
12647/// has a particular category set, propagate that category set up to
12648/// its parent nodes.
12649///
12650/// @param diff_tree the corpus_diff tree to walk for categorization
12651/// purpose;
12652void
12654{
12655 category_propagation_visitor v;
12656 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12657 diff_tree->context()->forbid_visiting_a_node_twice(false);
12658 diff_tree->traverse(v);
12659 diff_tree->context()->forbid_visiting_a_node_twice(s);
12660}
12661
12662/// Visit all the nodes of a given corpus tree. For each node that
12663/// has a particular category set, propagate that category set up to
12664/// its parent nodes.
12665///
12666/// @param diff_tree the corpus_diff tree to walk for categorization
12667/// purpose;
12668void
12671
12672/// A tree node visitor that knows how to categorizes a given diff
12673/// node in the SUPPRESSED_CATEGORY category and how to propagate that
12674/// categorization.
12675struct suppression_categorization_visitor : public diff_node_visitor
12676{
12677
12678 /// Before visiting the children of the diff node, check if the node
12679 /// is suppressed by a suppression specification. If it is, mark
12680 /// the node as belonging to the SUPPRESSED_CATEGORY category.
12681 ///
12682 /// @param p the diff node to visit.
12683 virtual void
12684 visit_begin(diff* d)
12685 {
12686 bool is_private_type = false;
12687 if (d->is_suppressed(is_private_type))
12688 {
12689 diff_category c = is_private_type
12693
12694 // If a node was suppressed, all the other nodes of its class
12695 // of equivalence are suppressed too.
12696 diff *canonical_diff = d->get_canonical_diff();
12697 if (canonical_diff != d)
12698 canonical_diff->add_to_category(c);
12699 }
12701 {
12702 // This diff node is specifically allowed by a
12703 // negated_suppression, then mark it as being in the
12704 // HAS_ALLOWED_CHANGE_CATEGORY.
12705 diff_category c = HAS_ALLOWED_CHANGE_CATEGORY;
12707 diff *canonical_diff = d->get_canonical_diff();
12708 canonical_diff->add_to_category(c);
12709
12710 // Note that some complementary code later down below does
12711 // categorize the descendants and parents nodes of this node
12712 // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
12713 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
12714 }
12715
12716 // If a parent node has been allowed by a negated suppression
12717 // specification, then categorize the current node as
12718 // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
12719 if (d->parent_node())
12720 {
12721 diff_category c = d->parent_node()->get_local_category();
12725 else
12726 {
12727 c = d->parent_node()->get_category();
12731 }
12732 }
12733
12734 }
12735
12736 /// After visiting the children nodes of a given diff node,
12737 /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
12738 /// diff node, if need be.
12739 ///
12740 /// That is, if all children nodes carry a suppressed change the
12741 /// current node should be marked as suppressed as well.
12742 ///
12743 /// In practice, this might be too strong of a condition. If the
12744 /// current node carries a local change (i.e, a change not carried
12745 /// by any of its children node) and if that change is not
12746 /// suppressed, then the current node should *NOT* be suppressed.
12747 ///
12748 /// But right now, the IR doesn't let us know about local vs
12749 /// children-carried changes. So we cannot be that precise yet.
12750 virtual void
12751 visit_end(diff* d)
12752 {
12753 bool has_non_suppressed_child = false;
12754 bool has_non_empty_child = false;
12755 bool has_suppressed_child = false;
12756 bool has_non_private_child = false;
12757 bool has_private_child = false;
12758 bool has_descendant_with_allowed_change = false;
12759
12760 if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
12761 // (or the PRIVATE_TYPE_CATEGORY for the same matter)
12762 // category from its children is a node which:
12763 //
12764 // 1/ hasn't been suppressed already
12765 //
12766 // 2/ and has no local change (unless it's a pointer,
12767 // reference or qualified diff node).
12768 //
12769 // Note that qualified type and typedef diff nodes are a bit
12770 // special. The local changes of the underlying type are
12771 // considered local for the qualified/typedef type, just like
12772 // for pointer/reference types. But then the qualified or
12773 // typedef type itself can have local changes of its own, and
12774 // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
12775 // So a qualified type which have local changes that are
12776 // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
12777 // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
12778 // or SUPPRESSED_CATEGORY can see these categories be
12779 // propagated.
12780 //
12781 // Note that all pointer/reference diff node changes are
12782 // potentially considered local, i.e, local changes of the
12783 // pointed-to-type are considered local to the pointer itself.
12784 //
12785 // Similarly, changes local to the type of function parameters,
12786 // variables (and data members) and classes (that are not of
12787 // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
12788 // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
12789 // those kinds of diff node.
12790 !(d->get_category() & SUPPRESSED_CATEGORY)
12791 && (!d->has_local_changes()
12792 || is_pointer_diff(d)
12793 || is_reference_diff(d)
12795 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12796 || (is_typedef_diff(d)
12797 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12799 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12800 || (is_fn_parm_diff(d)
12801 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12803 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12804 || (is_var_diff(d)
12805 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12806 || (is_class_diff(d)
12807 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
12808 {
12809 // Note that we handle private diff nodes differently from
12810 // generally suppressed diff nodes. E.g, it's not because a
12811 // type is private (and suppressed because of that; i.e, in
12812 // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
12813 // type should also be private and so suppressed. Private
12814 // diff nodes thus have different propagation rules than
12815 // generally suppressed rules.
12816 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12817 i != d->children_nodes().end();
12818 ++i)
12819 {
12820 diff* child = *i;
12821 if (child->has_changes())
12822 {
12823 has_non_empty_child = true;
12824 if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
12825 has_suppressed_child = true;
12826 else if (child->get_class_of_equiv_category()
12828 // Propagation of the PRIVATE_TYPE_CATEGORY is going
12829 // to be handled later below.
12830 ;
12831 else
12832 has_non_suppressed_child = true;
12833
12834 if (child->get_class_of_equiv_category()
12836 has_private_child = true;
12837 else if (child->get_class_of_equiv_category()
12839 // Propagation of the SUPPRESSED_CATEGORY has been
12840 // handled above already.
12841 ;
12842 else
12843 has_non_private_child = true;
12844 }
12845 }
12846
12847 if (has_non_empty_child
12848 && has_suppressed_child
12849 && !has_non_suppressed_child)
12850 {
12851 d->add_to_category(SUPPRESSED_CATEGORY);
12852 // If a node was suppressed, all the other nodes of its class
12853 // of equivalence are suppressed too.
12854 diff *canonical_diff = d->get_canonical_diff();
12855 if (canonical_diff != d)
12856 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12857 }
12858
12859 // Note that the private-ness of a an underlying type won't be
12860 // propagated to its parent typedef, by virtue of the big "if"
12861 // clause at the beginning of this function. So we don't have
12862 // to handle that case here. So the idiom of defining
12863 // typedefs of private (opaque) types will be respected;
12864 // meaning that changes to opaque underlying type will be
12865 // flagged as private and the typedef will be flagged private
12866 // as well, unless the typedef itself has local non-type
12867 // changes. In the later case, changes to the typedef will be
12868 // emitted because the typedef won't inherit the privateness
12869 // of its underlying type. So in practise, the typedef
12870 // remains public for the purpose of change reporting.
12871 if (has_non_empty_child
12872 && has_private_child
12873 && !has_non_private_child)
12874 {
12875 d->add_to_category(PRIVATE_TYPE_CATEGORY);
12876 // If a node was suppressed, all the other nodes of its class
12877 // of equivalence are suppressed too.
12878 diff *canonical_diff = d->get_canonical_diff();
12879 if (canonical_diff != d)
12880 canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
12881 }
12882
12883 // If the underlying type of a typedef is private and carries
12884 // changes (that are implicitely suppressed because it's
12885 // private) then the typedef must be suppressed too, so that
12886 // those changes to the underlying type are not seen.
12887 if (is_typedef_diff(d)
12888 && !d->has_local_changes()
12889 && has_private_child
12890 && has_non_empty_child)
12891 {
12892 d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
12893 // If a node was suppressed, all the other nodes of its class
12894 // of equivalence are suppressed too.
12895 diff *canonical_diff = d->get_canonical_diff();
12896 if (canonical_diff != d)
12897 canonical_diff->add_to_category
12899 }
12900
12901 if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
12902 if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
12903 {
12904 // d is a function diff that carries a local *type*
12905 // change (that means it's a change to the function
12906 // type). Let's see if the child function type diff
12907 // node is suppressed. That would mean that we are
12908 // instructed to show details of a diff that is deemed
12909 // suppressed; this means the suppression conflicts with
12910 // a local type change. In that case, let's follow what
12911 // the user asked and suppress the function altogether,
12912 if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
12913 if (fn_type_diff->is_suppressed())
12914 {
12915 d->add_to_category(SUPPRESSED_CATEGORY);
12916 // If a node was suppressed, all the other nodes
12917 // of its class of equivalence are suppressed too.
12918 diff *canonical_diff = d->get_canonical_diff();
12919 if (canonical_diff != d)
12920 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12921 }
12922 }
12923 }
12924
12925 // If any descendant node was selected by a negated suppression
12926 // specification then categorize the current one as
12927 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
12928 for (auto child_node : d->children_nodes())
12929 {
12930 diff *canonical_diff = child_node->get_canonical_diff();
12931 diff_category c = canonical_diff->get_category();
12934 has_descendant_with_allowed_change = true;
12935 }
12936 if (has_descendant_with_allowed_change)
12937 {
12939 d->add_to_category(c);
12940 d->get_canonical_diff()->add_to_category(c);
12941 }
12942 }
12943}; //end struct suppression_categorization_visitor
12944
12945/// Walk a given diff-sub tree and appply the suppressions carried by
12946/// the context. If the suppression applies to a given node than
12947/// categorize the node into the SUPPRESSED_CATEGORY category and
12948/// propagate that categorization.
12949///
12950/// @param diff_tree the diff-sub tree to apply the suppressions to.
12951void
12953{
12954 if (diff_tree && !diff_tree->context()->suppressions().empty())
12955 {
12956 // Apply suppressions to functions and variables that have
12957 // changed sub-types.
12958 suppression_categorization_visitor v;
12959 diff_tree->context()->forget_visited_diffs();
12960 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12961 diff_tree->context()->forbid_visiting_a_node_twice(true);
12962 diff_tree->traverse(v);
12963 diff_tree->context()->forbid_visiting_a_node_twice(s);
12964 }
12965}
12966
12967/// Walk a given diff-sub tree and appply the suppressions carried by
12968/// the context. If the suppression applies to a given node than
12969/// categorize the node into the SUPPRESSED_CATEGORY category and
12970/// propagate that categorization.
12971///
12972/// @param diff_tree the diff-sub tree to apply the suppressions to.
12973void
12975{apply_suppressions(diff_tree.get());}
12976
12977/// Walk a @ref corpus_diff tree and appply the suppressions carried
12978/// by the context. If the suppression applies to a given node then
12979/// categorize the node into the SUPPRESSED_CATEGORY category and
12980/// propagate that categorization.
12981///
12982/// @param diff_tree the diff tree to apply the suppressions to.
12983void
12985{
12986 if (diff_tree && !diff_tree->context()->suppressions().empty())
12987 {
12988 // First, visit the children trees of changed constructs:
12989 // changed functions, variables, as well as sub-types of these,
12990 // and apply suppression specifications to these ...
12991 suppression_categorization_visitor v;
12992 diff_tree->context()->forget_visited_diffs();
12993 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12994 diff_tree->context()->forbid_visiting_a_node_twice(true);
12995 const_cast<corpus_diff*>(diff_tree)->traverse(v);
12996 diff_tree->context()->forbid_visiting_a_node_twice(s);
12997
12998 // ... then also visit the set of added and removed functions,
12999 // variables, symbols, and types not reachable from global
13000 // functions and variables.
13001 diff_tree->priv_->
13002 apply_supprs_to_added_removed_fns_vars_unreachable_types();
13003 }
13004}
13005
13006/// Walk a diff tree and appply the suppressions carried by the
13007/// context. If the suppression applies to a given node than
13008/// categorize the node into the SUPPRESSED_CATEGORY category and
13009/// propagate that categorization.
13010///
13011/// @param diff_tree the diff tree to apply the suppressions to.
13012void
13014{apply_suppressions(diff_tree.get());}
13015
13016// </diff tree category propagation>
13017
13018// <diff tree printing stuff>
13019
13020/// A visitor to print (to an output stream) a pretty representation
13021/// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
13022struct diff_node_printer : public diff_node_visitor
13023{
13024 ostream& out_;
13025 unsigned level_;
13026
13027 /// Emit a certain number of spaces to the output stream associated
13028 /// to this diff_node_printer.
13029 ///
13030 /// @param level half of the numver of spaces to emit.
13031 void
13032 do_indent(unsigned level)
13033 {
13034 for (unsigned i = 0; i < level; ++i)
13035 out_ << " ";
13036 }
13037
13038 diff_node_printer(ostream& out)
13040 out_(out),
13041 level_(0)
13042 {}
13043
13044 virtual void
13045 visit_begin(diff*)
13046 {
13047 ++level_;
13048 }
13049
13050 virtual void
13051 visit_end(diff*)
13052 {
13053 --level_;
13054 }
13055
13056 virtual void
13057 visit_begin(corpus_diff*)
13058 {
13059 ++level_;
13060 }
13061
13062 virtual void
13063 visit_end(corpus_diff*)
13064 {
13065 --level_;
13066 }
13067
13068 virtual bool
13069 visit(diff* d, bool pre)
13070 {
13071 if (!pre)
13072 // We are post-visiting the diff node D. Which means, we have
13073 // printed a pretty representation for it already. So do
13074 // nothing now.
13075 return true;
13076
13077 do_indent(level_);
13078 out_ << d->get_pretty_representation();
13079 out_ << "\n";
13080 do_indent(level_);
13081 out_ << "{\n";
13082 do_indent(level_ + 1);
13083 out_ << "category: "<< d->get_category() << "\n";
13084 do_indent(level_ + 1);
13085 out_ << "@: " << std::hex << d << std::dec << "\n";
13086 do_indent(level_ + 1);
13087 out_ << "@-canonical: " << std::hex
13088 << d->get_canonical_diff()
13089 << std::dec << "\n";
13090 do_indent(level_);
13091 out_ << "}\n";
13092
13093 return true;
13094 }
13095
13096 virtual bool
13097 visit(corpus_diff* d, bool pre)
13098 {
13099 if (!pre)
13100 // We are post-visiting the diff node D. Which means, we have
13101 // printed a pretty representation for it already. So do
13102 // nothing now.
13103 return true;
13104
13105 // indent
13106 for (unsigned i = 0; i < level_; ++i)
13107 out_ << ' ';
13108 out_ << d->get_pretty_representation();
13109 out_ << '\n';
13110 return true;
13111 }
13112}; // end struct diff_printer_visitor
13113
13114// </ diff tree printing stuff>
13115
13116/// Emit a textual representation of a @ref diff sub-tree to an
13117/// output stream.
13118///
13119/// @param diff_tree the sub-tree to emit the textual representation
13120/// for.
13121///
13122/// @param out the output stream to emit the textual representation
13123/// for @p diff_tree to.
13124void
13125print_diff_tree(diff* diff_tree, ostream& out)
13126{
13127 diff_node_printer p(out);
13128 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13129 diff_tree->context()->forbid_visiting_a_node_twice(false);
13130 diff_tree->traverse(p);
13131 diff_tree->context()->forbid_visiting_a_node_twice(s);
13132}
13133
13134/// Emit a textual representation of a @ref corpus_diff tree to an
13135/// output stream.
13136///
13137/// @param diff_tree the @ref corpus_diff tree to emit the textual
13138/// representation for.
13139///
13140/// @param out the output stream to emit the textual representation
13141/// for @p diff_tree to.
13142void
13143print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
13144{
13145 diff_node_printer p(out);
13146 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13147 diff_tree->context()->forbid_visiting_a_node_twice(false);
13148 diff_tree->traverse(p);
13149 diff_tree->context()->forbid_visiting_a_node_twice(s);
13150}
13151
13152/// Emit a textual representation of a @ref diff sub-tree to an
13153/// output stream.
13154///
13155/// @param diff_tree the sub-tree to emit the textual representation
13156/// for.
13157///
13158/// @param out the output stream to emit the textual representation
13159/// for @p diff_tree to.
13160void
13162 std::ostream& o)
13163{print_diff_tree(diff_tree.get(), o);}
13164
13165/// Emit a textual representation of a @ref corpus_diff tree to an
13166/// output stream.
13167///
13168/// @param diff_tree the @ref corpus_diff tree to emit the textual
13169/// representation for.
13170///
13171/// @param out the output stream to emit the textual representation
13172/// for @p diff_tree to.
13173void
13175 std::ostream& o)
13176{print_diff_tree(diff_tree.get(), o);}
13177
13178// <redundancy_marking_visitor>
13179
13180/// A tree visitor to categorize nodes with respect to the
13181/// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
13182/// present on several spots of the tree) and mark such nodes
13183/// appropriatly. This visitor also takes care of propagating the
13184/// REDUNDANT_CATEGORY of a given node to its parent nodes as
13185/// appropriate.
13186struct redundancy_marking_visitor : public diff_node_visitor
13187{
13188 bool skip_children_nodes_;
13189
13190 redundancy_marking_visitor()
13191 : skip_children_nodes_()
13192 {}
13193
13194 virtual void
13195 visit_begin(diff* d)
13196 {
13197 if (d->to_be_reported())
13198 {
13199 // A diff node that carries a change and that has been already
13200 // traversed elsewhere is considered redundant. So let's mark
13201 // it as such and let's not traverse it; that is, let's not
13202 // visit its children.
13203 if ((d->context()->diff_has_been_visited(d)
13204 || d->get_canonical_diff()->is_traversing())
13205 && d->has_changes())
13206 {
13207 // But if two diff nodes are redundant sibbling that carry
13208 // changes of base types, do not mark them as being
13209 // redundant. This is to avoid marking nodes as redundant
13210 // in this case:
13211 //
13212 // int foo(int a, int b);
13213 // compared with:
13214 // float foo(float a, float b); (in C).
13215 //
13216 // In this case, we want to report all the occurences of
13217 // the int->float change because logically, they are at
13218 // the same level in the diff tree.
13219
13220 bool redundant_with_sibling_node = false;
13221 const diff* p = d->parent_node();
13222
13223 // If this is a child node of a fn_parm_diff, look through
13224 // the fn_parm_diff node to get the function diff node.
13225 if (p && dynamic_cast<const fn_parm_diff*>(p))
13226 p = p->parent_node();
13227
13228 if (p)
13229 for (vector<diff*>::const_iterator s =
13230 p->children_nodes().begin();
13231 s != p->children_nodes().end();
13232 ++s)
13233 {
13234 if (*s == d)
13235 continue;
13236 diff* sib = *s;
13237 // If this is a fn_parm_diff, look through the
13238 // fn_parm_diff node to get at the real type node.
13239 if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
13240 sib = f->type_diff().get();
13241 if (sib == d)
13242 continue;
13243 if (sib->get_canonical_diff() == d->get_canonical_diff()
13244 // Sibbling diff nodes that carry base type
13245 // changes are to be marked as redundant.
13246 && (is_base_diff(sib) || is_distinct_diff(sib)))
13247 {
13248 redundant_with_sibling_node = true;
13249 break;
13250 }
13251 }
13252 if (!redundant_with_sibling_node
13253 // Changes to basic types should never be considered
13254 // redundant. For instance, if a member of integer
13255 // type is changed into a char type in both a struct A
13256 // and a struct B, we want to see both changes.
13258 // The same goes for distinct type changes
13260 // Functions with similar *local* changes are never marked
13261 // redundant because otherwise one could miss important
13262 // similar local changes that are applied to different
13263 // functions.
13265 // Changes involving variadic parameters of functions
13266 // should never be marked redundant because we want to see
13267 // them all.
13270 // If the canonical diff itself has been filtered out,
13271 // then this one is not marked redundant, unless the
13272 // canonical diff was already redundant.
13273 && (!d->get_canonical_diff()->is_filtered_out()
13274 || (d->get_canonical_diff()->get_category()
13276 // If the *same* diff node (not one that is merely
13277 // equivalent to this one) has already been visited
13278 // the do not mark it as beind redundant. It's only
13279 // the other nodes that are equivalent to this one
13280 // that must be marked redundant.
13281 && d->context()->diff_has_been_visited(d) != d
13282 // If the diff node is a function parameter and is not
13283 // a reference/pointer (to a non basic or a non
13284 // distinct type diff) then do not mark it as
13285 // redundant.
13286 //
13287 // Children nodes of base class diff nodes are never
13288 // redundant either, we want to see them all.
13292 {
13293 d->add_to_category(REDUNDANT_CATEGORY);
13294 // As we said in preamble, as this node is marked as
13295 // being redundant, let's not visit its children.
13296 // This is not an optimization; it's needed for
13297 // correctness. In the case of a diff node involving
13298 // a class type that refers to himself, visiting the
13299 // children nodes might cause them to be wrongly
13300 // marked as redundant.
13303 skip_children_nodes_ = true;
13304 }
13305 }
13306 }
13307 else
13308 {
13309 // If the node is not to be reported, do not look at it children.
13311 skip_children_nodes_ = true;
13312 }
13313 }
13314
13315 virtual void
13316 visit_begin(corpus_diff*)
13317 {
13318 }
13319
13320 virtual void
13321 visit_end(diff* d)
13322 {
13323 if (skip_children_nodes_)
13324 // When visiting this node, we decided to skip its children
13325 // node. Now that we are done visiting the node, lets stop
13326 // avoiding the children nodes visiting for the other tree
13327 // nodes.
13328 {
13330 skip_children_nodes_ = false;
13331 }
13332 else
13333 {
13334 // Propagate the redundancy categorization of the children nodes
13335 // to this node. But if this node has local changes, then it
13336 // doesn't inherit redundancy from its children nodes.
13337 if (!(d->get_category() & REDUNDANT_CATEGORY)
13338 && (!d->has_local_changes_to_be_reported()
13339 // By default, pointer, reference, array and qualified
13340 // types consider that a local changes to their
13341 // underlying type is always a local change for
13342 // themselves.
13343 //
13344 // This is as if those types don't have local changes
13345 // in the same sense as other types. So we always
13346 // propagate redundancy to them, regardless of if they
13347 // have local changes or not.
13348 //
13349 // We also propagate redundancy to typedef types if
13350 // these /only/ carry changes to their underlying
13351 // type.
13352 //
13353 // Note that changes to the underlying type of a
13354 // typedef is considered local of
13355 // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
13356 // typedef itself are considered local of
13357 // LOCAL_NON_TYPE_CHANGE_KIND kind.
13358 || is_pointer_diff(d)
13359 || is_array_diff(d)
13361 // A typedef with local non-type changes should not
13362 // see redundancy propagation from its underlying
13363 // type, otherwise, the non-type change might be
13364 // "suppressed" away.
13365 || (is_typedef_diff(d)
13366 && (!(d->has_local_changes()
13368 // A (member) variable with non-type local changes
13369 // should not see redundacy propagation from its type.
13370 // If redundant local-type changes are carried by its
13371 // type however, then that redundancy is propagated to
13372 // the variable. This is key to keep the redundancy
13373 // consistency in the system; otherwise, a type change
13374 // would be rightfully considered redundant at some
13375 // places but not at others.
13376 || (is_var_diff(d)
13377 && (!(d->has_local_changes()
13379 // A function parameter with non-type local changes
13380 // should not see redundancy propagation either. But
13381 // a function parameter with local type changes can
13382 // definitely be redundant.
13383 || (is_fn_parm_diff(d)
13384 && (!(d->has_local_changes()
13386 ))
13387 {
13388 bool has_non_redundant_child = false;
13389 bool has_non_empty_child = false;
13390 bool is_array_diff_node = is_array_diff(d);
13391 for (vector<diff*>::const_iterator i =
13392 d->children_nodes().begin();
13393 i != d->children_nodes().end();
13394 ++i)
13395 {
13396 if ((*i)->has_changes())
13397 {
13398 // If we are looking at a child node of an array,
13399 // do not take a subrange diff node change into
13400 // account when considering redundancy. In other
13401 // words, a subrange diff node that carries a
13402 // change should not be considered as a non-empty
13403 // child node. This is because we want to report
13404 // all subrange diff node changes and not consider
13405 // them as redundant.
13406 if (!is_array_diff_node || !is_subrange_diff(*i))
13407 has_non_empty_child = true;
13408 // Let's see if the current child node '*i' is
13409 // "non-redundant".
13410 //
13411 // A non-redundant node would be a node that
13412 // carries a change to be reported and has not
13413 // been marked as being redundant.
13414 if ((*i)->to_be_reported()
13415 && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
13416 has_non_redundant_child = true;
13417 }
13418 if (has_non_redundant_child)
13419 break;
13420 }
13421
13422 // A diff node for which at least a child node carries a
13423 // change, and for which all the children are redundant is
13424 // deemed redundant too, unless it has local changes.
13425 if (has_non_empty_child
13426 && !has_non_redundant_child)
13427 d->add_to_category(REDUNDANT_CATEGORY);
13428 }
13429 }
13430 }
13431
13432 virtual void
13433 visit_end(corpus_diff*)
13434 {
13435 }
13436
13437 virtual bool
13438 visit(diff*, bool)
13439 {return true;}
13440
13441 virtual bool
13442 visit(corpus_diff*, bool)
13443 {
13444 return true;
13445 }
13446};// end struct redundancy_marking_visitor
13447
13448/// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13449/// category out of the nodes.
13450struct redundancy_clearing_visitor : public diff_node_visitor
13451{
13452 bool
13453 visit(corpus_diff*, bool)
13454 {return true;}
13455
13456 bool
13457 visit(diff* d, bool)
13458 {
13459 // clear the REDUNDANT_CATEGORY out of the current node.
13460 diff_category c = d->get_category();
13461 c &= ~REDUNDANT_CATEGORY;
13462 d->set_category(c);
13463 return true;
13464 }
13465}; // end struct redundancy_clearing_visitor
13466
13467/// Walk a given @ref diff sub-tree to categorize each of the nodes
13468/// with respect to the REDUNDANT_CATEGORY.
13469///
13470/// @param diff_tree the @ref diff sub-tree to walk.
13471void
13473{
13474 if (diff_tree->context()->show_redundant_changes())
13475 return;
13476 redundancy_marking_visitor v;
13477 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13478 diff_tree->context()->forbid_visiting_a_node_twice(false);
13479 diff_tree->traverse(v);
13480 diff_tree->context()->forbid_visiting_a_node_twice(s);
13481}
13482
13483/// Walk a given @ref diff sub-tree to categorize each of the nodes
13484/// with respect to the REDUNDANT_CATEGORY.
13485///
13486/// @param diff_tree the @ref diff sub-tree to walk.
13487void
13489{categorize_redundancy(diff_tree.get());}
13490
13491/// Walk a given @ref corpus_diff tree to categorize each of the nodes
13492/// with respect to the REDUNDANT_CATEGORY.
13493///
13494/// @param diff_tree the @ref corpus_diff tree to walk.
13495void
13497{
13498 redundancy_marking_visitor v;
13499 diff_tree->context()->forget_visited_diffs();
13500 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13501 diff_tree->context()->forbid_visiting_a_node_twice(false);
13502 diff_tree->traverse(v);
13503 diff_tree->context()->forbid_visiting_a_node_twice(s);
13504}
13505
13506/// Walk a given @ref corpus_diff tree to categorize each of the nodes
13507/// with respect to the REDUNDANT_CATEGORY.
13508///
13509/// @param diff_tree the @ref corpus_diff tree to walk.
13510void
13513
13514// </redundancy_marking_visitor>
13515
13516/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13517/// out of the category of the nodes.
13518///
13519/// @param diff_tree the @ref diff sub-tree to walk.
13520void
13522{
13523 redundancy_clearing_visitor v;
13524 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13525 diff_tree->context()->forbid_visiting_a_node_twice(false);
13526 diff_tree->traverse(v);
13527 diff_tree->context()->forbid_visiting_a_node_twice(s);
13528 diff_tree->context()->forget_visited_diffs();
13529}
13530
13531/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13532/// out of the category of the nodes.
13533///
13534/// @param diff_tree the @ref diff sub-tree to walk.
13535void
13538
13539/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13540/// out of the category of the nodes.
13541///
13542/// @param diff_tree the @ref corpus_diff tree to walk.
13543void
13545{
13546 redundancy_clearing_visitor v;
13547 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13548 diff_tree->context()->forbid_visiting_a_node_twice(false);
13549 diff_tree->traverse(v);
13550 diff_tree->context()->forbid_visiting_a_node_twice(s);
13551 diff_tree->context()->forget_visited_diffs();
13552}
13553
13554/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13555/// out of the category of the nodes.
13556///
13557/// @param diff_tree the @ref corpus_diff tree to walk.
13558void
13561
13562/// Apply the @ref diff tree filters that have been associated to the
13563/// context of the a given @ref corpus_diff tree. As a result, the
13564/// nodes of the @diff tree are going to be categorized into one of
13565/// several of the categories of @ref diff_category.
13566///
13567/// @param diff_tree the @ref corpus_diff instance which @ref diff are
13568/// to be categorized.
13569void
13571{
13572 diff_tree->context()->maybe_apply_filters(diff_tree);
13573 propagate_categories(diff_tree);
13574}
13575
13576/// Test if a diff node represents the difference between a variadic
13577/// parameter type and something else.
13578///
13579/// @param d the diff node to consider.
13580///
13581/// @return true iff @p d is a diff node that represents the
13582/// difference between a variadic parameter type and something else.
13583bool
13585{
13586 if (!d)
13587 return false;
13588
13589 type_base_sptr t = is_type(d->first_subject());
13590 if (t && t->get_environment().is_variadic_parameter_type(t))
13591 return true;
13592
13593 t = is_type(d->second_subject());
13594 if (t && t->get_environment().is_variadic_parameter_type(t))
13595 return true;
13596
13597 return false;
13598}
13599
13600/// Test if a diff node represents the difference between a variadic
13601/// parameter type and something else.
13602///
13603/// @param d the diff node to consider.
13604///
13605/// @return true iff @p d is a diff node that represents the
13606/// difference between a variadic parameter type and something else.
13607bool
13610
13611/// Test if a diff node represents the difference between a variadic
13612/// parameter and something else.
13613///
13614/// @param d the diff node to consider.
13615///
13616/// @return true iff @p d is a diff node that represents the
13617/// difference between a variadic parameter and something else.
13618bool
13620{
13622 dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
13623 return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
13624}
13625
13626/// Test if a diff node represents the difference between a variadic
13627/// parameter and something else.
13628///
13629/// @param d the diff node to consider.
13630///
13631/// @return true iff @p d is a diff node that represents the
13632/// difference between a variadic parameter and something else.
13633bool
13636
13637/// Test if a diff node represents a diff between two basic types.
13638///
13639/// @param d the diff node to consider.
13640///
13641/// @return true iff @p d is a diff between two basic types.
13642const type_decl_diff*
13644{return dynamic_cast<const type_decl_diff*>(d);}
13645
13646/// Test if a diff node represents a diff between two basic types, or
13647/// between pointers, references or qualified type to basic types.
13648///
13649/// @param diff the diff node to consider.
13650///
13651/// @param allow_indirect_type if true, then this function looks into
13652/// pointer, reference or qualified diff types to see if they "point
13653/// to" basic types.
13654///
13655/// @return true iff @p d is a diff between two basic types.
13656const type_decl_diff*
13657is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
13658{
13659 if (allow_indirect_type)
13662}
13663
13664/// If a diff node is about changes between two typedef types, get the
13665/// diff node about changes between the underlying types.
13666///
13667/// Note that this function walks the tree of underlying diff nodes
13668/// returns the first diff node about types that are not typedefs.
13669///
13670/// @param dif the dif node to consider.
13671///
13672/// @return the underlying diff node of @p dif, or just return @p dif
13673/// if it's not a typedef diff node.
13674const diff*
13676{
13677 const typedef_diff *d = 0;
13678 while ((d = is_typedef_diff(dif)))
13679 dif = d->underlying_type_diff().get();
13680 return dif;
13681}
13682
13683/// If a diff node is about changes between two pointer types, get the
13684/// diff node about changes between the underlying (pointed-to) types.
13685///
13686/// Note that this function walks the tree of underlying diff nodes
13687/// returns the first diff node about types that are not pointers.
13688///
13689/// @param dif the dif node to consider.
13690///
13691/// @return the underlying diff node of @p dif, or just return @p dif
13692/// if it's not a pointer diff node.
13693const diff*
13695{
13696 const pointer_diff *d = 0;
13697 while ((d = is_pointer_diff(dif)))
13698 dif = d->underlying_type_diff().get();
13699 return dif;
13700}
13701
13702/// If a diff node is about changes between two reference types, get
13703/// the diff node about changes between the underlying (pointed-to)
13704/// types.
13705///
13706/// Note that this function walks the tree of underlying diff nodes
13707/// returns the first diff node about types that are not references.
13708///
13709/// @param dif the dif node to consider.
13710///
13711/// @return the underlying diff node of @p dif, or just return @p dif
13712/// if it's not a reference diff node.
13713const diff*
13715{
13716 const reference_diff *d = 0;
13717 while ((d = is_reference_diff(dif)))
13718 dif = d->underlying_type_diff().get();
13719 return dif;
13720}
13721
13722/// If a diff node is about changes between two qualified types, get
13723/// the diff node about changes between the underlying (non-qualified)
13724/// types.
13725///
13726/// Note that this function walks the tree of underlying diff nodes
13727/// returns the first diff node about types that are not qualified.
13728///
13729/// @param dif the dif node to consider.
13730///
13731/// @return the underlying diff node of @p dif, or just return @p dif
13732/// if it's not a qualified diff node.
13733const diff*
13735{
13736 const qualified_type_diff *d = 0;
13737 while ((d = is_qualified_type_diff(dif)))
13738 dif = d->underlying_type_diff().get();
13739 return dif;
13740}
13741
13742/// If a diff node is about changes between two function parameters
13743/// get the diff node about changes between the types of the parameters.
13744///
13745/// @param dif the dif node to consider.
13746///
13747/// @return the diff of the types of the parameters.
13748const diff*
13750{
13751 const fn_parm_diff *d = 0;
13752 while ((d = is_fn_parm_diff(dif)))
13753 dif = d->type_diff().get();
13754 return dif;
13755}
13756
13757/// If a diff node is about changes between two pointer, reference or
13758/// qualified types, get the diff node about changes between the
13759/// underlying types.
13760///
13761/// Note that this function walks the tree of underlying diff nodes
13762/// returns the first diff node about types that are not pointer,
13763/// reference or qualified.
13764///
13765/// @param dif the dif node to consider.
13766///
13767/// @return the underlying diff node of @p dif, or just return @p dif
13768/// if it's not a pointer, reference or qualified diff node.
13769const diff*
13771{
13772 while (true)
13773 {
13774 if (const pointer_diff *d = is_pointer_diff(dif))
13775 dif = peel_pointer_diff(d);
13776 else if (const reference_diff *d = is_reference_diff(dif))
13777 dif = peel_reference_diff(d);
13778 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13779 dif = peel_qualified_diff(d);
13780 else
13781 break;
13782 }
13783 return dif;
13784}
13785
13786/// If a diff node is about changes between two typedefs or qualified
13787/// types, get the diff node about changes between the underlying
13788/// types.
13789///
13790/// Note that this function walks the tree of underlying diff nodes
13791/// returns the first diff node about types that are not typedef or
13792/// qualified types.
13793///
13794/// @param dif the dif node to consider.
13795///
13796/// @return the underlying diff node of @p dif, or just return @p dif
13797/// if it's not typedef or qualified diff node.
13798const diff*
13800{
13801 while (true)
13802 {
13803 if (const typedef_diff *d = is_typedef_diff(dif))
13804 dif = peel_typedef_diff(d);
13805 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13806 dif = peel_qualified_diff(d);
13807 else
13808 break;
13809 }
13810 return dif;
13811}
13812
13813/// If a diff node is about changes between two typedefs or qualified
13814/// types, get the diff node about changes between the underlying
13815/// types.
13816///
13817/// Note that this function walks the tree of underlying diff nodes
13818/// returns the first diff node about types that are neither typedef,
13819/// qualified type nor parameters.
13820///
13821/// @param dif the dif node to consider.
13822///
13823/// @return the diff node about changes between the underlying types.
13824const diff*
13826{
13827 while (true)
13828 {
13829 if (const typedef_diff *d = is_typedef_diff(dif))
13830 dif = peel_typedef_diff(d);
13831 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13832 dif = peel_qualified_diff(d);
13833 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
13834 dif = peel_fn_parm_diff(d);
13835 else
13836 break;
13837 }
13838 return dif;
13839}
13840
13841/// Test if a diff node represents a diff between two class or union
13842/// types.
13843///
13844/// @param d the diff node to consider.
13845///
13846/// @return iff @p is a diff between two class or union types then
13847/// return the instance of @ref class_or_union_diff that @p derives
13848/// from. Otherwise, return nil.
13851{return dynamic_cast<const class_or_union_diff*>(d);}
13852
13853/// Test if a given diff node carries *only* a local type change.
13854///
13855/// @param d the diff node to consider.
13856///
13857/// @return true iff @p has a change and that change is a local type
13858/// change.
13859static bool
13860has_local_type_change_only(const diff *d)
13861{
13862 if (enum change_kind k = d->has_local_changes())
13863 if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
13864 && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
13865 return true;
13866
13867 return false;
13868}
13869
13870/// Test if a diff node is a decl diff that only carries a basic type
13871/// change on its type diff sub-node.
13872///
13873///Note that that pointers/references/qualified types diffs to basic
13874/// type diffs are considered as having basic type change only.
13875///
13876/// @param d the diff node to consider.
13877///
13878/// @return true iff @p d is a decl diff that only carries a basic
13879/// type change on its type diff sub-node.
13880bool
13882{
13884
13885 if (is_diff_of_basic_type(d, true) && d->has_changes())
13886 return true;
13887 else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
13888 return (has_local_type_change_only(v)
13889 && is_diff_of_basic_type(v->type_diff().get(), true));
13890 else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
13891 return (has_local_type_change_only(p)
13892 && is_diff_of_basic_type(p->type_diff().get(), true));
13893 else if (const function_decl_diff* f =
13894 dynamic_cast<const function_decl_diff*>(d))
13895 return (has_local_type_change_only(f)
13896 && f->type_diff()
13897 && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
13898 true));
13899 return false;
13900}
13901}// end namespace comparison
13902} // 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:1718
#define ABG_ASSERT_NOT_REACHED
A macro that expands to aborting the program when executed.
The abstraction of a diff between two arrays.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of array_diff.
const diff_sptr & element_type_diff() const
Getter for the diff between the two types of array elements.
array_diff(const array_type_def_sptr first, const array_type_def_sptr second, diff_sptr element_type_diff, vector< subrange_diff_sptr > &subrange_diffs, diff_context_sptr ctxt=diff_context_sptr())
Constructor for array_diff.
bool any_subrange_diff_to_be_reported() const
Test if any subrange diff is to be reported.
const array_type_def_sptr second_array() const
Getter for the second array of the diff.
const array_type_def_sptr first_array() const
Getter for the first array of the diff.
virtual enum change_kind has_local_changes() const
const vector< subrange_diff_sptr > & subrange_diffs() const
Getter for the diffs between the array subranges.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
An abstraction of a diff between two instances of class_decl::base_spec.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of base_diff.
void set_underlying_class_diff(class_diff_sptr d)
Setter for the diff object for the diff of the underlyng base classes.
class_decl::base_spec_sptr second_base() const
Getter for the second base spec of the diff object.
base_diff(class_decl::base_spec_sptr first, class_decl::base_spec_sptr second, class_diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
const class_diff_sptr get_underlying_class_diff() const
Getter for the diff object for the diff of the underlying base classes.
class_decl::base_spec_sptr first_base() const
Getter for the first base spec of the diff object.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Generates a report for the current instance of base_diff.
This type abstracts changes for a class_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_diff.
class_decl_sptr first_class_decl() const
const base_diff_sptrs_type & changed_bases()
Getter for the changed base classes of the diff.
const vector< class_decl::base_spec_sptr > & moved_bases() const
Getter for the vector of bases that "moved". That is, the vector of base types which position changed...
const string_base_sptr_map & inserted_bases() const
Getter for the inserted base classes of the diff.
const string_base_sptr_map & deleted_bases() const
Getter for the deleted base classes of the diff.
virtual enum change_kind has_local_changes() const
const edit_script & base_changes() const
virtual const string & get_pretty_representation() const
class_diff(class_decl_sptr first_scope, class_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor of class_diff.
friend class_diff_sptr compute_diff(const class_decl_sptr first, const class_decl_sptr second, diff_context_sptr ctxt)
Compute the set of changes between two instances of class_decl.
class_decl_sptr second_class_decl() const
Getter of the second class involved in the diff.
virtual void report(ostream &, const string &indent="") const
Produce a basic report about the changes between two class_decl.
This is the base class of class_diff and union_diff.
virtual bool has_changes() const
Test if the current diff node carries a change.
const edit_script & member_fn_tmpls_changes() const
size_t count_filtered_subtype_changed_data_members(bool local_only=false) const
Count the number of /filtered/ data members with a sub-type change.
const class_or_union_diff::priv_ptr & get_priv() const
Getter of the private data of the class_or_union_diff type.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_or_un...
const edit_script & member_class_tmpls_changes() const
void allocate_priv_data()
Allocate the memory for the priv_ pimpl data member of the class_or_union_diff class.
class_or_union_diff(class_or_union_sptr first_scope, class_or_union_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the class_or_union_diff class.
const unsigned_var_diff_sptr_map & changed_data_members() const
Getter of the map of data members that got replaced by another data member. The key of the map is the...
const edit_script & member_types_changes() const
const string_member_function_sptr_map & deleted_member_fns() const
class_or_union_sptr first_class_or_union() const
const var_diff_sptrs_type & sorted_subtype_changed_data_members() const
Getter of the sorted vector of data members with a (sub-)type change.
bool lookup_tables_empty(void) const
Tests if the lookup tables are empty.
const string_decl_base_sptr_map & data_members_replaced_by_adms() const
Get the map of data members that got replaced by anonymous data members.
void clear_lookup_tables(void)
Clear the lookup tables useful for reporting.
const string_decl_base_sptr_map & deleted_data_members() const
Getter for the data members that got deleted.
virtual ~class_or_union_diff()
Destructor of class_or_union_diff.
const string_decl_base_sptr_map & inserted_data_members() const
Getter for the data members that got inserted.
void ensure_lookup_tables_populated(void) const
If the lookup tables are not yet built, walk the differences and fill them.
const string_member_function_sptr_map & inserted_member_fns() const
const function_decl_diff_sptrs_type & changed_member_fns() const
Getter for the virtual members functions that have had a change in a sub-type, without having a chang...
const edit_script & data_members_changes() const
const changed_var_sptrs_type & ordered_data_members_replaced_by_adms() const
Get an ordered vector of of data members that got replaced by anonymous data members.
virtual enum change_kind has_local_changes() const
size_t count_filtered_changed_data_members(bool local_only=false) const
Count the number of /filtered/ data members that got replaced by another data member.
const edit_script & member_fns_changes() const
class_or_union_sptr second_class_or_union() const
const var_diff_sptrs_type & sorted_changed_data_members() const
Getter of the sorted vector of data members that got replaced by another data member.
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current class_or_union_diff node in a textual format.
This is a document class that aims to capture statistics about the changes carried by a corpus_diff t...
size_t num_changed_unreachable_types_filtered_out() const
Getter of the number of changed types that are unreachable from public interfaces and that have been ...
size_t num_func_removed() const
Getter for the number of functions removed.
size_t num_removed_unreachable_types_filtered_out() const
Getter of the number of removed types that are not reachable from public interfaces and that have bee...
size_t num_vars_changed() const
Getter for the number of variables that have a change in one of their sub-types.
size_t 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.
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.
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.
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.
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.
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.
const string_changed_enumerator_map & changed_enumerators() const
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const enum_type_decl_sptr first_enum() const
const string_enumerator_map & deleted_enumerators() const
const enum_type_decl_sptr second_enum() const
const string_enumerator_map & inserted_enumerators() const
virtual void report(ostream &, const string &indent="") const
Report the differences between the two enums.
A filter that walks the diff nodes tree and tags relevant diff nodes into categories considered to re...
Abstraction of a diff between two function parameters.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children nodes of the diff base type sub-object of this instance of fn_parm_di...
const function_decl::parameter_sptr first_parameter() const
Getter for the first subject of this diff node.
virtual enum change_kind has_local_changes() const
Check if the current diff node carries a local change.
virtual const string & get_pretty_representation() const
Build and return a textual representation of the current instance of fn_parm_diff.
const function_decl::parameter_sptr second_parameter() const
Getter for the second subject of this diff node.
diff_sptr type_diff() const
Getter for the diff representing the changes on the type of the function parameter involved in the cu...
virtual void report(ostream &, const string &indent="") const
Emit a textual report about the current fn_parm_diff instance.
Abstraction of a diff between two function_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_de...
const function_decl_sptr second_function_decl() const
function_decl_diff(const function_decl_sptr first, const function_decl_sptr second, diff_context_sptr ctxt)
Constructor for function_decl_diff.
virtual enum change_kind has_local_changes() const
const function_decl_sptr first_function_decl() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Serialize a report of the changes encapsulated in the current instance of function_decl_diff over to ...
Abstraction of a diff between two function types.
virtual bool has_changes() const
Test if the current diff node carries changes.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_ty...
const string_fn_parm_diff_sptr_map & subtype_changed_parms() const
Getter for the map of function parameter changes of the current diff.
const diff_sptr return_type_diff() const
Getter for the diff of the return types of the two function types of the current diff.
const string_parm_map & removed_parms() const
Getter for the map of parameters that got removed.
const string_parm_map & added_parms() const
Getter for the map of parameters that got added.
friend function_type_diff_sptr compute_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of function_type.
const vector< function_decl::parameter_sptr > & sorted_added_parms() const
Getter for the sorted vector of added parameters .
const function_type_sptr first_function_type() const
Getter for the first subject of the diff.
const function_type_sptr second_function_type() const
Getter for the second subject of the diff.
function_type_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Consutrctor of the function_type type.
virtual enum change_kind has_local_changes() const
Test if the current diff node carries local changes.
virtual const string & get_pretty_representation() const
Build and return a copy of a pretty representation of the current instance of function_type_diff.
const vector< function_decl::parameter_sptr > & sorted_deleted_parms() const
Getter for the sorted vector of deleted parameters.
virtual void report(ostream &, const string &indent="") const
Build and emit a textual report about the current function_type_diff instance.
A reporter that only reports leaf changes.
The abstraction of a diff between two pointers.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const pointer_type_def_sptr first_pointer() const
Getter for the first subject of a pointer diff.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of pointer_dif...
const pointer_type_def_sptr second_pointer() const
Getter for the second subject of a pointer diff.
diff_sptr underlying_type_diff() const
Getter for the diff between the pointed-to types of the pointers of this diff.
pointer_diff(pointer_type_def_sptr first, pointer_type_def_sptr second, diff_sptr underlying_type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for a pointer_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
The abstraction of a diff between two ptr_to_mbr_type.
virtual bool has_changes() const
Test whether the current diff node carries any change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of ptr_to_mbr_...
virtual ~ptr_to_mbr_diff()
Destructor of ptr_to_mbr_diff.
ptr_to_mbr_type_sptr first_ptr_to_mbr_type() const
Getter of the first pointer-to-member subject of the current diff node.
const diff_sptr containing_type_diff() const
Getter of the diff node carrying changes to the containing type of first subject of the current diff ...
const diff_sptr member_type_diff() const
Getter of the diff node carrying changes to the member type of first subject of the current diff node...
ptr_to_mbr_type_sptr second_ptr_to_mbr_type() const
Getter of the second pointer-to-member subject of the current diff node.
virtual enum change_kind has_local_changes() const
Test whether the current diff node carries any local change.
virtual const string & get_pretty_representation() const
Get the pretty representation of the current ptr_to_mbr_diff node.
virtual void report(ostream &, const string &indent="") const
Pure interface to report the diff in a serialized form that is legible for the user.
Abstraction of a diff between two qualified types.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of qualified_t...
diff_sptr leaf_underlying_type_diff() const
Getter for the diff between the most underlying non-qualified types of two qualified types.
diff_sptr underlying_type_diff() const
Getter for the diff between the underlying types of the two qualified types.
qualified_type_diff(qualified_type_def_sptr first, qualified_type_def_sptr second, diff_sptr underling, diff_context_sptr ctxt=diff_context_sptr())
Constructor for qualified_type_diff.
const qualified_type_def_sptr second_qualified_type() const
Getter for the second qualified type of the diff.
virtual enum change_kind has_local_changes() const
const qualified_type_def_sptr first_qualified_type() const
Getter for the first qualified type of the diff.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
The abstraction of a diff between two references.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of reference_d...
reference_type_def_sptr first_reference() const
Getter for the first reference of the diff.
reference_type_def_sptr second_reference() const
Getter for the second reference of the diff.
reference_diff(const reference_type_def_sptr first, const reference_type_def_sptr second, diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
Constructor for reference_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const diff_sptr & underlying_type_diff() const
Getter for the diff between the two referred-to types.
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
An abstractions of the changes between two scopes.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of scope_diff.
const diff_sptrs_type & changed_types() const
const scope_decl_sptr second_scope() const
Getter for the second scope of the diff.
const scope_decl_sptr first_scope() const
Getter for the first scope of the diff.
const decl_base_sptr deleted_member_at(unsigned index) const
Accessor that eases the manipulation of the edit script associated to this instance....
const diff_sptrs_type & changed_decls() const
scope_diff(scope_decl_sptr first_scope, scope_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for scope_diff.
friend scope_diff_sptr compute_diff(const scope_decl_sptr first, const scope_decl_sptr second, scope_diff_sptr d, diff_context_sptr ctxt)
Compute the diff between two scopes.
const decl_base_sptr inserted_member_at(unsigned i)
Accessor that eases the manipulation of the edit script associated to this instance....
virtual void report(ostream &out, const string &indent="") const
Report the changes of one scope against another.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const edit_script & member_changes() const
Accessor of the edit script of the members of a scope.
The abstraction of the diff between two subrange types.
virtual bool has_changes() const
Test if the current subrange_diff node carries any change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of subrange_di...
const array_type_def::subrange_sptr second_subrange() const
Getter of the second subrange of the current instance subrange_diff.
subrange_diff(const array_type_def::subrange_sptr &first, const array_type_def::subrange_sptr &second, const diff_sptr &underlying_type_diff, const diff_context_sptr ctxt=diff_context_sptr())
Constructor of the subrange_diff diff node type.
const array_type_def::subrange_sptr first_subrange() const
Getter of the first subrange of the current instance subrange_diff.
const diff_sptr underlying_type_diff() const
Getter of the diff node of the underlying types of the current subrange_diff diff node.
virtual enum change_kind has_local_changes() const
Test if the current subrange_diff node carries any local change.
virtual const string & get_pretty_representation() const
Getter the pretty representation of the subrange_diff diff node.
virtual void report(ostream &, const string &indent="") const
Report about the changes carried by this node.
An abstraction of a diff between two translation units.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const translation_unit_sptr second_translation_unit() const
Getter for the second translation unit of this diff.
translation_unit_diff(translation_unit_sptr first, translation_unit_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for translation_unit_diff.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
virtual enum change_kind has_local_changes() const
const translation_unit_sptr first_translation_unit() const
Getter for the first translation unit of this diff.
Abstraction of a diff between two basic type declarations.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const type_decl_sptr first_type_decl() const
Getter for the first subject of the type_decl_diff.
const type_decl_sptr second_type_decl() const
Getter for the second subject of the type_decl_diff.
virtual void report(ostream &out, const string &indent="") const
Ouputs a report of the differences between of the two type_decl involved in the type_decl_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
The base class of diff between types.
Abstraction of a diff between two typedef_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of typedef_dif...
const typedef_decl_sptr second_typedef_decl() const
Getter for the second typedef_decl involved in the diff.
const typedef_decl_sptr first_typedef_decl() const
Getter for the firt typedef_decl involved in the diff.
const diff_sptr underlying_type_diff() const
Getter for the diff between the two underlying types of the typedefs.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Reports the difference between the two subjects of the diff in a serialized form.
union_diff(union_decl_sptr first_union, union_decl_sptr second_union, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the union_diff type.
union_decl_sptr first_union_decl() const
union_decl_sptr second_union_decl() const
virtual ~union_diff()
Destructor of the union_diff node.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current union_diff node in a textual format.
Abstracts a diff between two instances of var_decl.
virtual bool has_changes() const
Return true iff the diff node has a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of var_diff.
var_diff(var_decl_sptr first, var_decl_sptr second, diff_sptr type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for var_diff.
var_decl_sptr first_var() const
Getter for the first var_decl of the diff.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
virtual enum change_kind has_local_changes() const
friend var_diff_sptr compute_diff(const var_decl_sptr first, const var_decl_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of var_decl.
virtual const string & get_pretty_representation() const
diff_sptr type_diff() const
Getter for the diff of the types of the instances of var_decl.
var_decl_sptr second_var() const
Getter for the second var_decl of the diff.
The abstraction of an edit script for transforming a sequence A into a sequence B.
shared_ptr< subrange_type > subrange_sptr
Convenience typedef for a shared pointer on a function_decl::subrange.
Definition abg-ir.h:2537
shared_ptr< base_spec > base_spec_sptr
Convenience typedef.
Definition abg-ir.h:4145
vector< base_spec_sptr > base_specs
Convenience typedef.
Definition abg-ir.h:4146
vector< method_decl_sptr > member_functions
Convenience typedef.
Definition abg-ir.h:3960
bool get_is_anonymous() const
Test if the current declaration is anonymous.
Definition abg-ir.cc:4523
The abstraction of the version of an ELF symbol.
Definition abg-ir.h:1203
Abstraction of an elf symbol.
Definition abg-ir.h:932
const string & get_id_string() const
Get a string that is representative of a given elf_symbol.
Definition abg-ir.cc:2471
std::vector< enumerator > enumerators
Convenience typedef for a list of enumerator.
Definition abg-ir.h:2772
Abstraction for a function declaration.
Definition abg-ir.h:3117
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition abg-ir.h:3139
const function_type_sptr get_type() const
Return the type of the current instance of function_decl.
Definition abg-ir.cc:22480
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:22816
An abstraction helper for type declarations.
Definition abg-ir.h:1974
The base class of both types and declarations.
Definition abg-ir.h:1377
change_kind
The kind of change the current function suppression should apply to.
@ ADDED_FUNCTION_CHANGE_KIND
The function was added to the second subject of the diff.
@ DELETED_FUNCTION_CHANGE_KIND
The function was deleted from the second subject of the diff.
change_kind
The kind of change the current variable suppression should apply to.
@ ADDED_VARIABLE_CHANGE_KIND
The variable was added to the second second subject of the diff.
@ DELETED_VARIABLE_CHANGE_KIND
The variable was deleted from the second subject of the diff.
A type used to time various part of the libabigail system.
bool stop()
Stop the timer.
bool start()
Start the timer.
bool has_void_ptr_to_ptr_change(const diff *dif)
Test if a diff node carries a void* to pointer type change.
std::vector< filter_base_sptr > filters
Convenience typedef for a vector of filter_base_sptr.
bool has_harmless_enum_to_int_change(const diff *diff)
Test if a diff node carries a harmless change of an enum into an integer (or vice-versa).
bool is_decl_only_class_with_size_change(const class_or_union &first, const class_or_union &second)
Test if two classes that are decl-only (have the decl-only flag and carry no data members) but are di...
shared_ptr< filter_base > filter_base_sptr
Convenience typedef for a shared pointer to filter_base.
bool has_harmful_name_change(const decl_base_sptr &f, const decl_base_sptr &s)
Test if two decls represents a harmful name change.
bool has_benign_array_of_unknown_size_change(const diff *dif)
Test if a diff node carries a benign change to the size of a variable of type array.
bool has_decl_only_def_change(const decl_base_sptr &first, const decl_base_sptr &second)
Test if two decl_base_sptr are different just by the fact that one is decl-only and the other one is ...
bool has_basic_or_class_type_name_change(const diff *d)
Test if a diff node carries a basic or class type name change.
void apply_filter(filter_base &filter, corpus_diff_sptr d)
Walk the diff sub-trees of a a corpus_diff and apply a filter to the nodes visted....
bool is_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:78
visiting_kind operator~(visiting_kind l)
The overloaded 'bit inversion' operator for visiting_kind.
const decl_diff_base * is_decl_diff(const diff *diff)
Test if a diff node is about differences between declarations.
const diff * peel_qualified_diff(const diff *dif)
If a diff node is about changes between two qualified types, get the diff node about changes between ...
const diff * peel_pointer_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two pointer, reference or qualified types,...
void categorize_redundancy(diff *diff_tree)
Walk a given diff sub-tree to categorize each of the nodes with respect to the REDUNDANT_CATEGORY.
vector< diff * > diff_ptrs_type
Convenience typedef for a vector of diff*.
void sort_string_diff_ptr_map(const string_diff_ptr_map &map, diff_ptrs_type &sorted)
Sort a map ofg string -> diff* into a vector of diff_ptr. The diff_ptr are sorted lexicographically w...
diff_category
An enum for the different categories that a diff tree node falls into, regarding the kind of changes ...
@ ACCESS_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries access related changes,...
@ HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless data member change....
@ SUPPRESSED_CATEGORY
This means that a diff node was marked as suppressed by a user-provided suppression specification.
@ VIRTUAL_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an incompatible change to a vtable.
@ REDUNDANT_CATEGORY
A diff node in this category is redundant. That means it's present as a child of a other nodes in the...
@ SIZE_OR_OFFSET_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries a change that modifies the...
@ NON_VIRT_MEM_FUN_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a non-virtual member fu...
@ HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
A diff node in this category has a descendant node that is in the HAS_ALLOWED_CHANGE_CATEGORY categor...
@ HARMLESS_ENUM_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition of enumerator to an enum type.
@ FN_PARM_ADD_REMOVE_CHANGE_CATEGORY
A diff node in this category is a function (or function type) with at least one parameter added or re...
@ VOID_PTR_TO_PTR_CHANGE_CATEGORY
A diff node in this category carries a change from void pointer to non-void pointer.
@ NON_COMPATIBLE_DISTINCT_CHANGE_CATEGORY
A change between two non-compatible types of different kinds.
@ PRIVATE_TYPE_CATEGORY
This means that a diff node was warked as being for a private type. That is, the diff node is meant t...
@ NON_COMPATIBLE_NAME_CHANGE_CATEGORY
A non-compatible name change between two types.
@ COMPATIBLE_TYPE_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries a change involving two com...
@ TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a type that was declaration-only and that is now ...
@ STATIC_DATA_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a static data member.
@ HARMLESS_UNION_OR_CLASS_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless union or class change.
@ HARMLESS_DECL_NAME_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless declaration name change....
@ NO_CHANGE_CATEGORY
This means the diff node does not carry any (meaningful) change, or that it carries changes that have...
@ HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
A diff node in this category has a parent node that is in the HAS_ALLOWED_CHANGE_CATEGORY category....
@ BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY
A diff node in this category carries a change in the size of the array type of a global variable,...
@ VAR_TYPE_CV_CHANGE_CATEGORY
A diff node in this category is for a variable which type holds a cv-qualifier change.
@ HAS_ALLOWED_CHANGE_CATEGORY
A diff node in this category carries a change that must be reported, even if the diff node is also in...
@ FN_PARM_TYPE_CV_CHANGE_CATEGORY
A diff node in this category has a function parameter type with a cv-qualifiers change.
@ FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
A diff node in this category is a function parameter type which top cv-qualifiers change.
@ FN_RETURN_TYPE_CV_CHANGE_CATEGORY
A diff node in this category is a function return type with a cv-qualifier change.
@ HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an a symbol alias change that is harmless.
shared_ptr< reporter_base > reporter_base_sptr
A convenience typedef for a shared pointer to a reporter_base.
void sort_string_var_diff_sptr_map(const string_var_diff_sptr_map &map, var_diff_sptrs_type &sorted)
Sort of an instance of string_var_diff_sptr_map map.
unordered_map< string, var_diff_sptr > string_var_diff_sptr_map
Convenience typedef for a map whose key is a string and whose value is a changed variable of type var...
const class_or_union_diff * is_diff_of_class_or_union_type(const diff *d)
Test if a diff node represents a diff between two class or union types.
const subrange_diff * is_anonymous_subrange_diff(const diff *d)
Test if a diff node is a subrange_diff between two anonymous subranges.
const pointer_diff * is_pointer_diff(const diff *diff)
Test if a diff node is about differences between two pointers.
vector< var_diff_sptr > var_diff_sptrs_type
Convenience typedef for a vector of var_diff_sptr.
unordered_map< string, class_decl::base_spec_sptr > string_base_sptr_map
Convenience typedef for a map of string and class_decl::basse_spec_sptr.
void sort_string_function_ptr_map(const string_function_ptr_map &map, vector< const function_decl * > &sorted)
Sort an instance of string_function_ptr_map map and stuff a resulting sorted vector of pointers to fu...
diff_sptr try_to_diff(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
</distinct_diff>
bool has_basic_type_change_only(const diff *d)
Test if a diff node is a decl diff that only carries a basic type change on its type diff sub-node.
void propagate_categories(diff *diff_tree)
Visit all the nodes of a given sub-tree. For each node that has a particular category set,...
const subrange_diff * is_subrange_diff(const diff *diff)
Test if a diff node is a subrange_diff node.
unordered_map< unsigned, fn_parm_diff_sptr > unsigned_fn_parm_diff_sptr_map
Convenience typedef for a map which key is an integer and which value is a changed parameter.
void sort_string_base_sptr_map(const string_base_sptr_map &m, class_decl::base_specs &sorted)
Lexicographically sort base specifications found in instances of string_base_sptr_map.
diff_category get_default_harmless_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmless.
vector< diff_sptr > diff_sptrs_type
Convenience typedef for a vector of diff_sptr.
distinct_diff_sptr compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
Try to diff entities that are of distinct kinds.
void sort_changed_data_members(changed_var_sptrs_type &input)
Sort (in place) a vector of changed data members.
unordered_map< string, type_base_sptr > string_type_base_sptr_map
Convenience typedef for a map which key is a string and which value is a type_base_sptr.
diff_sptr try_to_diff< class_decl >(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
This is a specialization of try_to_diff() template to diff instances of class_decl.
shared_ptr< type_decl_diff > type_decl_diff_sptr
Convenience typedef for a shared pointer on a type_decl_diff type.
bool is_diff_of_variadic_parameter(const diff *d)
Test if a diff node represents the difference between a variadic parameter and something else.
shared_ptr< diff_context > diff_context_sptr
Convenience typedef for a shared pointer of diff_context.
Definition abg-fwd.h:70
bool is_diff_of_global_decls(const diff *)
Tests if a given diff node is to represent the changes between two gobal decls.
shared_ptr< subrange_diff > subrange_diff_sptr
A convenience typedef for a shared pointer to subrange_diff type.
bool is_diff_of_variadic_parameter_type(const diff *d)
Test if a diff node represents the difference between a variadic parameter type and something else.
diff_category get_default_harmful_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmful.
unordered_map< string, function_decl::parameter_sptr > string_parm_map
Convenience typedef for a map which value is a function parameter. The key is the name of the functio...
unordered_map< string, enum_type_decl::enumerator > string_enumerator_map
Convenience typedef for a map which value is an enumerator. The key is the name of the enumerator.
shared_ptr< var_diff > var_diff_sptr
Convenience typedef for a shared pointer to a var_diff type.
unordered_map< string, method_decl_sptr > string_member_function_sptr_map
Convenience typedef for a hash map of strings and member functions.
const diff * peel_typedef_diff(const diff *dif)
If a diff node is about changes between two typedef types, get the diff node about changes between th...
shared_ptr< reference_diff > reference_diff_sptr
Convenience typedef for a shared pointer on a reference_diff type.
vector< base_diff_sptr > base_diff_sptrs_type
Convenience typedef for a vector of base_diff_sptr.
shared_ptr< function_decl_diff > function_decl_diff_sptr
Convenience typedef for a shared pointer to a function_decl type.
shared_ptr< ptr_to_mbr_diff > ptr_to_mbr_diff_sptr
Typedef of a shared_ptr to ptr_to_mbr_diff.
void sort_string_elf_symbol_map(const string_elf_symbol_map &map, vector< elf_symbol_sptr > &sorted)
Sort a map of string -> pointer to elf_symbol.
const function_decl_diff * is_function_decl_diff(const diff *diff)
Test if a diff node is about differences between functions.
void sort_string_function_decl_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort the values of a string_function_decl_diff_sptr_map map and store the result in a vector of funct...
shared_ptr< fn_parm_diff > fn_parm_diff_sptr
Convenience typedef for a shared pointer to a fn_parm_diff type.
unordered_map< string, function_decl_diff_sptr > string_function_decl_diff_sptr_map
Convenience typedef for a map which key is a string and which value is a function_decl_diff_sptr.
void clear_redundancy_categorization(diff *diff_tree)
Walk a given diff sub-tree to clear the REDUNDANT_CATEGORY out of the category of the nodes.
void sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map, var_diff_sptrs_type &sorted)
Sort the values of a unsigned_var_diff_sptr_map map and store the result into a vector of var_diff_sp...
void sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map &map, vector< fn_parm_diff_sptr > &sorted)
Sort a map of fn_parm_diff by the indexes of the function parameters.
bool is_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.
unordered_map< string, var_decl_sptr > string_var_ptr_map
Convenience typedef for a map which key is a string and which value is a point to var_decl.
void sort_artifacts_set(const artifact_sptr_set_type &set, vector< type_or_decl_base_sptr > &sorted)
Sort the set of ABI artifacts contained in a artifact_sptr_set_type.
const class_or_union_diff * is_anonymous_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff between two anonymous classes or unions.
shared_ptr< base_diff > base_diff_sptr
Convenience typedef for a shared pointer to a base_diff type.
shared_ptr< scope_diff > scope_diff_sptr
Convenience typedef for a shared pointer on a scope_diff.
shared_ptr< class_diff > class_diff_sptr
Convenience typedef for a shared pointer on a class_diff type.
const base_diff * is_base_diff(const diff *diff)
Test if a diff node is about differences between two base class specifiers.
const fn_parm_diff * is_fn_parm_diff(const diff *diff)
Test if a diff node is about differences between two function parameters.
void sort_string_member_function_sptr_map(const string_member_function_sptr_map &map, class_or_union::member_functions &sorted)
Sort a map that's an instance of string_member_function_sptr_map and fill a vector of member function...
const union_diff * is_union_diff(const diff *diff)
Test if a diff node is a union_diff node.
vector< changed_var_sptr > changed_var_sptrs_type
Convenience typedef for a vector of @changed_var_sptr.gg381.
shared_ptr< pointer_diff > pointer_diff_sptr
Convenience typedef for a shared pointer on a pointer_diff type.
const diff * peel_pointer_diff(const diff *dif)
If a diff node is about changes between two pointer types, get the diff node about changes between th...
void sort_string_var_ptr_map(const string_var_ptr_map &map, vector< var_decl_sptr > &sorted)
Sort a map of string -> pointer to var_decl.
void apply_suppressions(diff *diff_tree)
Walk a given diff-sub tree and appply the suppressions carried by the context. If the suppression app...
void sort_string_parm_map(const string_parm_map &map, vector< function_decl::parameter_sptr > &sorted)
Sort a map of string -> function parameters.
void sort_string_type_base_sptr_map(string_type_base_sptr_map &map, vector< type_base_sptr > &sorted)
Sort a map of string to type_base_sptr entities.
const enum_diff * is_enum_diff(const diff *diff)
Test if a diff node is a enum_diff node.
unordered_map< string, base_diff_sptr > string_base_diff_sptr_map
Convenience typedef for a map of string and base_diff_sptr.
void sort_data_members(const string_decl_base_sptr_map &data_members, vector< decl_base_sptr > &sorted)
Sort a map of data members by the offset of their initial value.
const class_or_union_diff * is_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff node.
const corpus_diff * is_corpus_diff(const diff *diff)
Test if a diff node is a corpus_diff node.
const diff * get_typedef_diff_underlying_type_diff(const diff *diff)
Return the leaf underlying diff node of a typedef_diff node.
const typedef_diff * is_typedef_diff(const diff *diff)
Test if a diff node is a typedef_diff node.
unordered_map< unsigned, var_diff_sptr > unsigned_var_diff_sptr_map
Convenience typedef for a map whose key is an unsigned int and whose value is a changed variable of t...
type_base_sptr get_leaf_type(qualified_type_def_sptr t)
Return the first underlying type that is not a qualified type.
const diff * peel_typedef_qualified_type_or_parameter_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
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.
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:235
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition abg-ir.cc:6309
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:5430
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition abg-fwd.h:269
unordered_set< type_or_decl_base_sptr, type_or_decl_hash, type_or_decl_equal > artifact_sptr_set_type
A convenience typedef for a hash set of type_or_decl_base_sptr.
Definition abg-ir.h:559
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition abg-ir.cc:10465
bool is_anonymous_data_member(const decl_base &d)
Test if a decl is an anonymous data member.
Definition abg-ir.cc:5727
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:11841
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition abg-ir.h:897
change_kind
A bitfield that gives callers of abigail::ir::equals() some insight about how different two internal ...
Definition abg-ir.h:1332
@ LOCAL_TYPE_CHANGE_KIND
This means that a given IR artifact has a local type change.
Definition abg-ir.h:1336
@ ALL_LOCAL_CHANGES_MASK
Testing (anding) against this mask means that a given IR artifact has local differences,...
Definition abg-ir.h:1347
@ LOCAL_NON_TYPE_CHANGE_KIND
This means that a given IR artifact has a local non-type change. That is a change that is carried by ...
Definition abg-ir.h:1341
bool is_user_defined_type(const type_base *t)
Test if a type is user-defined.
Definition abg-ir.cc:5334
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:5670
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition abg-ir.cc:10791
shared_ptr< array_type_def > array_type_def_sptr
Convenience typedef for a shared pointer on a array_type_def.
Definition abg-fwd.h:244
string get_pretty_representation(const type_or_decl_base *tod, bool internal)
Build and return a copy of the pretty representation of an ABI artifact that could be either a type o...
Definition abg-ir.cc:9135
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:11022
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:5597
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition abg-fwd.h:193
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition abg-fwd.h:210
shared_ptr< typedef_decl > typedef_decl_sptr
Convenience typedef for a shared pointer on a typedef_decl.
Definition abg-fwd.h:167
const enum_type_decl * is_enum_type(const type_or_decl_base *d)
Test if a decl is an enum_type_decl.
Definition abg-ir.cc:10741
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:10308
const global_scope * get_global_scope(const decl_base &decl)
return the global scope as seen by a given declaration.
Definition abg-ir.cc:8398
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition abg-fwd.h:256
shared_ptr< ptr_to_mbr_type > ptr_to_mbr_type_sptr
Convenience typedef for a shared pointer to a ptr_to_mbr_type.
Definition abg-fwd.h:239
shared_ptr< scope_decl > scope_decl_sptr
Convenience typedef for a shared pointer on a scope_decl.
Definition abg-fwd.h:264
shared_ptr< type_or_decl_base > type_or_decl_base_sptr
A convenience typedef for a shared_ptr to type_or_decl_base.
Definition abg-fwd.h:120
shared_ptr< translation_unit > translation_unit_sptr
Convenience typedef for a shared pointer on a translation_unit type.
Definition abg-fwd.h:136
unordered_map< string, decl_base_sptr > string_decl_base_sptr_map
Convenience typedef for a map which key is a string and which value is a decl_base_sptr.
Definition abg-fwd.h:157
bool equals(const decl_base &l, const decl_base &r, change_kind *k)
Compares two instances of decl_base.
Definition abg-ir.cc:4993
shared_ptr< pointer_type_def > pointer_type_def_sptr
Convenience typedef for a shared pointer on a pointer_type_def.
Definition abg-fwd.h:226
bool is_enumerator_present_in_enum(const enum_type_decl::enumerator &enr, const enum_type_decl &enom)
Test if a given enumerator is found present in an enum.
Definition abg-ir.cc:20060
uint64_t get_absolute_data_member_offset(const var_decl &m)
Get the absolute offset of a data member.
Definition abg-ir.cc:6128
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition abg-ir.cc:6223
var_decl * is_var_decl(const type_or_decl_base *tod)
Tests if a declaration is a variable declaration.
Definition abg-ir.cc:11685
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition abg-ir.cc:10405
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition abg-fwd.h:175
type_base_sptr strip_typedef(const type_base_sptr type)
Recursively returns the the underlying type of a typedef. The return type should not be a typedef of ...
Definition abg-ir.cc:6635
uint64_t get_data_member_offset(const var_decl &m)
Get the offset of a data member.
Definition abg-ir.cc:6039
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition abg-ir.cc:6496
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:5885
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:11544
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition abg-ir.cc:11071
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition abg-ir.cc:5468
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition abg-ir.cc:10078
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:28517
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:9029
shared_ptr< type_decl > type_decl_sptr
Convenience typedef for a shared pointer on a type_decl.
Definition abg-fwd.h:161
bool is_unique_type(const type_base_sptr &t)
Test if a type is unique in the entire environment.
Definition abg-ir.cc:28112
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:11514
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:11043
bool is_at_global_scope(const decl_base &decl)
Tests whether a given declaration is at global scope.
Definition abg-ir.cc:10238
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition abg-ir.cc:5272
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:1662
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:1659
bool is_negated_suppression(const suppression_base &s)
Test if a suppression specification is a negated suppression.
Toplevel namespace for libabigail.
A comparison function for instances of base_diff.
A functor to compare instances of class_decl::base_spec.
A functor to compare two changed enumerators, based on their initial value.
size_t count_filtered_bases()
Count the number of bases classes whose changes got filtered out.
class_decl::base_spec_sptr base_has_changed(class_decl::base_spec_sptr) const
Test whether a given base class has changed. A base class has changed if it's in both in deleted *and...
The type of private data of class_or_union_diff.
size_t count_filtered_changed_dm(bool local_only=false)
Get the number of data member changes carried by the current diff node that were filtered out.
size_t count_filtered_subtype_changed_dm(bool local_only=false)
Get the number of data member sub-type changes carried by the current diff node that were filtered ou...
size_t get_deleted_non_static_data_members_number() const
Get the number of non static data members that were deleted.
size_t count_filtered_changed_mem_fns(const diff_context_sptr &)
Get the number of member functions changes carried by the current diff node that were filtered out.
decl_base_sptr subtype_changed_dm(decl_base_sptr) const
Test if the current diff node carries a data member change for a data member which name is the same a...
type_or_decl_base_sptr member_type_has_changed(decl_base_sptr) const
Test if the current diff node carries a member type change for a member type which name is the same a...
decl_base_sptr member_class_tmpl_has_changed(decl_base_sptr) const
Test if the current diff node carries a member class template change for a member class template whic...
size_t count_filtered_inserted_mem_fns(const diff_context_sptr &)
Get the number of member functions insertions carried by the current diff node that were filtered out...
size_t count_filtered_deleted_mem_fns(const diff_context_sptr &)
Get the number of member functions deletions carried by the current diff node that were filtered out.
size_t get_inserted_non_static_data_members_number() const
Get the number of non static data members that were inserted.
The type of the private data of corpus_diff::diff_stats.
bool added_unreachable_type_is_suppressed(const type_base *t) const
Test if an added type that is unreachable from public interface has been suppressed by a suppression ...
void ensure_lookup_tables_populated()
If the lookup tables are not yet built, walk the differences and fill the lookup tables.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Get the sorted vector of diff nodes representing changed unreachable types.
diff_context_sptr get_context()
Getter of the context associated with this corpus.
void categorize_redundant_changed_sub_nodes()
Walk the changed functions and variables diff nodes to categorize redundant nodes.
const string_diff_sptr_map & changed_unreachable_types() const
Get the map of diff nodes representing changed unreachable types.
bool added_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added variable symbol (that is not referenced by any debug inf...
bool lookup_tables_empty() const
Tests if the lookup tables are empty.
bool deleted_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted function symbol (that is not referenced by any debug i...
void apply_filters_and_compute_diff_stats(corpus_diff::diff_stats &)
Compute the diff stats.
bool deleted_unreachable_type_is_suppressed(const type_base *t) const
Test if a deleted type that is unreachable from public interface has been suppressed by a suppression...
bool deleted_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted variable symbol (that is not referenced by any debug i...
void maybe_dump_diff_tree()
If the user asked to dump the diff tree node (for changed variables and functions) on the error outpu...
void count_unreachable_types(size_t &num_added, size_t &num_removed, size_t &num_changed, size_t &num_filtered_added, size_t &num_filtered_removed, size_t &num_filtered_changed)
Count the number of types not reachable from the interface (i.e, not reachable from global functions ...
bool deleted_variable_is_suppressed(const var_decl_sptr &var) const
Test if the change reports for a give given deleted variable has been deleted.
void clear_redundancy_categorization()
Walk the changed functions and variables diff nodes and clear the redundancy categorization they migh...
void count_leaf_changes(size_t &num_changes, size_t &num_filtered)
Count the number of leaf changes as well as the number of the changes that have been filtered out.
void count_leaf_type_changes(size_t &num_type_changes, size_t &num_type_changes_filtered)
Count the number of leaf *type* changes as well as the number of the leaf type changes that have been...
bool added_variable_is_suppressed(const var_decl_sptr &var) const
Test if the change reports for a given added variable have been suppressed.
bool added_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added function symbol (that is not referenced by any debug inf...
bool deleted_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a given deleted function have been deleted.
void apply_supprs_to_added_removed_fns_vars_unreachable_types()
Apply suppression specifications for this corpus diff to the set of added/removed functions/variables...
void emit_diff_stats(const diff_stats &stats, ostream &out, const string &indent)
Emit the summary of the functions & variables that got removed/changed/added.
bool added_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a give given added function has been deleted.
void clear_lookup_tables()
Clear the lookup tables useful for reporting an enum_diff.
A comparison functor to compare two data members based on their offset.
A comparison functor to compare two instances of var_diff that represent changed data members based o...
A comparison functor for instances of diff.
A functor to compare two instances of diff_sptr.
The private data structure for distinct_diff.
A functor to compare instances of elf_symbol base on their names.
A functor to compare two enumerators based on their value. This implements the "less than" operator.
A comparison functor to compare two instances of fn_parm_diff based on their indexes.
"Less than" functor to compare instances of function_decl.
A "Less Than" functor to compare instance of function_decl_diff.
Functor that compares two function parameters for the purpose of sorting them.
The internal type for the impl idiom implementation of pointer_diff.
The private data of the ptr_to_mbr_diff type.
The internal type for the impl idiom implementation of subrange_diff.
A functor to compare instances of var_decl base on their qualified names.
The internal type for the impl idiom implementation of var_diff.
Functor to sort instances of var_diff_sptr.
A comparison functor for instances of function_decl_diff that represent changes between two virtual m...
An equality functor to deeply compare pointers.
A comparison functor to compare pointer to instances of type_or_decl_base.
Definition abg-ir.h:3246
A deleter for shared pointers that ... doesn't delete the object managed by the shared pointer.