libabigail
abg-comparison.cc
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2// -*- Mode: C++ -*-
3//
4// Copyright (C) 2013-2023 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/// Sort an instance of @ref string_function_ptr_map map and stuff a
172/// resulting sorted vector of pointers to function_decl.
173///
174/// @param map the map to sort.
175///
176/// @param sorted the resulting sorted vector.
177void
179 vector<const function_decl*>& sorted)
180{
181 sorted.reserve(map.size());
182 for (string_function_ptr_map::const_iterator i = map.begin();
183 i != map.end();
184 ++i)
185 sorted.push_back(i->second);
186
187 function_comp comp;
188 std::sort(sorted.begin(), sorted.end(), comp);
189}
190
191/// Sort a map that's an instance of @ref
192/// string_member_function_sptr_map and fill a vector of member
193/// functions with the sorted result.
194///
195/// @param map the map to sort.
196///
197/// @param sorted the resulting sorted vector.
198void
201{
202 sorted.reserve(map.size());
203 for (string_member_function_sptr_map::const_iterator i = map.begin();
204 i != map.end();
205 ++i)
206 sorted.push_back(i->second);
207
208 function_comp comp;
209 std::sort(sorted.begin(), sorted.end(), comp);
210}
211
212/// Sort the values of a @ref string_function_decl_diff_sptr_map map
213/// and store the result in a vector of @ref function_decl_diff_sptr
214/// objects.
215///
216/// @param map the map whose values to store.
217///
218/// @param sorted the vector of function_decl_diff_sptr to store the
219/// result of the sort into.
220void
224{
225 sorted.reserve(map.size());
226 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
227 i != map.end();
228 ++i)
229 sorted.push_back(i->second);
231 std::sort(sorted.begin(), sorted.end(), comp);
232}
233
234/// Sort of an instance of @ref string_var_diff_sptr_map map.
235///
236/// @param map the input map to sort.
237///
238/// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
239/// It's populated with the sorted content.
240void
242 var_diff_sptrs_type& sorted)
243{
244 sorted.reserve(map.size());
245 for (string_var_diff_sptr_map::const_iterator i = map.begin();
246 i != map.end();
247 ++i)
248 sorted.push_back(i->second);
249
251 std::sort(sorted.begin(), sorted.end(), comp);
252}
253
254/// Sort a map of string -> pointer to @ref elf_symbol.
255///
256/// The result is a vector of @ref elf_symbol_sptr sorted by the
257/// name of the symbol.
258///
259/// @param map the map to sort.
260///
261/// @param sorted out parameter; the sorted vector of @ref
262/// elf_symbol_sptr.
263void
265 vector<elf_symbol_sptr>& sorted)
266{
267 for (string_elf_symbol_map::const_iterator i = map.begin();
268 i!= map.end();
269 ++i)
270 sorted.push_back(i->second);
271
272 elf_symbol_comp comp;
273 std::sort(sorted.begin(), sorted.end(), comp);
274}
275
276/// Sort a map of string -> pointer to @ref var_decl.
277///
278/// The result is a vector of var_decl* sorted by the qualified name
279/// of the variables.
280///
281/// @param map the map to sort.
282///
283/// @param sorted out parameter; the sorted vector of @ref var_decl.
284void
286 vector<const var_decl*>& sorted)
287{
288 for (string_var_ptr_map::const_iterator i = map.begin();
289 i != map.end();
290 ++i)
291 sorted.push_back(i->second);
292
293 var_comp comp;
294 std::sort(sorted.begin(), sorted.end(), comp);
295}
296
297/// Sort the values of a string_var_diff_sptr_map and store the result
298/// in a vector of var_diff_sptr.
299///
300/// @param map the map of changed data members to sort.
301///
302/// @param sorted the resulting vector of var_diff_sptr.
303void
305 var_diff_sptrs_type& sorted)
306{
307 sorted.reserve(map.size());
308 for (string_var_diff_sptr_map::const_iterator i = map.begin();
309 i != map.end();
310 ++i)
311 sorted.push_back(i->second);
313 std::sort(sorted.begin(), sorted.end(), comp);
314}
315
316/// Sort the values of a unsigned_var_diff_sptr_map map and store the
317/// result into a vector of var_diff_sptr.
318///
319/// @param map the map of changed data members to sort.
320///
321/// @param sorted the resulting vector of sorted var_diff_sptr.
322void
324 var_diff_sptrs_type& sorted)
325{
326 sorted.reserve(map.size());
327 for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
328 i != map.end();
329 ++i)
330 sorted.push_back(i->second);
332 std::sort(sorted.begin(), sorted.end(), comp);
333}
334
335/// Sort an map of string -> virtual member function into a vector of
336/// virtual member functions. The virtual member functions are sorted
337/// by increasing order of their virtual index.
338///
339/// @param map the input map.
340///
341/// @param sorted the resulting sorted vector of virtual function
342/// member.
343void
347{
348 sorted.reserve(map.size());
349 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
350 i != map.end();
351 ++i)
352 sorted.push_back(i->second);
353
355 sort(sorted.begin(), sorted.end(), comp);
356}
357
358/// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
359/// diff_sptr. The diff_sptr are sorted lexicographically wrt
360/// qualified names of their first subjects.
361///
362/// @param map the map to sort.
363///
364/// @param sorted the resulting sorted vector.
365void
367 diff_sptrs_type& sorted)
368{
369 sorted.reserve(map.size());
370 for (string_diff_sptr_map::const_iterator i = map.begin();
371 i != map.end();
372 ++i)
373 sorted.push_back(i->second);
374
375 diff_comp comp;
376 sort(sorted.begin(), sorted.end(), comp);
377}
378
379/// Sort a map ofg string -> @ref diff* into a vector of @ref
380/// diff_ptr. The diff_ptr are sorted lexicographically wrt
381/// qualified names of their first subjects.
382///
383/// @param map the map to sort.
384///
385/// @param sorted the resulting sorted vector.
386void
388 diff_ptrs_type& sorted)
389{
390 sorted.reserve(map.size());
391 for (string_diff_ptr_map::const_iterator i = map.begin();
392 i != map.end();
393 ++i)
394 sorted.push_back(i->second);
395
396 diff_comp comp;
397 sort(sorted.begin(), sorted.end(), comp);
398}
399
400/// Sort a map of string -> base_diff_sptr into a sorted vector of
401/// base_diff_sptr. The base_diff_sptr are sorted by increasing value
402/// of their offset in their containing type.
403///
404/// @param map the input map to sort.
405///
406/// @param sorted the resulting sorted vector.
407void
409 base_diff_sptrs_type& sorted)
410{
411 for (string_base_diff_sptr_map::const_iterator i = map.begin();
412 i != map.end();
413 ++i)
414 sorted.push_back(i->second);
415 base_diff_comp comp;
416 sort(sorted.begin(), sorted.end(), comp);
417}
418
419/// Lexicographically sort base specifications found
420/// in instances of string_base_sptr_map.
421void
424{
425 for (string_base_sptr_map::const_iterator i = m.begin();
426 i != m.end();
427 ++i)
428 sorted.push_back(i->second);
429
430 base_spec_comp comp;
431 std::sort(sorted.begin(), sorted.end(), comp);
432}
433
434/// Sort a map of @ref fn_parm_diff by the indexes of the function
435/// parameters.
436///
437/// @param map the map to sort.
438///
439/// @param sorted the resulting sorted vector of changed function
440/// parms.
441void
443 vector<fn_parm_diff_sptr>& sorted)
444{
445 sorted.reserve(map.size());
446 for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
447 i != map.end();
448 ++i)
449 sorted.push_back(i->second);
450
452 std::sort(sorted.begin(), sorted.end(), comp);
453}
454
455/// Sort a map of changed function parameters by the indexes of the
456/// function parameters.
457///
458/// @param map the map to sort.
459///
460/// @param sorted the resulting sorted vector of instances of @ref
461/// fn_parm_diff_sptr
462void
464 vector<fn_parm_diff_sptr>& sorted)
465{
466 sorted.reserve(map.size());
467 for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
468 i != map.end();
469 ++i)
470 sorted.push_back(i->second);
471
473 std::sort(sorted.begin(), sorted.end(), comp);
474}
475
476/// Sort a map of string -> function parameters.
477///
478/// @param map the map to sort.
479///
480/// @param sorted the resulting sorted vector of
481/// @ref vector<function_decl::parameter_sptr>
482void
484 vector<function_decl::parameter_sptr>& sorted)
485{
486 for (string_parm_map::const_iterator i = map.begin();
487 i != map.end();
488 ++i)
489 sorted.push_back(i->second);
490
491 parm_comp comp;
492 std::sort(sorted.begin(), sorted.end(), comp);
493}
494
495/// Sort the set of ABI artifacts contained in a @ref
496/// artifact_sptr_set_type.
497///
498/// @param set the set of ABI artifacts to sort.
499///
500/// @param output parameter the vector containing the sorted ABI
501/// artifacts.
502void
504 vector<type_or_decl_base_sptr>& sorted)
505{
506
507 for (artifact_sptr_set_type::const_iterator it = set.begin();
508 it != set.end();
509 ++it)
510 sorted.push_back(*it);
511
513 std::sort(sorted.begin(), sorted.end(), comp);
514}
515
516/// Sort a map of string to type_base_sptr entities.
517///
518/// The entries are sorted based on the lexicographic order of the
519/// pretty representation of the type_sptr_sptr. The sorted result is
520/// put in a vector of type_base_sptr.
521///
522/// @param map the map to sort.
523///
524/// @param sorted the resulting vector of type_base_sptr
525/// lexicographically sorted using their pretty representation.
526void
528 vector<type_base_sptr>& sorted)
529{
530 for (string_type_base_sptr_map::const_iterator i = map.begin();
531 i != map.end();
532 ++i)
533 sorted.push_back(i->second);
534
536 std::sort(sorted.begin(), sorted.end(), comp);
537}
538
539/// Return the first underlying type that is not a qualified type.
540/// @param t the qualified type to consider.
541///
542/// @return the first underlying type that is not a qualified type, or
543/// NULL if t is NULL.
544type_base_sptr
545get_leaf_type(qualified_type_def_sptr t)
546{
547 if (!t)
548 return type_base_sptr();
549
550 type_base_sptr ut = t->get_underlying_type();
551 qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
552
553 if (!qut)
554 return ut;
555 return get_leaf_type(qut);
556}
557
558/// Tests if a given diff node is to represent the changes between two
559/// gobal decls.
560///
561/// @param d the diff node to consider.
562///
563/// @return true iff @p d represents the changes between two global
564/// decls.
565bool
567{
568 ABG_ASSERT(d != 0);
569
570 if (d == 0)
571 return false;
572
574 ABG_ASSERT(first);
575
577 ABG_ASSERT(second);
578
579 if (decl_base_sptr decl = is_decl(first))
580 if (is_at_global_scope(decl))
581 if ((decl = is_decl(second)))
582 if (is_at_global_scope(decl))
583 return true;
584
585 return false;
586}
587
588// -----------------------------------------
589// </private functions re-usable elsewhere>
590// -----------------------------------------
591
592/// The overloaded or operator for @ref visiting_kind.
595{return static_cast<visiting_kind>(static_cast<unsigned>(l)
596 | static_cast<unsigned>(r));}
597
598/// The overloaded and operator for @ref visiting_kind.
601{
602 return static_cast<visiting_kind>(static_cast<unsigned>(l)
603 & static_cast<unsigned>(r));
604}
605
606/// The overloaded 'bit inversion' operator for @ref visiting_kind.
609{return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
610
611/// Test if a diff node is about differences between types.
612///
613/// @param diff the diff node to test.
614///
615/// @return a pointer to the actual type_diff_base* that @p diff
616/// extends, iff it is about differences between types.
617const type_diff_base*
619{return dynamic_cast<const type_diff_base*>(diff);}
620
621/// Test if a diff node is about differences between declarations.
622///
623/// @param diff the diff node to test.
624///
625/// @return a pointer to the actual decl_diff_base @p diff extends,
626/// iff it is about differences between declarations.
627const decl_diff_base*
629{return dynamic_cast<const decl_diff_base*>(diff);}
630
631/// Test if a diff node is a @ref class_diff node.
632///
633/// @param diff the diff node to consider.
634///
635/// @return a non-nil pointer to a @ref class_diff iff @p diff is a
636/// @ref class_diff node.
637const class_diff*
639{return dynamic_cast<const class_diff*>(diff);}
640
641/// Test if a diff node is a @ref enum_diff node.
642///
643/// @param diff the diff node to consider.
644///
645/// @return a non-nil pointer to ad @ref enum_diff node iff @p diff is
646/// a @ref enum_diff node.
647const enum_diff*
649{return dynamic_cast<const enum_diff*>(diff);}
650
651/// Test if a diff node is a @ref union_diff node.
652///
653/// @param diff the diff node to consider.
654///
655/// @return a non-nil pointer to a @ref union_diff iff @p diff is a
656/// @ref union_diff node.
657const union_diff*
659{return dynamic_cast<const union_diff*>(diff);}
660
661/// Test if a diff node is a @ref class_or_union_diff node.
662///
663/// @param d the diff node to consider.
664///
665/// @return a non-nil pointer to the @ref class_or_union_diff denoted
666/// by @p d iff @p d is a @ref class_or_union_diff.
669{return dynamic_cast<const class_or_union_diff*>(d);}
670
671/// Test if a diff node is a @ref class_or_union_diff between two
672/// anonymous classes or unions.
673///
674/// @param d the diff node to consider.
675///
676/// @return a non-nil pointer to the @ref class_or_union_diff iff @p
677/// denoted by @p d iff @p is pointer to an anonymous class or union
678/// diff.
681{
683 if (dif->first_class_or_union()->get_is_anonymous())
684 return dif;
685 return 0;
686}
687
688/// Test if a diff node is a @ref typedef_diff node.
689///
690/// @param diff the diff node to consider.
691///
692/// @return a non-nil pointer to a @ref typedef_diff iff @p diff is a
693/// @ref typedef_diff node.
694const typedef_diff*
696{return dynamic_cast<const typedef_diff*>(diff);}
697
698/// Test if a diff node is a @ref subrange_diff node.
699///
700/// @param diff the diff node to consider.
701///
702/// @return a non-nil pointer to a @ref subrange_diff iff @p diff is a
703/// @ref subrange_diff node.
704const subrange_diff*
706{return dynamic_cast<const subrange_diff*>(diff);}
707
708/// Test if a diff node is a @ref array_diff node.
709///
710/// @param diff the diff node to consider.
711///
712/// @return a non-nil pointer to a @ref array_diff iff @p diff is a
713/// @ref array_diff node.
714const array_diff*
716{return dynamic_cast<const array_diff*>(diff);}
717
718/// Test if a diff node is a @ref function_type_diff node.
719///
720/// @param diff the diff node to consider.
721///
722/// @return a non-nil pointer to a @ref function_type_diff iff @p diff is a
723/// @ref function_type_diff node.
726{return dynamic_cast<const function_type_diff*>(diff);}
727
728/// Test if a given diff node carries a function type change with
729/// local changes.
730///
731/// @param diff the diff node to consider.
732///
733/// @return a non-nil pointer to a @ref function_type_diff iff @p diff
734/// is a function_type_diff node that carries a local change.
737{
739 if (d->has_local_changes())
740 return d;
741
742 return 0;
743}
744
745/// Test if a diff node is about differences between variables.
746///
747/// @param diff the diff node to test.
748///
749/// @return a pointer to the actual var_diff that @p diff is a type
750/// of, iff it is about differences between variables.
751const var_diff*
753{
754 const var_diff* d = dynamic_cast<const var_diff*>(diff);
755 if (d)
757 return d;
758}
759
760/// Test if a diff node is about differences between functions.
761///
762/// @param diff the diff node to test.
763///
764/// @return a pointer to the actual var_diff that @p diff is a type
765/// of, iff it is about differences between variables.
768{
769 const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
770 if (d)
772 return d;
773}
774
775/// Test if a diff node is about differences between two pointers.
776///
777/// @param diff the diff node to consider.
778///
779/// @return the @p diff converted into an instance of @ref
780/// pointer_diff iff @p diff is about differences between two
781/// pointers.
782const pointer_diff*
784{return dynamic_cast<const pointer_diff*>(diff);}
785
786/// Test if a diff node is about differences between two references.
787///
788/// @param diff the diff node to consider.
789///
790/// @return the @p diff converted into an instance of @ref
791/// reference_diff iff @p diff is about differences between two
792/// references.
793const reference_diff*
795{return dynamic_cast<const reference_diff*>(diff);}
796
797/// Test if a diff node is about differences between two qualified
798/// types.
799///
800/// @param diff the diff node to consider.
801///
802/// @return @p diff converted into an instance of @ref
803/// qualified_type_diff iff @p diff is about differences between two
804/// qualified types.
807{return dynamic_cast<const qualified_type_diff*>(diff);}
808
809/// Test if a diff node is a reference or pointer diff node to a
810/// change that is neither basic type change nor distinct type change.
811///
812/// Note that this function also works on diffs of typedefs of
813/// reference or pointer.
814///
815/// @param diff the diff node to consider.
816///
817/// @return true iff @p diff is a eference or pointer diff node to a
818/// change that is neither basic type change nor distinct type change.
819bool
821{
823 if (const reference_diff* d = is_reference_diff(diff))
824 {
827 return false;
828 return true;
829 }
830 else if (const pointer_diff *d = is_pointer_diff(diff))
831 {
834 return false;
835 return true;
836 }
837
838 return false;
839}
840
841/// Test if a diff node is about differences between two function
842/// parameters.
843///
844/// @param diff the diff node to consider.
845///
846/// @return the @p diff converted into an instance of @ref
847/// reference_diff iff @p diff is about differences between two
848/// function parameters.
849const fn_parm_diff*
851{return dynamic_cast<const fn_parm_diff*>(diff);}
852
853/// Test if a diff node is about differences between two base class
854/// specifiers.
855///
856/// @param diff the diff node to consider.
857///
858/// @return the @p diff converted into an instance of @ref base_diff
859/// iff @p diff is about differences between two base class
860/// specifiers.
861const base_diff*
863{return dynamic_cast<const base_diff*>(diff);}
864
865/// Test if a diff node is about differences between two diff nodes of
866/// different kinds.
867///
868/// @param diff the diff node to consider.
869///
870/// @return the @p diff converted into an instance of @ref
871/// distintc_diff iff @p diff is about differences between two diff
872/// nodes of different kinds.
873const distinct_diff*
875{return dynamic_cast<const distinct_diff*>(diff);}
876
877/// Test if a diff node is a @ref corpus_diff node.
878///
879/// @param diff the diff node to consider.
880///
881/// @return a non-nil pointer to a @ref corpus_diff iff @p diff is a
882/// @ref corpus_diff node.
883const corpus_diff*
885{return dynamic_cast<const corpus_diff*>(diff);}
886
887/// Test if a diff node is a child node of a function parameter diff node.
888///
889/// @param diff the diff node to test.
890///
891/// @return true iff @p diff is a child node of a function parameter
892/// diff node.
893bool
895{return diff && is_fn_parm_diff(diff->parent_node());}
896
897/// Test if a diff node is a child node of a base diff node.
898///
899/// @param diff the diff node to test.
900///
901/// @return true iff @p diff is a child node of a base diff node.
902bool
904{return diff && is_base_diff(diff->parent_node());}
905
906/// The default traverse function.
907///
908/// @return true.
909bool
911{return true;}
912
913diff_context::diff_context()
914 : priv_(new diff_context::priv)
915{
916 // Setup all the diff output filters we have.
918
920 add_diff_filter(f);
921
922 // f.reset(new filtering::harmless_filter);
923 // add_diff_filter(f);
924
925 // f.reset(new filtering::harmful_filter);
926 // add_diff_filter(f);
927}
928
929diff_context::~diff_context() = default;
930
931/// Test if logging was requested.
932///
933/// @return true iff logging was requested.
934bool
936{return priv_->do_log_;}
937
938/// Set logging as requested.
939///
940/// @param f the flag
941void
943{priv_->do_log_ = f;}
944
945/// Set the corpus diff relevant to this context.
946///
947/// @param d the corpus_diff we are interested in.
948void
950{priv_->corpus_diff_ = d;}
951
952/// Get the corpus diff for the current context.
953///
954/// @return the corpus diff of this context.
955const corpus_diff_sptr&
957{return priv_->corpus_diff_;}
958
959/// Getter for the first corpus of the corpus diff of the current context.
960///
961/// @return the first corpus of the corpus diff of the current
962/// context, if no corpus diff is associated to the context.
963corpus_sptr
965{
966 if (priv_->corpus_diff_)
967 return priv_->corpus_diff_->first_corpus();
968 return corpus_sptr();
969}
970
971/// Getter for the second corpus of the corpus diff of the current
972/// context.
973///
974/// @return the second corpus of the corpus diff of the current
975/// context, if no corpus diff is associated to the context.
976corpus_sptr
978{
979 if (priv_->corpus_diff_)
980 return priv_->corpus_diff_->second_corpus();
981 return corpus_sptr();
982}
983
984/// Getter of the reporter to be used in this context.
985///
986/// @return the reporter to be used in this context.
989{
990 if (!priv_->reporter_)
991 {
993 priv_->reporter_.reset(new leaf_reporter);
994 else
995 priv_->reporter_.reset(new default_reporter);
996 }
997 ABG_ASSERT(priv_->reporter_);
998 return priv_->reporter_;
999}
1000
1001/// Setter of the reporter to be used in this context.
1002///
1003/// @param r the reporter to be used in this context.
1004void
1006{priv_->reporter_ = r;}
1007
1008/// Tests if the current diff context already has a diff for two decls.
1009///
1010/// @param first the first decl to consider.
1011///
1012/// @param second the second decl to consider.
1013///
1014/// @return a pointer to the diff for @p first @p second if found,
1015/// null otherwise.
1017diff_context::has_diff_for(const type_or_decl_base_sptr first,
1018 const type_or_decl_base_sptr second) const
1019{
1020 types_or_decls_diff_map_type::const_iterator i =
1021 priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
1022 if (i != priv_->types_or_decls_diff_map.end())
1023 return i->second;
1024 return diff_sptr();
1025}
1026
1027/// Tests if the current diff context already has a diff for two types.
1028///
1029/// @param first the first type to consider.
1030///
1031/// @param second the second type to consider.
1032///
1033/// @return a pointer to the diff for @p first @p second if found,
1034/// null otherwise.
1036diff_context::has_diff_for_types(const type_base_sptr first,
1037 const type_base_sptr second) const
1038{return has_diff_for(first, second);}
1039
1040/// Tests if the current diff context already has a given diff.
1041///
1042///@param d the diff to consider.
1043///
1044/// @return a pointer to the diff found for @p d
1045const diff*
1046diff_context::has_diff_for(const diff* d) const
1047{return has_diff_for(d->first_subject(), d->second_subject()).get();}
1048
1049/// Tests if the current diff context already has a given diff.
1050///
1051///@param d the diff to consider.
1052///
1053/// @return a pointer to the diff found for @p d
1055diff_context::has_diff_for(const diff_sptr d) const
1056{return has_diff_for(d->first_subject(), d->second_subject());}
1057
1058/// Getter for the bitmap that represents the set of categories that
1059/// the user wants to see reported.
1060///
1061/// @return a bitmap that represents the set of categories that the
1062/// user wants to see reported.
1065{return priv_->allowed_category_;}
1066
1067/// Setter for the bitmap that represents the set of categories that
1068/// the user wants to see reported.
1069///
1070/// @param c a bitmap that represents the set of categories that the
1071/// user wants to see represented.
1072void
1074{priv_->allowed_category_ = c;}
1075
1076/// Setter for the bitmap that represents the set of categories that
1077/// the user wants to see reported
1078///
1079/// This function perform a bitwise or between the new set of
1080/// categories and the current ones, and then sets the current
1081/// categories to the result of the or.
1082///
1083/// @param c a bitmap that represents the set of categories that the
1084/// user wants to see represented.
1085void
1087{priv_->allowed_category_ = priv_->allowed_category_ | c;}
1088
1089/// Setter for the bitmap that represents the set of categories that
1090/// the user wants to see reported
1091///
1092/// This function actually unsets bits from the current categories.
1093///
1094/// @param c a bitmap that represents the set of categories to unset
1095/// from the current categories.
1096void
1098{priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
1099
1100/// Add a diff for two decls to the cache of the current diff_context.
1101///
1102/// Doing this allows to later find the added diff from its two
1103/// subject decls.
1104///
1105/// @param first the first decl to consider.
1106///
1107/// @param second the second decl to consider.
1108///
1109/// @param the diff to add.
1110void
1111diff_context::add_diff(type_or_decl_base_sptr first,
1113 const diff_sptr d)
1114{priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
1115
1116/// Add a diff tree node to the cache of the current diff_context
1117///
1118/// @param d the diff tree node to add.
1119void
1120diff_context::add_diff(const diff* d)
1121{
1122 if (d)
1123 {
1124 diff_sptr dif(const_cast<diff*>(d), noop_deleter());
1125 add_diff(d->first_subject(), d->second_subject(), dif);
1126 }
1127}
1128
1129/// Add a diff tree node to the cache of the current diff_context
1130///
1131/// @param d the diff tree node to add.
1132void
1133diff_context::add_diff(const diff_sptr d)
1134{
1135 if (d)
1136 add_diff(d->first_subject(), d->second_subject(), d);
1137}
1138
1139/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1140/// @ref diff represented by their two subjects.
1141///
1142/// @param first the first subject of the diff.
1143///
1144/// @param second the second subject of the diff.
1145///
1146/// @return the canonical diff for the diff node represented by the
1147/// two diff subjects @p first and @p second. If no canonical diff
1148/// node was registered for these subjects, then a nil node is
1149/// returned.
1152 const type_or_decl_base_sptr second) const
1153{return has_diff_for(first, second);}
1154
1155/// Getter for the @ref CanonicalDiff "canonical diff node" for the
1156/// @ref diff represented by the two subjects of a given diff node.
1157///
1158/// @param d the diff node to get the canonical node for.
1159///
1160/// @return the canonical diff for the diff node represented by the
1161/// two diff subjects of @p d. If no canonical diff node was
1162/// registered for these subjects, then a nil node is returned.
1165{return has_diff_for(d);}
1166
1167/// Setter for the @ref CanonicalDiff "canonical diff node" for the
1168/// @ref diff represented by their two subjects.
1169///
1170/// @param first the first subject of the diff.
1171///
1172/// @param second the second subject of the diff.
1173///
1174/// @param d the new canonical diff.
1175void
1176diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
1177 const type_or_decl_base_sptr second,
1178 const diff_sptr d)
1179{
1180 ABG_ASSERT(d);
1181 if (!has_diff_for(first, second))
1182 {
1183 add_diff(first, second, d);
1184 priv_->canonical_diffs.push_back(d);
1185 }
1186}
1187
1188/// If there is is a @ref CanonicalDiff "canonical diff node"
1189/// registered for two diff subjects, return it. Otherwise, register
1190/// a canonical diff node for these two diff subjects and return it.
1191///
1192/// @param first the first subject of the diff.
1193///
1194/// @param second the second subject of the diff.
1195///
1196/// @param d the new canonical diff node.
1197///
1198/// @return the canonical diff node.
1200diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
1201 const type_or_decl_base_sptr second,
1202 const diff_sptr canonical_diff)
1203{
1204 ABG_ASSERT(canonical_diff);
1205
1206 diff_sptr canonical = get_canonical_diff_for(first, second);
1207 if (!canonical)
1208 {
1209 canonical = canonical_diff;
1210 set_canonical_diff_for(first, second, canonical);
1211 }
1212 return canonical;
1213}
1214
1215/// Set the canonical diff node property of a given diff node
1216/// appropriately.
1217///
1218/// For a given diff node that has no canonical diff node, retrieve
1219/// the canonical diff node (by looking at its diff subjects and at
1220/// the current context) and set the canonical diff node property of
1221/// the diff node to that canonical diff node. If no canonical diff
1222/// node has been registered to the diff context for the subjects of
1223/// the diff node then, register the canonical diff node as being the
1224/// diff node itself; and set its canonical diff node property as
1225/// such. Otherwise, if the diff node already has a canonical diff
1226/// node, do nothing.
1227///
1228/// @param diff the diff node to initialize the canonical diff node
1229/// property for.
1230void
1232{
1233 if (diff->get_canonical_diff() == 0)
1234 {
1235 diff_sptr canonical =
1236 set_or_get_canonical_diff_for(diff->first_subject(),
1238 diff);
1239 diff->set_canonical_diff(canonical.get());
1240 }
1241}
1242
1243/// Add a diff node to the set of diff nodes that are kept alive for
1244/// the life time of the current instance of diff_context.
1245///
1246/// Note that diff added to the diff cache are kept alive as well, and
1247/// don't need to be passed to this function to be kept alive.
1248///
1249/// @param d the diff node to be kept alive during the life time of
1250/// the current instance of @ref diff_context.
1251void
1253{priv_->live_diffs_.insert(d);}
1254
1255/// Test if a diff node has been traversed.
1256///
1257/// @param d the diff node to consider.
1258///
1259/// @return the first diff node against which @p d is redundant.
1260diff*
1262{
1263 const diff* canonical = d->get_canonical_diff();
1264 ABG_ASSERT(canonical);
1265
1266 size_t ptr_value = reinterpret_cast<size_t>(canonical);
1267 pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
1268 if (it != priv_->visited_diff_nodes_.end())
1269 return reinterpret_cast<diff*>(it->second);
1270 else
1271 return 0;
1272}
1273
1274/// Test if a diff node has been traversed.
1275///
1276/// @param d the diff node to consider.
1277///
1278/// @return the first diff node against which @p d is redundant.
1281{
1283 return diff;
1284}
1285
1286/// Mark a diff node as traversed by a traversing algorithm.
1287///
1288/// Actually, it's the @ref CanonicalDiff "canonical diff" of this
1289/// node that is marked as traversed.
1290///
1291/// Subsequent invocations of diff_has_been_visited() on the diff node
1292/// will yield true.
1293void
1295{
1296 if (diff_has_been_visited(d))
1297 return;
1298
1299 const diff* canonical = d->get_canonical_diff();
1300 ABG_ASSERT(canonical);
1301
1302 size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
1303 size_t diff_ptr_value = reinterpret_cast<size_t>(d);
1304 priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
1305}
1306
1307/// Unmark all the diff nodes that were marked as being traversed.
1308void
1310{priv_->visited_diff_nodes_.clear();}
1311
1312/// This sets a flag that, if it's true, then during the traversing of
1313/// a diff nodes tree each node is visited at most once.
1314///
1315/// @param f if true then during the traversing of a diff nodes tree
1316/// each node is visited at most once.
1317///
1318void
1320{priv_->forbid_visiting_a_node_twice_ = f;}
1321
1322/// This function sets a flag os that if @ref
1323/// forbid_visiting_a_node_twice() returns true, then each time the
1324/// node visitor starts visiting a new interface, it resets the
1325/// memory the systems has about already visited node.
1326///
1327/// @param f the flag to set.
1328void
1330{priv_->reset_visited_diffs_for_each_interface_ = f;}
1331
1332/// Return a flag that, if true, then during the traversing of a diff
1333/// nodes tree each node is visited at most once.
1334///
1335/// @return the boolean flag.
1336bool
1338{return priv_->forbid_visiting_a_node_twice_;}
1339
1340/// Return a flag that, if true, then during the traversing of a diff
1341/// nodes tree each node is visited at most once, while visiting the
1342/// diff tree underneath a given interface (public function or
1343/// variable). Each time a new interface is visited, the nodes
1344/// visited while visiting previous interfaces can be visited again.
1345///
1346/// @return the boolean flag.
1347///
1348/// @return the boolean flag.
1349bool
1351{
1352 return (priv_->forbid_visiting_a_node_twice_
1353 && priv_->reset_visited_diffs_for_each_interface_);
1354}
1355
1356/// Getter for the diff tree nodes filters to apply to diff sub-trees.
1357///
1358/// @return the vector of tree filters to apply to diff sub-trees.
1359const filtering::filters&
1361{return priv_->filters_;}
1362
1363/// Setter for the diff filters to apply to a given diff sub-tree.
1364///
1365/// @param f the new diff filter to add to the vector of diff filters
1366/// to apply to diff sub-trees.
1367void
1369{priv_->filters_.push_back(f);}
1370
1371/// Apply the diff filters to a given diff sub-tree.
1372///
1373/// If the current context is instructed to filter out some categories
1374/// then this function walks the given sub-tree and categorizes its
1375/// nodes by using the filters held by the context.
1376///
1377/// @param diff the diff sub-tree to apply the filters to.
1378void
1380{
1381 if (!diff)
1382 return;
1383
1384 if (!diff->has_changes())
1385 return;
1386
1387 for (filtering::filters::const_iterator i = diff_filters().begin();
1388 i != diff_filters().end();
1389 ++i)
1390 {
1392 if (do_log())
1393 {
1394 std::cerr << "applying a filter to diff '"
1396 << "'...\n";
1397 t.start();
1398 }
1399
1401
1402 if (do_log())
1403 {
1404 t.stop();
1405 std::cerr << "filter applied!:" << t << "\n";
1406
1407 std::cerr << "propagating categories for the same diff node ... \n";
1408 t.start();
1409 }
1410
1412
1413 if (do_log())
1414 {
1415 t.stop();
1416 std::cerr << "category propagated!: " << t << "\n";
1417 }
1418 }
1419
1420 }
1421
1422/// Apply the diff filters to the diff nodes of a @ref corpus_diff
1423/// instance.
1424///
1425/// If the current context is instructed to filter out some categories
1426/// then this function walks the diff tree and categorizes its nodes
1427/// by using the filters held by the context.
1428///
1429/// @param diff the corpus diff to apply the filters to.
1430void
1432{
1433
1434 if (!diff || !diff->has_changes())
1435 return;
1436
1437 for (filtering::filters::const_iterator i = diff_filters().begin();
1438 i != diff_filters().end();
1439 ++i)
1440 {
1443 }
1444}
1445
1446/// Getter for the vector of suppressions that specify which diff node
1447/// reports should be dropped on the floor.
1448///
1449/// @return the set of suppressions.
1450const suppressions_type&
1452{return priv_->suppressions_;}
1453
1454/// Getter for the vector of suppressions that specify which diff node
1455/// reports should be dropped on the floor.
1456///
1457/// @return the set of suppressions.
1460{
1461 // Invalidate negated and direct suppressions caches that are built
1462 // from priv_->suppressions_;
1463 priv_->negated_suppressions_.clear();
1464 priv_->direct_suppressions_.clear();
1465 return priv_->suppressions_;
1466}
1467
1468/// Getter of the negated suppression specifications that are
1469/// comprised in the general vector of suppression specifications
1470/// returned by diff_context::suppressions().
1471///
1472/// Note that the first invocation of this function scans the vector
1473/// returned by diff_context::suppressions() and caches the negated
1474/// suppressions from there.
1475///
1476/// Subsequent invocations of this function just return the cached
1477/// negated suppressions.
1478///
1479/// @return the negated suppression specifications stored in this diff
1480/// context.
1483{
1484 if (priv_->negated_suppressions_.empty())
1485 for (auto s : suppressions())
1487 priv_->negated_suppressions_.push_back(s);
1488
1489 return priv_->negated_suppressions_;
1490}
1491
1492/// Getter of the direct suppression specification (those that are
1493/// not negated) comprised in the general vector of suppression
1494/// specifications returned by diff_context::suppression().
1495///
1496/// Note that the first invocation of this function scans the vector
1497/// returned by diff_context::suppressions() and caches the direct
1498/// suppressions from there.
1499///
1500/// Subsequent invocations of this function just return the cached
1501/// direct suppressions.
1502///
1503/// @return the direct suppression specifications.
1506{
1507 if (priv_->direct_suppressions_.empty())
1508 {
1509 for (auto s : suppressions())
1510 if (!is_negated_suppression(s))
1511 priv_->direct_suppressions_.push_back(s);
1512 }
1513 return priv_->direct_suppressions_;
1514}
1515
1516/// Add a new suppression specification that specifies which diff node
1517/// reports should be dropped on the floor.
1518///
1519/// @param suppr the new suppression specification to add to the
1520/// existing set of suppressions specifications of the diff context.
1521void
1523{
1524 priv_->suppressions_.push_back(suppr);
1525 // Invalidate negated and direct suppressions caches that are built
1526 // from priv_->suppressions_;
1527 priv_->negated_suppressions_.clear();
1528 priv_->direct_suppressions_.clear();
1529}
1530
1531/// Add new suppression specifications that specify which diff node
1532/// reports should be dropped on the floor.
1533///
1534/// @param supprs the new suppression specifications to add to the
1535/// existing set of suppression specifications of the diff context.
1536void
1538{
1539 priv_->suppressions_.insert(priv_->suppressions_.end(),
1540 supprs.begin(), supprs.end());
1541}
1542
1543/// Test if it's requested to perform diff node categorization.
1544///
1545/// @return true iff it's requested to perform diff node
1546/// categorization.
1547bool
1549{return priv_->perform_change_categorization_;}
1550
1551/// Request change categorization or not.
1552///
1553/// @param f true iff change categorization is requested.
1554void
1556{priv_->perform_change_categorization_ = f;}
1557
1558/// Set the flag that indicates if the diff using this context should
1559/// show only leaf changes or not.
1560///
1561/// @param f the new value of the flag that indicates if the diff
1562/// using this context should show only leaf changes or not.
1563void
1565{
1566 // This function can be called only if the reporter hasn't yet been
1567 // created. Once it's been created, we are supposed to live with
1568 // it.
1569 ABG_ASSERT(priv_->reporter_ == 0);
1570 priv_->leaf_changes_only_ = f;
1571}
1572
1573/// Get the flag that indicates if the diff using this context should
1574/// show only leaf changes or not.
1575///
1576/// @return the value of the flag that indicates if the diff using
1577/// this context should show only leaf changes or not.
1578bool
1580{return priv_->leaf_changes_only_;}
1581
1582/// Get the flag that indicates if the diff reports using this context
1583/// should show sizes and offsets in an hexadecimal base or not. If
1584/// not, then they are to be shown in a decimal base.
1585///
1586/// @return true iff sizes and offsets are to be shown in an
1587/// hexadecimal base.
1588bool
1590{return priv_->hex_values_;}
1591
1592/// Set the flag that indicates if diff reports using this context
1593/// should show sizes and offsets in an hexadecimal base or not. If
1594/// not, then they are to be shown in a decimal base.
1595///
1596/// @param f if true then sizes and offsets are to be shown in an
1597/// hexadecimal base.
1598void
1600{priv_->hex_values_ = f;}
1601
1602/// Get the flag that indicates if diff reports using this context
1603/// should show sizes and offsets in bits, rather than bytes.
1604///
1605/// @return true iff sizes and offsets are to be shown in bits.
1606/// Otherwise they are to be shown in bytes.
1607bool
1609{return priv_->show_offsets_sizes_in_bits_;}
1610
1611/// Set the flag that indicates if diff reports using this context
1612/// should show sizes and offsets in bits, rather than bytes.
1613///
1614/// @param f if true then sizes and offsets are to be shown in bits.
1615/// Otherwise they are to be shown in bytes.
1616void
1618{priv_->show_offsets_sizes_in_bits_ = f;}
1619
1620/// Set a flag saying if offset changes should be reported in a
1621/// relative way. That is, if the report should say how of many bits
1622/// a class/struct data member did move.
1623///
1624/// @param f the new boolean value of the flag.
1625void
1627{priv_->show_relative_offset_changes_ = f;}
1628
1629/// Get the flag saying if offset changes should be reported in a
1630/// relative way. That is, if the report should say how of many bits
1631/// a class/struct data member did move.
1632///
1633/// @return the boolean value of the flag.
1634bool
1636{return priv_->show_relative_offset_changes_;}
1637
1638/// Set a flag saying if the comparison module should only show the
1639/// diff stats.
1640///
1641/// @param f the flag to set.
1642void
1644{priv_->show_stats_only_ = f;}
1645
1646/// Test if the comparison module should only show the diff stats.
1647///
1648/// @return true if the comparison module should only show the diff
1649/// stats, false otherwise.
1650bool
1652{return priv_->show_stats_only_;}
1653
1654/// Setter for the property that says if the comparison module should
1655/// show the soname changes in its report.
1656///
1657/// @param f the new value of the property.
1658void
1660{priv_->show_soname_change_ = f;}
1661
1662/// Getter for the property that says if the comparison module should
1663/// show the soname changes in its report.
1664///
1665/// @return the value of the property.
1666bool
1668{return priv_->show_soname_change_;}
1669
1670/// Setter for the property that says if the comparison module should
1671/// show the architecture changes in its report.
1672///
1673/// @param f the new value of the property.
1674void
1676{priv_->show_architecture_change_ = f;}
1677
1678/// Getter for the property that says if the comparison module should
1679/// show the architecture changes in its report.
1680///
1681/// @return the value of the property.
1682bool
1684{return priv_->show_architecture_change_;}
1685
1686/// Set a flag saying to show the deleted functions.
1687///
1688/// @param f true to show deleted functions.
1689void
1691{priv_->show_deleted_fns_ = f;}
1692
1693/// @return true if we want to show the deleted functions, false
1694/// otherwise.
1695bool
1697{return priv_->show_deleted_fns_;}
1698
1699/// Set a flag saying to show the changed functions.
1700///
1701/// @param f true to show the changed functions.
1702void
1704{priv_->show_changed_fns_ = f;}
1705
1706/// @return true if we want to show the changed functions, false otherwise.
1707bool
1709{return priv_->show_changed_fns_;}
1710
1711/// Set a flag saying to show the added functions.
1712///
1713/// @param f true to show the added functions.
1714void
1716{priv_->show_added_fns_ = f;}
1717
1718/// @return true if we want to show the added functions, false
1719/// otherwise.
1720bool
1722{return priv_->show_added_fns_;}
1723
1724/// Set a flag saying to show the deleted variables.
1725///
1726/// @param f true to show the deleted variables.
1727void
1729{priv_->show_deleted_vars_ = f;}
1730
1731/// @return true if we want to show the deleted variables, false
1732/// otherwise.
1733bool
1735{return priv_->show_deleted_vars_;}
1736
1737/// Set a flag saying to show the changed variables.
1738///
1739/// @param f true to show the changed variables.
1740void
1742{priv_->show_changed_vars_ = f;}
1743
1744/// @return true if we want to show the changed variables, false otherwise.
1745bool
1747{return priv_->show_changed_vars_;}
1748
1749/// Set a flag saying to show the added variables.
1750///
1751/// @param f true to show the added variables.
1752void
1754{priv_->show_added_vars_ = f;}
1755
1756/// @return true if we want to show the added variables, false
1757/// otherwise.
1758bool
1760{return priv_->show_added_vars_;}
1761
1762bool
1763diff_context::show_linkage_names() const
1764{return priv_->show_linkage_names_;}
1765
1766void
1767diff_context::show_linkage_names(bool f)
1768{priv_->show_linkage_names_= f;}
1769
1770/// Set a flag saying to show location information.
1771///
1772/// @param f true to show location information.
1773void
1775{priv_->show_locs_= f;}
1776
1777/// @return true if we want to show location information, false
1778/// otherwise.
1779bool
1781{return priv_->show_locs_;}
1782
1783/// A getter for the flag that says if we should report about
1784/// functions or variables diff nodes that have *exclusively*
1785/// redundant diff tree children nodes.
1786///
1787/// @return the flag.
1788bool
1790{return priv_->show_redundant_changes_;}
1791
1792/// A setter for the flag that says if we should report about
1793/// functions or variables diff nodes that have *exclusively*
1794/// redundant diff tree children nodes.
1795///
1796/// @param f the flag to set.
1797void
1799{priv_->show_redundant_changes_ = f;}
1800
1801/// Getter for the flag that indicates if symbols not referenced by
1802/// any debug info are to be compared and reported about.
1803///
1804/// @return the boolean flag.
1805bool
1807{return priv_->show_syms_unreferenced_by_di_;}
1808
1809/// Setter for the flag that indicates if symbols not referenced by
1810/// any debug info are to be compared and reported about.
1811///
1812/// @param f the new flag to set.
1813void
1815{priv_->show_syms_unreferenced_by_di_ = f;}
1816
1817/// Getter for the flag that indicates if symbols not referenced by
1818/// any debug info and that got added are to be reported about.
1819///
1820/// @return true iff symbols not referenced by any debug info and that
1821/// got added are to be reported about.
1822bool
1824{return priv_->show_added_syms_unreferenced_by_di_;}
1825
1826/// Setter for the flag that indicates if symbols not referenced by
1827/// any debug info and that got added are to be reported about.
1828///
1829/// @param f the new flag that says if symbols not referenced by any
1830/// debug info and that got added are to be reported about.
1831void
1833{priv_->show_added_syms_unreferenced_by_di_ = f;}
1834
1835/// Setter for the flag that indicates if changes on types unreachable
1836/// from global functions and variables are to be reported.
1837///
1838/// @param f if true, then changes on types unreachable from global
1839/// functions and variables are to be reported.
1840void
1842{priv_->show_unreachable_types_ = f;}
1843
1844/// Getter for the flag that indicates if changes on types unreachable
1845/// from global functions and variables are to be reported.
1846///
1847/// @return true iff changes on types unreachable from global
1848/// functions and variables are to be reported.
1849bool
1851{return priv_->show_unreachable_types_;}
1852
1853/// Getter of the flag that indicates if the leaf reporter should
1854/// display a summary of the interfaces impacted by a given leaf
1855/// change or not.
1856///
1857/// @return the flag that indicates if the leaf reporter should
1858/// display a summary of the interfaces impacted by a given leaf
1859/// change or not.
1860bool
1862{return priv_->show_impacted_interfaces_;}
1863
1864/// Setter of the flag that indicates if the leaf reporter should
1865/// display a summary of the interfaces impacted by a given leaf
1866/// change or not.
1867///
1868/// @param f the new value of the flag that indicates if the leaf
1869/// reporter should display a summary of the interfaces impacted by a
1870/// given leaf change or not.
1871void
1873{priv_->show_impacted_interfaces_ = f;}
1874
1875/// Setter for the default output stream used by code of the
1876/// comparison engine. By default the default output stream is a NULL
1877/// pointer.
1878///
1879/// @param o a pointer to the default output stream.
1880void
1882{priv_->default_output_stream_ = o;}
1883
1884/// Getter for the default output stream used by code of the
1885/// comparison engine. By default the default output stream is a NULL
1886/// pointer.
1887///
1888/// @return a pointer to the default output stream.
1889ostream*
1891{return priv_->default_output_stream_;}
1892
1893/// Setter for the errror output stream used by code of the comparison
1894/// engine. By default the error output stream is a NULL pointer.
1895///
1896/// @param o a pointer to the error output stream.
1897void
1899{priv_->error_output_stream_ = o;}
1900
1901/// Getter for the errror output stream used by code of the comparison
1902/// engine. By default the error output stream is a NULL pointer.
1903///
1904/// @return a pointer to the error output stream.
1905ostream*
1907{return priv_->error_output_stream_;}
1908
1909/// Test if the comparison engine should dump the diff tree for the
1910/// changed functions and variables it has.
1911///
1912/// @return true if after the comparison, the engine should dump the
1913/// diff tree for the changed functions and variables it has.
1914bool
1916{return priv_->dump_diff_tree_;}
1917
1918/// Set if the comparison engine should dump the diff tree for the
1919/// changed functions and variables it has.
1920///
1921/// @param f true if after the comparison, the engine should dump the
1922/// diff tree for the changed functions and variables it has.
1923void
1925{priv_->dump_diff_tree_ = f;}
1926
1927/// Emit a textual representation of a diff tree to the error output
1928/// stream of the current context, for debugging purposes.
1929///
1930/// @param d the diff tree to serialize to the error output associated
1931/// to the current instance of @ref diff_context.
1932void
1934{
1935 if (error_output_stream())
1937}
1938
1939/// Emit a textual representation of a @ref corpus_diff tree to the error
1940/// output stream of the current context, for debugging purposes.
1941///
1942/// @param d the @ref corpus_diff tree to serialize to the error
1943/// output associated to the current instance of @ref diff_context.
1944void
1946{
1947 if (error_output_stream())
1949}
1950// </diff_context stuff>
1951
1952// <diff stuff>
1953
1954/// Constructor for the @ref diff type.
1955///
1956/// This constructs a diff between two subjects that are actually
1957/// declarations; the first and the second one.
1958///
1959/// @param first_subject the first decl (subject) of the diff.
1960///
1961/// @param second_subject the second decl (subject) of the diff.
1962diff::diff(type_or_decl_base_sptr first_subject,
1963 type_or_decl_base_sptr second_subject)
1964 : priv_(new priv(first_subject, second_subject,
1967 /*reported_once=*/false,
1968 /*currently_reporting=*/false))
1969{}
1970
1971/// Constructor for the @ref diff type.
1972///
1973/// This constructs a diff between two subjects that are actually
1974/// declarations; the first and the second one.
1975///
1976/// @param first_subject the first decl (subject) of the diff.
1977///
1978/// @param second_subject the second decl (subject) of the diff.
1979///
1980/// @param ctxt the context of the diff. Note that this context
1981/// object must stay alive during the entire life time of the current
1982/// instance of @ref diff. Otherwise, memory corruption issues occur.
1983diff::diff(type_or_decl_base_sptr first_subject,
1984 type_or_decl_base_sptr second_subject,
1985 diff_context_sptr ctxt)
1986 : priv_(new priv(first_subject, second_subject,
1987 ctxt, NO_CHANGE_CATEGORY,
1988 /*reported_once=*/false,
1989 /*currently_reporting=*/false))
1990{}
1991
1992/// Test if logging was requested
1993///
1994/// @return true iff logging was requested.
1995bool
1997{return context()->do_log();}
1998
1999/// Request logging (or not)
2000///
2001/// @param f true iff logging is to be requested.
2002void
2004{context()->do_log(f);}
2005
2006/// Flag a given diff node as being traversed.
2007///
2008/// For certain diff nodes like @ref class_diff, it's important to
2009/// avoid traversing the node again while it's already being
2010/// traversed; otherwise this leads to infinite loops. So the
2011/// diff::begin_traversing() and diff::end_traversing() methods flag a
2012/// given node as being traversed (or not), so that
2013/// diff::is_traversing() can tell if the node is being traversed.
2014///
2015/// Note that traversing a node means visiting it *and* visiting its
2016/// children nodes.
2017///
2018/// The canonical node is marked as being traversed too.
2019///
2020/// These functions are called by the traversing code.
2021void
2023{
2025 if (priv_->canonical_diff_)
2026 priv_->canonical_diff_->priv_->traversing_ = true;
2027 priv_->traversing_ = true;
2028}
2029
2030/// Tell if a given node is being traversed or not.
2031///
2032/// Note that traversing a node means visiting it *and* visiting its
2033/// children nodes.
2034///
2035/// It's the canonical node which is looked at, actually.
2036///
2037/// Please read the comments for the diff::begin_traversing() for mode
2038/// context.
2039///
2040/// @return true if the current instance of @diff is being traversed.
2041bool
2043{
2044 if (priv_->canonical_diff_)
2045 return priv_->canonical_diff_->priv_->traversing_;
2046 return priv_->traversing_;
2047}
2048
2049/// Flag a given diff node as not being traversed anymore.
2050///
2051/// Note that traversing a node means visiting it *and* visiting its
2052/// children nodes.
2053///
2054/// Please read the comments of the function diff::begin_traversing()
2055/// for mode context.
2056void
2058{
2060 if (priv_->canonical_diff_)
2061 priv_->canonical_diff_->priv_->traversing_ = false;
2062 priv_->traversing_ = false;
2063}
2064
2065/// Finish the insertion of a diff tree node into the diff graph.
2066///
2067/// This function might be called several times. It must perform the
2068/// insertion only once.
2069///
2070/// For instance, certain kinds of diff tree node have specific
2071/// children nodes that are populated after the constructor of the
2072/// diff tree node has been called. In that case, calling overloads
2073/// of this method ensures that these children nodes are properly
2074/// gathered and setup.
2075void
2077{
2078 if (diff::priv_->finished_)
2079 return;
2081 diff::priv_->finished_ = true;
2082}
2083
2084/// Getter of the first subject of the diff.
2085///
2086/// @return the first subject of the diff.
2089{return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
2090
2091/// Getter of the second subject of the diff.
2092///
2093/// @return the second subject of the diff.
2096{return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
2097
2098/// Getter for the children nodes of the current @ref diff node.
2099///
2100/// @return a vector of the children nodes.
2101const vector<diff*>&
2103{return priv_->children_;}
2104
2105/// Getter for the parent node of the current @ref diff node.
2106///
2107/// @return the parent node of the current @ref diff node.
2108const diff*
2110{return priv_->parent_;}
2111
2112/// Getter for the canonical diff of the current instance of @ref
2113/// diff.
2114///
2115/// Note that the canonical diff node for the current instanc eof diff
2116/// node must have been set by invoking
2117/// class_diff::initialize_canonical_diff() on the current instance of
2118/// diff node.
2119///
2120/// @return the canonical diff node or null if none was set.
2121diff*
2123{return priv_->canonical_diff_;}
2124
2125/// Setter for the canonical diff of the current instance of @ref
2126/// diff.
2127///
2128/// @param d the new canonical node to set.
2129void
2131{priv_->canonical_diff_ = d;}
2132
2133/// Add a new child node to the vector of children nodes for the
2134/// current @ref diff node.
2135///
2136/// @param d the new child node to add to the children nodes.
2137void
2139{
2140 ABG_ASSERT(d);
2141
2142 // Ensure 'd' is kept alive for the life time of the context of this
2143 // diff.
2144 context()->keep_diff_alive(d);
2145
2146 // Add the underlying pointer of 'd' to the vector of children.
2147 // Note that this vector holds no reference to 'd'. This is to avoid
2148 // reference cycles. The reference to 'd' is held by the context of
2149 // this diff, thanks to the call to context()->keep_diff_alive(d)
2150 // above.
2151 priv_->children_.push_back(d.get());
2152
2153 d->priv_->parent_ = this;
2154}
2155
2156/// Getter of the context of the current diff.
2157///
2158/// @return the context of the current diff.
2161{return priv_->get_context();}
2162
2163/// Setter of the context of the current diff.
2164///
2165/// @param c the new context to set.
2166void
2168{priv_->ctxt_ = c;}
2169
2170/// Tests if we are currently in the middle of emitting a report for
2171/// this diff.
2172///
2173/// @return true if we are currently emitting a report for the
2174/// current diff, false otherwise.
2175bool
2177{
2178 if (priv_->canonical_diff_)
2179 return priv_->canonical_diff_->priv_->currently_reporting_;
2180 return priv_->currently_reporting_;
2181}
2182
2183/// Sets a flag saying if we are currently in the middle of emitting
2184/// a report for this diff.
2185///
2186/// @param f true if we are currently emitting a report for the
2187/// current diff, false otherwise.
2188void
2190{
2191 if (priv_->canonical_diff_)
2192 priv_->canonical_diff_->priv_->currently_reporting_ = f;
2193 priv_->currently_reporting_ = f;
2194}
2195
2196/// Tests if a report has already been emitted for the current diff.
2197///
2198/// @return true if a report has already been emitted for the
2199/// current diff, false otherwise.
2200bool
2202{
2203 ABG_ASSERT(priv_->canonical_diff_);
2204 return priv_->canonical_diff_->priv_->reported_once_;
2205}
2206
2207/// The generic traversing code that walks a given diff sub-tree.
2208///
2209/// Note that there is a difference between traversing a diff node and
2210/// visiting it. Basically, traversing a diff node means visiting it
2211/// and visiting its children nodes too. So one can visit a node
2212/// without traversing it. But traversing a node without visiting it
2213/// is not possible.
2214///
2215/// Note that the insertion of the "generic view" of the diff node
2216/// into the graph being traversed is done "on the fly". The
2217/// insertion of the "typed view" of the diff node into the graph is
2218/// done implicitely. To learn more about the generic and typed view
2219/// of the diff node, please read the introductory comments of the
2220/// @ref diff class.
2221///
2222/// Note that by default this traversing code visits a given class of
2223/// equivalence of a diff node only once. This behaviour can been
2224/// changed by calling
2225/// diff_context::visiting_a_node_twice_is_forbidden(), but this is
2226/// very risky as it might create endless loops while visiting a diff
2227/// tree graph that has changes that refer to themselves; that is,
2228/// diff tree graphs with cycles.
2229///
2230/// When a diff node is encountered, the
2231/// diff_node_visitor::visit_begin() method is invoked on the diff
2232/// node first.
2233///
2234/// If the diff node has already been visited, then
2235/// node_visitor::visit_end() is called on it and the node traversing
2236/// is done; the children of the diff node are not visited in this
2237/// case.
2238///
2239/// If the diff node has *NOT* been visited yet, then the
2240/// diff_node_visitor::visit() method is invoked with it's 'pre'
2241/// argument set to true. Then if the diff_node_visitor::visit()
2242/// returns true, then the children nodes of the diff node are
2243/// visited. Otherwise, no children nodes of the diff node is
2244/// visited and the diff_node_visitor::visit_end() is called.
2245
2246/// After the children nodes are visited (and only if they are
2247/// visited) the diff_node_visitor::visit() method is invoked with
2248/// it's 'pre' argument set to false. And then the
2249/// diff_node_visitor::visit_end() is called.
2250///
2251/// @param v the entity that visits each node of the diff sub-tree.
2252///
2253/// @return true to tell the caller that all of the sub-tree could be
2254/// walked. This instructs the caller to keep walking the rest of the
2255/// tree. Return false otherwise.
2256bool
2258{
2259 // Insert the "generic view" of the diff node into its graph.
2261
2262 v.visit_begin(this);
2263
2264 bool already_visited = false;
2265 if (context()->visiting_a_node_twice_is_forbidden()
2266 && context()->diff_has_been_visited(this))
2267 already_visited = true;
2268
2269 bool mark_visited_nodes_as_traversed =
2271
2272 if (!already_visited && !v.visit(this, /*pre=*/true))
2273 {
2274 v.visit_end(this);
2275 if (mark_visited_nodes_as_traversed)
2276 context()->mark_diff_as_visited(this);
2277 return false;
2278 }
2279
2281 && !is_traversing()
2282 && !already_visited)
2283 {
2285 for (vector<diff*>::const_iterator i = children_nodes().begin();
2286 i != children_nodes().end();
2287 ++i)
2288 {
2289 if (!(*i)->traverse(v))
2290 {
2291 v.visit_end(this);
2292 if (mark_visited_nodes_as_traversed)
2293 context()->mark_diff_as_visited(this);
2295 return false;
2296 }
2297 }
2299 }
2300
2301 if (!v.visit(this, /*pref=*/false))
2302 {
2303 v.visit_end(this);
2304 if (mark_visited_nodes_as_traversed)
2305 context()->mark_diff_as_visited(this);
2306 return false;
2307 }
2308
2309 v.visit_end(this);
2310 if (!already_visited && mark_visited_nodes_as_traversed)
2311 context()->mark_diff_as_visited(this);
2312
2313 return true;
2314}
2315
2316/// Sets a flag saying if a report has already been emitted for the
2317/// current diff.
2318///
2319/// @param f true if a report has already been emitted for the
2320/// current diff, false otherwise.
2321void
2323{
2324 ABG_ASSERT(priv_->canonical_diff_);
2325 priv_->canonical_diff_->priv_->reported_once_ = f;
2326 priv_->reported_once_ = f;
2327}
2328
2329/// Getter for the local category of the current diff tree node.
2330///
2331/// The local category represents the set of categories of a diff
2332/// node, not taking in account the categories inherited from its
2333/// children nodes.
2334///
2335/// @return the local category of the current diff tree node.
2338{return priv_->local_category_;}
2339
2340/// Getter of the category of the class of equivalence of the current
2341/// diff tree node.
2342///
2343/// That is, if the current diff tree node has a canonical node,
2344/// return the category of that canonical node. Otherwise, return the
2345/// category of the current node.
2346///
2347/// @return the category of the class of equivalence of the current
2348/// tree node.
2351{
2352 diff* canonical = get_canonical_diff();
2353 return canonical ? canonical->get_category() : get_category();
2354}
2355
2356/// Getter for the category of the current diff tree node.
2357///
2358/// This category represents the union of the local category and the
2359/// categories inherited from the children diff nodes.
2360///
2361/// @return the category of the current diff tree node.
2364{return priv_->category_;}
2365
2366/// Adds the current diff tree node to an additional set of
2367/// categories. Note that the categories include thoses inherited
2368/// from the children nodes of this diff node.
2369///
2370/// @param c a bit-map representing the set of categories to add the
2371/// current diff tree node to.
2372///
2373/// @return the resulting bit-map representing the categories this
2374/// current diff tree node belongs to, including those inherited from
2375/// its children nodes.
2378{
2379 priv_->category_ = priv_->category_ | c;
2380 return priv_->category_;
2381}
2382
2383/// Adds the current diff tree node to the categories resulting from
2384/// the local changes of the current diff node.
2385///
2386/// @param c a bit-map representing the set of categories to add the
2387/// current diff tree node to.
2388///
2389/// @return the resulting bit-map representing the categories this
2390/// current diff tree node belongs to.
2393{
2394 priv_->local_category_ = priv_->local_category_ | c;
2395 return priv_->local_category_;
2396}
2397
2398/// Adds the current diff tree node to the categories resulting from
2399/// the local and inherited changes of the current diff node.
2400///
2401/// @param c a bit-map representing the set of categories to add the
2402/// current diff tree node to.
2403void
2405{
2407 add_to_category(c);
2408}
2409
2410/// Remove the current diff tree node from an a existing sef of
2411/// categories. The categories include those inherited from the
2412/// children nodes of the current diff node.
2413///
2414/// @param c a bit-map representing the set of categories to add the
2415/// current diff tree node to.
2416///
2417/// @return the resulting bit-map representing the categories this
2418/// current diff tree onde belongs to, including the categories
2419/// inherited from the children nodes of the current diff node.
2422{
2423 priv_->category_ = priv_->category_ & ~c;
2424 return priv_->category_;
2425}
2426
2427/// Remove the current diff tree node from the categories resulting
2428/// from the local changes.
2429///
2430/// @param c a bit-map representing the set of categories to add the
2431/// current diff tree node to.
2432///
2433/// @return the resulting bit-map representing the categories this
2434/// current diff tree onde belongs to.
2437{
2438 priv_->local_category_ = priv_->local_category_ & ~c;
2439 return priv_->local_category_;
2440}
2441
2442/// Set the category of the current @ref diff node. This category
2443/// includes the categories inherited from the children nodes of the
2444/// current diff node.
2445///
2446/// @param c the new category for the current diff node.
2447void
2449{priv_->category_ = c;}
2450
2451/// Set the local category of the current @ref diff node.
2452///
2453/// @param c the new category for the current diff node.
2454void
2456{priv_->local_category_ = c;}
2457
2458/// Test if this diff tree node is to be filtered out for reporting
2459/// purposes.
2460///
2461/// There is a difference between a diff node being filtered out and
2462/// being suppressed. Being suppressed means that there is a
2463/// suppression specification that suppresses the diff node
2464/// specifically. Being filtered out mean the node is either
2465/// suppressed, or it's filtered out because the suppression of a set
2466/// of (children) nodes caused this node to be filtered out as well.
2467/// For instance, if a function diff has all its children diff nodes
2468/// suppressed and if the function diff node carries no local change,
2469/// then the function diff node itself is going to be filtered out.
2470///
2471/// The function tests if the categories of the diff tree node are
2472/// "forbidden" by the context or not.
2473///
2474/// @return true iff the current diff node should NOT be reported.
2475bool
2477{
2478 if (diff * canonical = get_canonical_diff())
2479 if ((canonical->get_category() & SUPPRESSED_CATEGORY
2480 || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
2481 && !canonical->is_allowed_by_specific_negated_suppression()
2482 && !canonical->has_descendant_allowed_by_specific_negated_suppression()
2483 && !canonical->has_parent_allowed_by_specific_negated_suppression())
2484 // The canonical type was suppressed either by a user-provided
2485 // suppression specification or by a "private-type" suppression
2486 // specification.. This means all the classes of equivalence of
2487 // that canonical type were suppressed. So this node should be
2488 // filtered out.
2489 return true;
2490 return priv_->is_filtered_out(get_category());
2491}
2492
2493/// Test if this diff tree node is to be filtered out for reporting
2494/// purposes, but by considering only the categories that were *NOT*
2495/// inherited from its children nodes.
2496///
2497/// The function tests if the local categories of the diff tree node
2498/// are "forbidden" by the context or not.
2499///
2500/// @return true iff the current diff node should NOT be reported,
2501/// with respect to its local categories.
2502bool
2504{return priv_->is_filtered_out(get_local_category());}
2505
2506/// Test if this diff tree node is to be filtered out for reporting
2507/// purposes, but without considering the categories that can /force/
2508/// the node to be unfiltered.
2509///
2510/// The function tests if the categories of the diff tree node are
2511/// "forbidden" by the context or not.
2512///
2513/// @return true iff the current diff node should should NOT be
2514/// reported, with respect to the categories that might filter it out
2515/// only.
2516bool
2518{
2523
2524 return priv_->is_filtered_out(c);
2525}
2526
2527/// Test if the current diff node has been suppressed by a
2528/// user-provided suppression specification.
2529///
2530/// @return true if the current diff node has been suppressed by a
2531/// user-provided suppression list.
2532bool
2534{
2535 bool is_private = false;
2536 return is_suppressed(is_private);
2537}
2538
2539/// Test if the current diff node has been suppressed by a
2540/// user-provided suppression specification or by an auto-generated
2541/// "private type" suppression specification.
2542///
2543/// Note that private type suppressions are auto-generated from the
2544/// path to where public headers are, as given by the user.
2545///
2546/// Here is the current algorithm:
2547///
2548/// First, suppress this diff node if it's not matched by any
2549/// negated suppression specifications. If it's not
2550/// suppressed, then suppress it if it's matched by direct
2551/// suppression specifications.
2552///
2553/// @param is_private_type out parameter if the current diff node was
2554/// suppressed because it's a private type then this parameter is set
2555/// to true.
2556///
2557/// @return true if the current diff node has been suppressed by a
2558/// user-provided suppression list.
2559bool
2560diff::is_suppressed(bool &is_private_type) const
2561{
2562 // If there is at least one negated suppression, then suppress the
2563 // current diff node by default ...
2564 bool do_suppress = !context()->negated_suppressions().empty();
2565
2566 // ... unless there is at least one negated suppression that
2567 // specifically asks to keep this diff node around (un-suppressed).
2568 for (auto n : context()->negated_suppressions())
2569 if (!n->suppresses_diff(this))
2570 {
2571 do_suppress = false;
2572 break;
2573 }
2574
2575 // Then walk the set of non-negated, AKA direct, suppressions. If at
2576 // least one suppression suppresses the current diff node then the
2577 // diff node must be suppressed.
2578 for (auto d : context()->direct_suppressions())
2579 if (d->suppresses_diff(this))
2580 {
2581 do_suppress = true;
2583 is_private_type = true;
2584 break;
2585 }
2586
2587 return do_suppress;
2588}
2589
2590/// Test if this diff tree node should be reported.
2591///
2592/// @return true iff the current node should be reported.
2593bool
2595{
2596 if (has_changes() && !is_filtered_out())
2597 return true;
2598 return false;
2599}
2600
2601/// Test if this diff tree node should be reported when considering
2602/// the categories that were *NOT* inherited from its children nodes.
2603///
2604/// @return true iff the current node should be reported.
2605bool
2607{
2608 if (has_local_changes()
2610 return true;
2611 return false;
2612}
2613
2614/// Test if this diff node is allowed (prevented from being
2615/// suppressed) by at least one negated suppression specification.
2616///
2617/// @return true if this diff node is meant to be allowed by at least
2618/// one negated suppression specification.
2619bool
2621{
2622 const suppressions_type& suppressions = context()->suppressions();
2623 for (suppressions_type::const_iterator i = suppressions.begin();
2624 i != suppressions.end();
2625 ++i)
2626 {
2628 && !(*i)->suppresses_diff(this))
2629 return true;
2630 }
2631 return false;
2632}
2633
2634/// Test if the current diff node has a descendant node which is
2635/// specifically allowed by a negated suppression specification.
2636///
2637/// @return true iff the current diff node has a descendant node
2638/// which is specifically allowed by a negated suppression
2639/// specification.
2640bool
2642{
2644 return result;
2645}
2646
2647/// Test if the current diff node has a parent node which is
2648/// specifically allowed by a negated suppression specification.
2649///
2650/// @return true iff the current diff node has a parent node which is
2651/// specifically allowed by a negated suppression specification.
2652bool
2654{
2656 return result;
2657}
2658
2659/// Get a pretty representation of the current @ref diff node.
2660///
2661/// This is suitable for e.g. emitting debugging traces for the diff
2662/// tree nodes.
2663///
2664/// @return the pretty representation of the diff node.
2665const string&
2667{
2668 if (priv_->pretty_representation_.empty())
2669 priv_->pretty_representation_ = "empty_diff";
2670 return priv_->pretty_representation_;
2671}
2672
2673/// Default implementation of the hierachy chaining virtual function.
2674///
2675/// There are several types of diff nodes that have logical children
2676/// nodes; for instance, a typedef_diff has the diff of the underlying
2677/// type as a child node. A var_diff has the diff of the types of the
2678/// variables as a child node, etc.
2679///
2680/// But because the @ref diff base has a generic representation for
2681/// children nodes of the all the types of @ref diff nodes (regardless
2682/// of the specific most-derived type of diff node) that one can get
2683/// using the method diff::children_nodes(), one need to populate that
2684/// vector of children node.
2685///
2686/// Populating that vector of children node is done by this function;
2687/// it must be overloaded by each most-derived type of diff node that
2688/// extends the @ref diff type.
2689void
2691{}
2692
2693// </diff stuff>
2694
2695// <type_diff_base stuff>
2696
2697type_diff_base::type_diff_base(type_base_sptr first_subject,
2698 type_base_sptr second_subject,
2699 diff_context_sptr ctxt)
2700 : diff(first_subject, second_subject, ctxt),
2701 priv_(new priv)
2702{}
2703
2704type_diff_base::~type_diff_base()
2705{}
2706// </type_diff_base stuff>
2707
2708// <decl_diff_base stuff>
2709
2710/// Constructor of @ref decl_diff_base.
2711///
2712/// @param first_subject the first subject of the diff.
2713///
2714/// @param second_subject the second subject of the diff.
2715///
2716/// @param ctxt the context of the diff. This object must stay alive
2717/// at least during the life time of the current instance of @ref
2718/// decl_diff_base, otherwise, memory corruption issues occur.
2719decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
2720 decl_base_sptr second_subject,
2721 diff_context_sptr ctxt)
2722 : diff(first_subject, second_subject, ctxt),
2723 priv_(new priv)
2724{}
2725
2726decl_diff_base::~decl_diff_base()
2727{}
2728
2729// </decl_diff_base stuff>
2730
2731// <distinct_diff stuff>
2732
2733/// @return a pretty representation for the @ref distinct_diff node.
2734const string&
2736{
2737 if (diff::priv_->pretty_representation_.empty())
2738 {
2739 std::ostringstream o;
2740 o << "distinct_diff[";
2741 if (first_subject())
2742 o << first_subject()->get_pretty_representation();
2743 else
2744 o << "null";
2745 o << ", ";
2746 if (second_subject())
2747 o << second_subject()->get_pretty_representation() ;
2748 else
2749 o << "null";
2750 o << "]" ;
2751 diff::priv_->pretty_representation_ = o.str();
2752 }
2753 return diff::priv_->pretty_representation_;
2754}
2755
2756/// Populate the vector of children node of the @ref diff base type
2757/// sub-object of this instance of @distinct_diff.
2758///
2759/// The children nodes can then later be retrieved using
2760/// diff::children_nodes().
2761void
2763{
2765
2768}
2769
2770/// Constructor for @ref distinct_diff.
2771///
2772/// Note that the two entities considered for the diff (and passed in
2773/// parameter) must be of different kinds.
2774///
2775/// @param first the first entity to consider for the diff.
2776///
2777/// @param second the second entity to consider for the diff.
2778///
2779/// @param ctxt the context of the diff. Note that this context
2780/// object must stay alive at least during the life time of the
2781/// current instance of @ref distinct_diff. Otherwise memory
2782/// corruption issues occur.
2785 diff_context_sptr ctxt)
2786 : diff(first, second, ctxt),
2787 priv_(new priv)
2789
2790/// Getter for the first subject of the diff.
2791///
2792/// @return the first subject of the diff.
2795{return first_subject();}
2796
2797/// Getter for the second subject of the diff.
2798///
2799/// @return the second subject of the diff.
2802{return second_subject();}
2803
2804/// Getter for the child diff of this distinct_diff instance.
2805///
2806/// When a distinct_diff has two subjects that are different but
2807/// compatible, then the distinct_diff instance has a child diff node
2808/// (named the compatible child diff) that is the diff between the two
2809/// subjects stripped from their typedefs. Otherwise, the compatible
2810/// child diff is nul.
2811///
2812/// Note that two diff subjects (that compare different) are
2813/// considered compatible if stripping typedefs out of them makes them
2814/// comparing equal.
2815///
2816/// @return the compatible child diff node, if any. Otherwise, null.
2817const diff_sptr
2819{
2820 if (!priv_->compatible_child_diff)
2821 {
2822 type_base_sptr fs = strip_typedef(is_type(first())),
2823 ss = strip_typedef(is_type(second()));
2824
2825 if (fs && ss
2828 priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
2830 context());
2831 }
2832 return priv_->compatible_child_diff;
2833}
2834
2835/// Test if the two arguments are of different kind, or that are both
2836/// NULL.
2837///
2838/// @param first the first argument to test for similarity in kind.
2839///
2840/// @param second the second argument to test for similarity in kind.
2841///
2842/// @return true iff the two arguments are of different kind.
2843bool
2846{
2847 if (!!first != !!second)
2848 return true;
2849 if (!first && !second)
2850 // We do consider diffs of two empty decls as a diff of distinct
2851 // kinds, for now.
2852 return true;
2853 if (first == second)
2854 return false;
2855
2856 const type_or_decl_base &f = *first, &s = *second;
2857 return typeid(f) != typeid(s);
2858}
2859
2860/// @return true if the two subjects of the diff are different, false
2861/// otherwise.
2862bool
2864{return first() != second();}
2865
2866/// @return the kind of local change carried by the current diff node.
2867/// The value returned is zero if the current node carries no local
2868/// change.
2869enum change_kind
2871{
2872 // Changes on a distinct_diff are all local.
2873 if (has_changes())
2875 return NO_CHANGE_KIND;
2876}
2877
2878/// Emit a report about the current diff instance.
2879///
2880/// @param out the output stream to send the diff report to.
2881///
2882/// @param indent the indentation string to use in the report.
2883void
2884distinct_diff::report(ostream& out, const string& indent) const
2885{
2886 context()->get_reporter()->report(*this, out, indent);
2887}
2888
2889/// Try to diff entities that are of distinct kinds.
2890///
2891/// @param first the first entity to consider for the diff.
2892///
2893/// @param second the second entity to consider for the diff.
2894///
2895/// @param ctxt the context of the diff.
2896///
2897/// @return a non-null diff if a diff object could be built, null
2898/// otherwise.
2901 const type_or_decl_base_sptr second,
2902 diff_context_sptr ctxt)
2903{
2905 return distinct_diff_sptr();
2906
2907 distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
2908
2909 ctxt->initialize_canonical_diff(result);
2910
2911 return result;
2912}
2913
2914/// </distinct_diff stuff>
2915
2916/// Try to compute a diff on two instances of DiffType representation.
2917///
2918/// The function template performs the diff if and only if the decl
2919/// representations are of a DiffType.
2920///
2921/// @tparm DiffType the type of instances to diff.
2922///
2923/// @param first the first representation of decl to consider in the
2924/// diff computation.
2925///
2926/// @param second the second representation of decl to consider in the
2927/// diff computation.
2928///
2929/// @param ctxt the diff context to use.
2930///
2931///@return the diff of the two types @p first and @p second if and
2932///only if they represent the parametrized type DiffType. Otherwise,
2933///returns a NULL pointer value.
2934template<typename DiffType>
2937 const type_or_decl_base_sptr second,
2938 diff_context_sptr ctxt)
2939{
2940 if (shared_ptr<DiffType> f =
2941 dynamic_pointer_cast<DiffType>(first))
2942 {
2943 shared_ptr<DiffType> s =
2944 dynamic_pointer_cast<DiffType>(second);
2945 if (!s)
2946 return diff_sptr();
2947 return compute_diff(f, s, ctxt);
2948 }
2949 return diff_sptr();
2950}
2951
2952
2953/// This is a specialization of @ref try_to_diff() template to diff
2954/// instances of @ref class_decl.
2955///
2956/// @param first the first representation of decl to consider in the
2957/// diff computation.
2958///
2959/// @param second the second representation of decl to consider in the
2960/// diff computation.
2961///
2962/// @param ctxt the diff context to use.
2963template<>
2966 const type_or_decl_base_sptr second,
2967 diff_context_sptr ctxt)
2968{
2969 if (class_decl_sptr f =
2970 dynamic_pointer_cast<class_decl>(first))
2971 {
2972 class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
2973 if (!s)
2974 return diff_sptr();
2975
2976 if (f->get_is_declaration_only())
2977 {
2978 class_decl_sptr f2 =
2979 is_class_type (f->get_definition_of_declaration());
2980 if (f2)
2981 f = f2;
2982 }
2983 if (s->get_is_declaration_only())
2984 {
2985 class_decl_sptr s2 =
2986 is_class_type(s->get_definition_of_declaration());
2987 if (s2)
2988 s = s2;
2989 }
2990 return compute_diff(f, s, ctxt);
2991 }
2992 return diff_sptr();
2993}
2994
2995/// Try to diff entities that are of distinct kinds.
2996///
2997/// @param first the first entity to consider for the diff.
2998///
2999/// @param second the second entity to consider for the diff.
3000///
3001/// @param ctxt the context of the diff.
3002///
3003/// @return a non-null diff if a diff object could be built, null
3004/// otherwise.
3005static diff_sptr
3006try_to_diff_distinct_kinds(const type_or_decl_base_sptr first,
3007 const type_or_decl_base_sptr second,
3008 diff_context_sptr ctxt)
3009{return compute_diff_for_distinct_kinds(first, second, ctxt);}
3010
3011/// Compute the difference between two types.
3012///
3013/// The function considers every possible types known to libabigail
3014/// and runs the appropriate diff function on them.
3015///
3016/// Whenever a new kind of type decl is supported by abigail, if we
3017/// want to be able to diff two instances of it, we need to update
3018/// this function to support it.
3019///
3020/// @param first the first type decl to consider for the diff
3021///
3022/// @param second the second type decl to consider for the diff.
3023///
3024/// @param ctxt the diff context to use.
3025///
3026/// @return the resulting diff. It's a pointer to a descendent of
3027/// abigail::comparison::diff.
3028static diff_sptr
3029compute_diff_for_types(const type_or_decl_base_sptr& first,
3030 const type_or_decl_base_sptr& second,
3031 const diff_context_sptr& ctxt)
3032{
3033 type_or_decl_base_sptr f = first;
3034 type_or_decl_base_sptr s = second;
3035
3036 diff_sptr d;
3037
3038 ((d = try_to_diff<type_decl>(f, s, ctxt))
3039 ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
3040 ||(d = try_to_diff<union_decl>(f, s,ctxt))
3041 ||(d = try_to_diff<class_decl>(f, s,ctxt))
3042 ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
3043 ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
3044 ||(d = try_to_diff<ptr_to_mbr_type>(f, s, ctxt))
3045 ||(d = try_to_diff<array_type_def::subrange_type>(f, s, ctxt))
3046 ||(d = try_to_diff<array_type_def>(f, s, ctxt))
3047 ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
3048 ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
3049 ||(d = try_to_diff<function_type>(f, s, ctxt))
3050 ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
3051
3052 ABG_ASSERT(d);
3053
3054 return d;
3055}
3056
3059{return static_cast<diff_category>(static_cast<unsigned>(c1)
3060 | static_cast<unsigned>(c2));}
3061
3063operator|=(diff_category& c1, diff_category c2)
3064{
3065 c1 = c1 | c2;
3066 return c1;
3067}
3068
3070operator&=(diff_category& c1, diff_category c2)
3071{
3072 c1 = c1 & c2;
3073 return c1;
3074}
3075
3077operator^(diff_category c1, diff_category c2)
3078{return static_cast<diff_category>(static_cast<unsigned>(c1)
3079 ^ static_cast<unsigned>(c2));}
3080
3083{return static_cast<diff_category>(static_cast<unsigned>(c1)
3084 & static_cast<unsigned>(c2));}
3085
3088{return static_cast<diff_category>(~static_cast<unsigned>(c));}
3089
3090
3091/// Getter of a bitmap made of the set of change categories that are
3092/// considered harmless.
3093///
3094/// @return the bitmap made of the set of change categories that are
3095/// considered harmless.
3098{
3115}
3116
3117/// Getter of a bitmap made of the set of change categories that are
3118/// considered harmful.
3119///
3120/// @return the bitmap made of the set of change categories that are
3121/// considered harmful.
3124{
3128}
3129
3130/// Serialize an instance of @ref diff_category to an output stream.
3131///
3132/// @param o the output stream to serialize @p c to.
3133///
3134/// @param c the instance of diff_category to serialize.
3135///
3136/// @return the output stream to serialize @p c to.
3137ostream&
3138operator<<(ostream& o, diff_category c)
3139{
3140 bool emitted_a_category = false;
3141
3142 if (c == NO_CHANGE_CATEGORY)
3143 {
3144 o << "NO_CHANGE_CATEGORY";
3145 emitted_a_category = true;
3146 }
3147
3148 if (c & ACCESS_CHANGE_CATEGORY)
3149 {
3150 if (emitted_a_category)
3151 o << "|";
3152 o << "ACCESS_CHANGE_CATEGORY";
3153 emitted_a_category |= true;
3154 }
3155
3157 {
3158 if (emitted_a_category)
3159 o << "|";
3160 o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
3161 emitted_a_category |= true;
3162 }
3163
3165 {
3166 if (emitted_a_category)
3167 o << "|";
3168 o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
3169 emitted_a_category |= true;
3170 }
3171
3173 {
3174 if (emitted_a_category)
3175 o << "|";
3176 o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
3177 emitted_a_category |= true;
3178 }
3179
3181 {
3182 if (emitted_a_category)
3183 o << "|";
3184 o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
3185 emitted_a_category |= true;
3186 }
3187
3189 {
3190 if (emitted_a_category)
3191 o << "|";
3192 o << "HARMLESS_ENUM_CHANGE_CATEGORY";
3193 emitted_a_category |= true;
3194 }
3195
3197 {
3198 if (emitted_a_category)
3199 o << "|";
3200 o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
3201 emitted_a_category |= true;
3202 }
3203
3205 {
3206 if (emitted_a_category)
3207 o << "|";
3208 o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY";
3209 emitted_a_category |= true;
3210 }
3211
3213 {
3214 if (emitted_a_category)
3215 o << "|";
3216 o << "HARMLESS_UNION_CHANGE_CATEGORY";
3217 emitted_a_category |= true;
3218 }
3219
3220 if (c & SUPPRESSED_CATEGORY)
3221 {
3222 if (emitted_a_category)
3223 o << "|";
3224 o << "SUPPRESSED_CATEGORY";
3225 emitted_a_category |= true;
3226 }
3227
3228 if (c & PRIVATE_TYPE_CATEGORY)
3229 {
3230 if (emitted_a_category)
3231 o << "|";
3232 o << "PRIVATE_TYPE_CATEGORY";
3233 emitted_a_category |= true;
3234 }
3235
3237 {
3238 if (emitted_a_category)
3239 o << "|";
3240 o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
3241 emitted_a_category |= true;
3242 }
3243
3245 {
3246 if (emitted_a_category)
3247 o << "|";
3248 o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
3249 emitted_a_category |= true;
3250 }
3251
3252 if (c & REDUNDANT_CATEGORY)
3253 {
3254 if (emitted_a_category)
3255 o << "|";
3256 o << "REDUNDANT_CATEGORY";
3257 emitted_a_category |= true;
3258 }
3259
3261 {
3262 if (emitted_a_category)
3263 o << "|";
3264 o << "TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY";
3265 emitted_a_category |= true;
3266 }
3267
3269 {
3270 if (emitted_a_category)
3271 o << "|";
3272 o << "FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY";
3273 emitted_a_category |= true;
3274 }
3275
3277 {
3278 if (emitted_a_category)
3279 o << "|";
3280 o << "FN_PARM_TYPE_CV_CHANGE_CATEGORY";
3281 emitted_a_category |= true;
3282 }
3283
3285 {
3286 if (emitted_a_category)
3287 o << "|";
3288 o << "FN_RETURN_TYPE_CV_CHANGE_CATEGORY";
3289 emitted_a_category |= true;
3290 }
3291
3293 {
3294 if (emitted_a_category)
3295 o << "|";
3296 o << "FN_PARM_ADD_REMOVE_CHANGE_CATEGORY";
3297 emitted_a_category |= true;
3298 }
3299
3301 {
3302 if (emitted_a_category)
3303 o << "|";
3304 o << "VAR_TYPE_CV_CHANGE_CATEGORY";
3305 emitted_a_category |= true;
3306 }
3307
3309 {
3310 if (emitted_a_category)
3311 o << "|";
3312 o << "VOID_PTR_TO_PTR_CHANGE_CATEGORY";
3313 emitted_a_category |= true;
3314 }
3315
3317 {
3318 if (emitted_a_category)
3319 o << "|";
3320 o << "BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY";
3321 emitted_a_category |= true;
3322 }
3323
3325 {
3326 if (emitted_a_category)
3327 o << "|";
3328 o << "HAS_ALLOWED_CHANGE_CATEGORY";
3329 emitted_a_category |= true;
3330 }
3331
3333 {
3334 if (emitted_a_category)
3335 o << "|";
3336 o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
3337 emitted_a_category |= true;
3338 }
3339
3341 {
3342 if (emitted_a_category)
3343 o << "|";
3344 o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
3345 emitted_a_category |= true;
3346 }
3347
3348 return o;
3349}
3350
3351/// Compute the difference between two decls.
3352///
3353/// The function consider every possible decls known to libabigail and
3354/// runs the appropriate diff function on them.
3355///
3356/// Whenever a new kind of non-type decl is supported by abigail, if
3357/// we want to be able to diff two instances of it, we need to update
3358/// this function to support it.
3359///
3360/// @param first the first decl to consider for the diff
3361///
3362/// @param second the second decl to consider for the diff.
3363///
3364/// @param ctxt the diff context to use.
3365///
3366/// @return the resulting diff.
3367static diff_sptr
3368compute_diff_for_decls(const decl_base_sptr first,
3369 const decl_base_sptr second,
3370 diff_context_sptr ctxt)
3371{
3372
3373 diff_sptr d;
3374
3375 ((d = try_to_diff<function_decl>(first, second, ctxt))
3376 || (d = try_to_diff<var_decl>(first, second, ctxt))
3377 || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
3378
3379 ABG_ASSERT(d);
3380
3381 return d;
3382}
3383
3384/// Compute the difference between two decls. The decls can represent
3385/// either type declarations, or non-type declaration.
3386///
3387/// Note that the two decls must have been created in the same @ref
3388/// environment, otherwise, this function aborts.
3389///
3390/// @param first the first decl to consider.
3391///
3392/// @param second the second decl to consider.
3393///
3394/// @param ctxt the diff context to use.
3395///
3396/// @return the resulting diff, or NULL if the diff could not be
3397/// computed.
3399compute_diff(const decl_base_sptr first,
3400 const decl_base_sptr second,
3401 diff_context_sptr ctxt)
3402{
3403 if (!first || !second)
3404 return diff_sptr();
3405
3406 diff_sptr d;
3407 if (is_type(first) && is_type(second))
3408 d = compute_diff_for_types(first, second, ctxt);
3409 else
3410 d = compute_diff_for_decls(first, second, ctxt);
3411 ABG_ASSERT(d);
3412 return d;
3413}
3414
3415/// Compute the difference between two types.
3416///
3417/// Note that the two types must have been created in the same @ref
3418/// environment, otherwise, this function aborts.
3419///
3420/// @param first the first type to consider.
3421///
3422/// @param second the second type to consider.
3423///
3424/// @param ctxt the diff context to use.
3425///
3426/// @return the resulting diff, or NULL if the diff couldn't be
3427/// computed.
3429compute_diff(const type_base_sptr first,
3430 const type_base_sptr second,
3431 diff_context_sptr ctxt)
3432{
3433 decl_base_sptr f = get_type_declaration(first),
3434 s = get_type_declaration(second);
3435
3436 diff_sptr d = compute_diff_for_types(f,s, ctxt);
3437 ABG_ASSERT(d);
3438 return d;
3439}
3440
3441/// Get a copy of the pretty representation of a diff node.
3442///
3443/// @param d the diff node to consider.
3444///
3445/// @return the pretty representation string.
3446string
3448{
3449 if (!d)
3450 return "";
3451 string prefix= "diff of ";
3452 return prefix + get_pretty_representation(d->first_subject());
3453}
3454
3455// <var_diff stuff>
3456
3457/// Populate the vector of children node of the @ref diff base type
3458/// sub-object of this instance of @ref var_diff.
3459///
3460/// The children node can then later be retrieved using
3461/// diff::children_node().
3462void
3465
3466/// @return the pretty representation for this current instance of
3467/// @ref var_diff.
3468const string&
3470{
3471 if (diff::priv_->pretty_representation_.empty())
3472 {
3473 std::ostringstream o;
3474 o << "var_diff["
3475 << first_subject()->get_pretty_representation()
3476 << ", "
3477 << second_subject()->get_pretty_representation()
3478 << "]";
3479 diff::priv_->pretty_representation_ = o.str();
3480 }
3481 return diff::priv_->pretty_representation_;
3482}
3483/// Constructor for @ref var_diff.
3484///
3485/// @param first the first instance of @ref var_decl to consider in
3486/// the diff.
3487///
3488/// @param second the second instance of @ref var_decl to consider in
3489/// the diff.
3490///
3491/// @param type_diff the diff between types of the instances of
3492/// var_decl.
3493///
3494/// @param ctxt the diff context to use.
3496 var_decl_sptr second,
3497 diff_sptr type_diff,
3498 diff_context_sptr ctxt)
3499 : decl_diff_base(first, second, ctxt),
3500 priv_(new priv)
3501{priv_->type_diff_ = type_diff;}
3502
3503/// Getter for the first @ref var_decl of the diff.
3504///
3505/// @return the first @ref var_decl of the diff.
3508{return dynamic_pointer_cast<var_decl>(first_subject());}
3509
3510/// Getter for the second @ref var_decl of the diff.
3511///
3512/// @return the second @ref var_decl of the diff.
3515{return dynamic_pointer_cast<var_decl>(second_subject());}
3516
3517/// Getter for the diff of the types of the instances of @ref
3518/// var_decl.
3519///
3520/// @return the diff of the types of the instances of @ref var_decl.
3523{
3524 if (diff_sptr result = priv_->type_diff_.lock())
3525 return result;
3526 else
3527 {
3528 result = compute_diff(first_var()->get_type(),
3529 second_var()->get_type(),
3530 context());
3531 context()->keep_diff_alive(result);
3532 priv_->type_diff_ = result;
3533 return result;
3534 }
3535}
3536
3537/// Return true iff the diff node has a change.
3538///
3539/// @return true iff the diff node has a change.
3540bool
3542{return *first_var() != *second_var();}
3543
3544/// @return the kind of local change carried by the current diff node.
3545/// The value returned is zero if the current node carries no local
3546/// change.
3547enum change_kind
3549{
3550 ir::change_kind k = ir::NO_CHANGE_KIND;
3551 if (!equals(*first_var(), *second_var(), &k))
3552 return k & ir::ALL_LOCAL_CHANGES_MASK;
3553 return ir::NO_CHANGE_KIND;
3554}
3555
3556/// Report the diff in a serialized form.
3557///
3558/// @param out the stream to serialize the diff to.
3559///
3560/// @param indent the prefix to use for the indentation of this
3561/// serialization.
3562void
3563var_diff::report(ostream& out, const string& indent) const
3564{
3565 context()->get_reporter()->report(*this, out, indent);
3566}
3567
3568/// Compute the diff between two instances of @ref var_decl.
3569///
3570/// Note that the two decls must have been created in the same @ref
3571/// environment, otherwise, this function aborts.
3572///
3573/// @param first the first @ref var_decl to consider for the diff.
3574///
3575/// @param second the second @ref var_decl to consider for the diff.
3576///
3577/// @param ctxt the diff context to use.
3578///
3579/// @return the resulting diff between the two @ref var_decl.
3582 const var_decl_sptr second,
3583 diff_context_sptr ctxt)
3584{
3585 var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
3586 ctxt->initialize_canonical_diff(d);
3587
3588 return d;
3589}
3590
3591// </var_diff stuff>
3592
3593// <pointer_type_def stuff>
3594
3595/// Populate the vector of children node of the @ref diff base type
3596/// sub-object of this instance of @ref pointer_diff.
3597///
3598/// The children node can then later be retrieved using
3599/// diff::children_node().
3600void
3603
3604/// Constructor for a pointer_diff.
3605///
3606/// @param first the first pointer to consider for the diff.
3607///
3608/// @param second the secon pointer to consider for the diff.
3609///
3610/// @param ctxt the diff context to use.
3612 pointer_type_def_sptr second,
3613 diff_sptr underlying,
3614 diff_context_sptr ctxt)
3615 : type_diff_base(first, second, ctxt),
3616 priv_(new priv(underlying))
3617{}
3618
3619/// Getter for the first subject of a pointer diff
3620///
3621/// @return the first pointer considered in this pointer diff.
3624{return dynamic_pointer_cast<pointer_type_def>(first_subject());}
3625
3626/// Getter for the second subject of a pointer diff
3627///
3628/// @return the second pointer considered in this pointer diff.
3631{return dynamic_pointer_cast<pointer_type_def>(second_subject());}
3632
3633/// @return the pretty represenation for the current instance of @ref
3634/// pointer_diff.
3635const string&
3637{
3638 if (diff::priv_->pretty_representation_.empty())
3639 {
3640 std::ostringstream o;
3641 o << "pointer_diff["
3642 << first_subject()->get_pretty_representation()
3643 << ", "
3644 << second_subject()->get_pretty_representation()
3645 << "]";
3646 diff::priv_->pretty_representation_ = o.str();
3647 }
3648 return diff::priv_->pretty_representation_;
3649}
3650
3651/// Return true iff the current diff node carries a change.
3652///
3653/// @return true iff the current diff node carries a change.
3654bool
3656{return first_pointer() != second_pointer();}
3657
3658/// @return the kind of local change carried by the current diff node.
3659/// The value returned is zero if the current node carries no local
3660/// change.
3661enum change_kind
3663{
3664 ir::change_kind k = ir::NO_CHANGE_KIND;
3665 if (!equals(*first_pointer(), *second_pointer(), &k))
3666 return k & ir::ALL_LOCAL_CHANGES_MASK;
3667 return ir::NO_CHANGE_KIND;
3668}
3669
3670/// Getter for the diff between the pointed-to types of the pointers
3671/// of this diff.
3672///
3673/// @return the diff between the pointed-to types.
3676{return priv_->underlying_type_diff_;}
3677
3678/// Setter for the diff between the pointed-to types of the pointers
3679/// of this diff.
3680///
3681/// @param d the new diff between the pointed-to types of the pointers
3682/// of this diff.
3683void
3685{priv_->underlying_type_diff_ = d;}
3686
3687/// Report the diff in a serialized form.
3688///
3689/// @param out the stream to serialize the diff to.
3690///
3691/// @param indent the prefix to use for the indentation of this
3692/// serialization.
3693void
3694pointer_diff::report(ostream& out, const string& indent) const
3695{
3696 context()->get_reporter()->report(*this, out, indent);
3697}
3698
3699/// Compute the diff between between two pointers.
3700///
3701/// Note that the two types must have been created in the same @ref
3702/// environment, otherwise, this function aborts.
3703///
3704/// @param first the pointer to consider for the diff.
3705///
3706/// @param second the pointer to consider for the diff.
3707///
3708/// @return the resulting diff between the two pointers.
3709///
3710/// @param ctxt the diff context to use.
3713 pointer_type_def_sptr second,
3714 diff_context_sptr ctxt)
3715{
3716 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
3717 second->get_pointed_to_type(),
3718 ctxt);
3719 pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
3720 ctxt->initialize_canonical_diff(result);
3721
3722 return result;
3723}
3724
3725// </pointer_type_def>
3726
3727// <subrange_diff >
3728
3729/// Constructor of the @ref subrange_diff diff node type.
3730///
3731/// @param first the first subrange type to consider for the diff.
3732///
3733/// @param second the second subrange type to consider for the diff.
3734///
3735/// @param underlying_type_diff the underlying type diff between @p
3736/// first and @p second.
3737///
3738/// @param ctxt the diff context to use.
3740(const array_type_def::subrange_sptr& first,
3741 const array_type_def::subrange_sptr& second,
3742 const diff_sptr& underlying_type_diff,
3743 const diff_context_sptr ctxt)
3744 : type_diff_base(first, second, ctxt),
3745 priv_(new priv(underlying_type_diff))
3746{}
3747
3748
3749/// Getter of the first subrange of the current instance @ref
3750/// subrange_diff.
3751///
3752/// @return The first subrange of the current instance @ref subrange_diff.
3756
3757/// Getter of the second subrange of the current instance @ref
3758/// subrange_diff.
3759///
3760/// @return The second subrange of the current instance @ref
3761/// subrange_diff.
3765
3766/// Getter of the diff node of the underlying types of the current
3767/// @ref subrange_diff diff node.
3768///
3769/// @return The diff node of the underlying types of the current @ref
3770/// subrange_diff diff node.
3771const diff_sptr
3773{return priv_->underlying_type_diff_;}
3774
3775/// Getter the pretty representation of the @ref subrange_diff diff
3776/// node.
3777///
3778/// @return The pretty representation of the @ref subrange_diff diff node.
3779const string&
3781{
3782 if (diff::priv_->pretty_representation_.empty())
3783 {
3784 std::ostringstream o;
3785 o << "subrange_diff["
3786 << first_subject()->get_pretty_representation()
3787 << ","
3788 << second_subject()->get_pretty_representation()
3789 << "]";
3790 diff::priv_->pretty_representation_ = o.str();
3791 }
3792 return diff::priv_->pretty_representation_;
3793}
3794
3795/// Test if the current @ref subrange_diff node carries any change.
3796///
3797/// @return true iff the current @ref subrange_diff node carries any
3798/// change.
3799bool
3801{return *first_subrange() != *second_subrange();}
3802
3803/// Test if the current @ref subrange_diff node carries any local
3804/// change.
3805///
3806/// @return true iff the current @ref subrange_diff node carries any
3807/// local change.
3808enum change_kind
3810{
3811 ir::change_kind k = ir::NO_CHANGE_KIND;
3812 if (!equals(*first_subrange(), *second_subrange(), &k))
3813 return k & ir::ALL_LOCAL_CHANGES_MASK;
3814 return ir::NO_CHANGE_KIND;
3815}
3816
3817/// Report about the changes carried by this node.
3818///
3819/// @param out the output stream to send the report to.
3820///
3821/// @param indent the indentation string to use.
3822void
3823subrange_diff::report(ostream& out, const string& indent) const
3824{context()->get_reporter()->report(*this, out, indent);}
3825
3826/// Populate the vector of children node of the @ref diff base type
3827/// sub-object of this instance of @ref subrange_diff.
3828///
3829/// The children node can then later be retrieved using
3830/// diff::children_node().
3831void
3834
3835/// Compute the diff between two instances of @ref subrange_diff.
3836///
3837/// Note that the two decls must have been created in the same @ref
3838/// environment, otherwise, this function aborts.
3839///
3840/// @param first the first @ref subrange_diff to consider for the diff.
3841///
3842/// @param second the second @ref subrange_diff to consider for the diff.
3843///
3844/// @param ctxt the diff context to use.
3845///
3846/// @return the resulting diff between the two @ref subrange_diff.
3850 diff_context_sptr ctxt)
3851{
3852 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
3853 second->get_underlying_type(),
3854 ctxt);
3855
3856 subrange_diff_sptr result(new subrange_diff(first, second, d, ctxt));
3857 ctxt->initialize_canonical_diff(result);
3858 return result;
3859}
3860
3861//</subrange_diff >
3862
3863
3864// <array_type_def>
3865
3866/// Populate the vector of children node of the @ref diff base type
3867/// sub-object of this instance of @ref array_diff.
3868///
3869/// The children node can then later be retrieved using
3870/// diff::children_node().
3871void
3874
3875/// Constructor for array_diff
3876///
3877/// @param first the first array_type of the diff.
3878///
3879/// @param second the second array_type of the diff.
3880///
3881/// @param element_type_diff the diff between the two array element
3882/// types.
3883///
3884/// @param ctxt the diff context to use.
3886 const array_type_def_sptr second,
3887 diff_sptr element_type_diff,
3888 diff_context_sptr ctxt)
3889 : type_diff_base(first, second, ctxt),
3890 priv_(new priv(element_type_diff))
3891{}
3892
3893/// Getter for the first array of the diff.
3894///
3895/// @return the first array of the diff.
3898{return dynamic_pointer_cast<array_type_def>(first_subject());}
3899
3900/// Getter for the second array of the diff.
3901///
3902/// @return for the second array of the diff.
3905{return dynamic_pointer_cast<array_type_def>(second_subject());}
3906
3907/// Getter for the diff between the two types of array elements.
3908///
3909/// @return the diff between the two types of array elements.
3910const diff_sptr&
3912{return priv_->element_type_diff_;}
3913
3914/// Setter for the diff between the two array element types.
3915///
3916/// @param d the new diff betweend the two array element types.
3917void
3919{priv_->element_type_diff_ = d;}
3920
3921/// @return the pretty representation for the current instance of @ref
3922/// array_diff.
3923const string&
3925{
3926 if (diff::priv_->pretty_representation_.empty())
3927 {
3928 std::ostringstream o;
3929 o << "array_diff["
3930 << first_subject()->get_pretty_representation()
3931 << ", "
3932 << second_subject()->get_pretty_representation()
3933 << "]";
3934 diff::priv_->pretty_representation_ = o.str();
3935 }
3936 return diff::priv_->pretty_representation_;
3937}
3938
3939/// Return true iff the current diff node carries a change.
3940///
3941/// @return true iff the current diff node carries a change.
3942bool
3944{
3945 bool l = false;
3946
3947 // the array element types match check for differing dimensions
3948 // etc...
3950 f = dynamic_pointer_cast<array_type_def>(first_subject()),
3951 s = dynamic_pointer_cast<array_type_def>(second_subject());
3952
3953 if (f->get_name() != s->get_name())
3954 l |= true;
3955 if (f->get_size_in_bits() != s->get_size_in_bits())
3956 l |= true;
3957 if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
3958 l |= true;
3959
3960 l |= element_type_diff()
3961 ? element_type_diff()->has_changes()
3962 : false;
3963
3964 return l;
3965}
3966
3967
3968/// @return the kind of local change carried by the current diff node.
3969/// The value returned is zero if the current node carries no local
3970/// change.
3971enum change_kind
3973{
3974 ir::change_kind k = ir::NO_CHANGE_KIND;
3975 if (!equals(*first_array(), *second_array(), &k))
3976 return k & ir::ALL_LOCAL_CHANGES_MASK;
3977 return ir::NO_CHANGE_KIND;
3978}
3979
3980/// Report the diff in a serialized form.
3981///
3982/// @param out the output stream to serialize the dif to.
3983///
3984/// @param indent the string to use for indenting the report.
3985void
3986array_diff::report(ostream& out, const string& indent) const
3987{
3988 context()->get_reporter()->report(*this, out, indent);
3989}
3990
3991/// Compute the diff between two arrays.
3992///
3993/// Note that the two types must have been created in the same @ref
3994/// environment, otherwise, this function aborts.
3995///
3996/// @param first the first array to consider for the diff.
3997///
3998/// @param second the second array to consider for the diff.
3999///
4000/// @param ctxt the diff context to use.
4003 array_type_def_sptr second,
4004 diff_context_sptr ctxt)
4005{
4006 diff_sptr d = compute_diff_for_types(first->get_element_type(),
4007 second->get_element_type(),
4008 ctxt);
4009 array_diff_sptr result(new array_diff(first, second, d, ctxt));
4010 ctxt->initialize_canonical_diff(result);
4011 return result;
4012}
4013// </array_type_def>
4014
4015// <reference_type_def>
4016
4017/// Populate the vector of children node of the @ref diff base type
4018/// sub-object of this instance of @ref reference_diff.
4019///
4020/// The children node can then later be retrieved using
4021/// diff::children_node().
4022void
4025
4026/// Constructor for reference_diff
4027///
4028/// @param first the first reference_type of the diff.
4029///
4030/// @param second the second reference_type of the diff.
4031///
4032/// @param ctxt the diff context to use.
4034 const reference_type_def_sptr second,
4035 diff_sptr underlying,
4036 diff_context_sptr ctxt)
4037 : type_diff_base(first, second, ctxt),
4038 priv_(new priv(underlying))
4039{}
4040
4041/// Getter for the first reference of the diff.
4042///
4043/// @return the first reference of the diff.
4046{return dynamic_pointer_cast<reference_type_def>(first_subject());}
4047
4048/// Getter for the second reference of the diff.
4049///
4050/// @return for the second reference of the diff.
4053{return dynamic_pointer_cast<reference_type_def>(second_subject());}
4054
4055
4056/// Getter for the diff between the two referred-to types.
4057///
4058/// @return the diff between the two referred-to types.
4059const diff_sptr&
4061{return priv_->underlying_type_diff_;}
4062
4063/// Setter for the diff between the two referred-to types.
4064///
4065/// @param d the new diff betweend the two referred-to types.
4066diff_sptr&
4068{
4069 priv_->underlying_type_diff_ = d;
4070 return priv_->underlying_type_diff_;
4071}
4072
4073/// @return the pretty representation for the current instance of @ref
4074/// reference_diff.
4075const string&
4077{
4078 if (diff::priv_->pretty_representation_.empty())
4079 {
4080 std::ostringstream o;
4081 o << "reference_diff["
4082 << first_subject()->get_pretty_representation()
4083 << ", "
4084 << second_subject()->get_pretty_representation()
4085 << "]";
4086 diff::priv_->pretty_representation_ = o.str();
4087 }
4088 return diff::priv_->pretty_representation_;
4089}
4090
4091/// Return true iff the current diff node carries a change.
4092///
4093/// @return true iff the current diff node carries a change.
4094bool
4096{
4097 return first_reference() != second_reference();
4098}
4099
4100/// @return the kind of local change carried by the current diff node.
4101/// The value returned is zero if the current node carries no local
4102/// change.
4103enum change_kind
4105{
4106 ir::change_kind k = ir::NO_CHANGE_KIND;
4107 if (!equals(*first_reference(), *second_reference(), &k))
4108 return k & ir::ALL_LOCAL_CHANGES_MASK;
4109 return ir::NO_CHANGE_KIND;
4110}
4111
4112/// Report the diff in a serialized form.
4113///
4114/// @param out the output stream to serialize the dif to.
4115///
4116/// @param indent the string to use for indenting the report.
4117void
4118reference_diff::report(ostream& out, const string& indent) const
4119{
4120 context()->get_reporter()->report(*this, out, indent);
4121}
4122
4123/// Compute the diff between two references.
4124///
4125/// Note that the two types must have been created in the same @ref
4126/// environment, otherwise, this function aborts.
4127///
4128/// @param first the first reference to consider for the diff.
4129///
4130/// @param second the second reference to consider for the diff.
4131///
4132/// @param ctxt the diff context to use.
4136 diff_context_sptr ctxt)
4137{
4138 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
4139 second->get_pointed_to_type(),
4140 ctxt);
4141 reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
4142 ctxt->initialize_canonical_diff(result);
4143 return result;
4144}
4145// </reference_type_def>
4146
4147// <ptr_to_mbr_diff stuff>
4148
4149
4150/// Constructor of @ref ptr_to_mbr_diff.
4151///
4152/// @param first the first pointer-to-member subject of the diff.
4153///
4154/// @param second the second pointer-to-member subject of the diff.
4155///
4156/// @param member_type_diff the diff node carrying changes to the
4157/// member type of the pointer-to-member we are considering.
4158///
4159/// @param containing_type_diff the diff node carrying changes to the
4160/// containing type of the pointer-to-member we are considering.
4161///
4162/// @param ctxt the context of the diff we are considering.
4163ptr_to_mbr_diff::ptr_to_mbr_diff(const ptr_to_mbr_type_sptr& first,
4164 const ptr_to_mbr_type_sptr& second,
4165 const diff_sptr& member_type_diff,
4166 const diff_sptr& containing_type_diff,
4167 diff_context_sptr ctxt)
4168 : type_diff_base(first, second, ctxt),
4169 priv_(new priv(member_type_diff, containing_type_diff))
4170{}
4171
4172/// Getter of the first pointer-to-member subject of the current diff
4173/// node.
4174///
4175/// @return the first pointer-to-member subject of the current diff
4176/// node.
4179{return dynamic_pointer_cast<ptr_to_mbr_type>(first_subject());}
4180
4181/// Getter of the second pointer-to-member subject of the current diff
4182/// node.
4183///
4184/// @return the second pointer-to-member subject of the current diff
4185/// node.
4188{return dynamic_pointer_cast<ptr_to_mbr_type>(second_subject());}
4189
4190/// Getter of the diff node carrying changes to the member type of
4191/// first subject of the current diff node.
4192///
4193/// @return The diff node carrying changes to the member type of first
4194/// subject of the current diff node.
4195const diff_sptr
4197{return priv_->member_type_diff_;}
4198
4199/// Getter of the diff node carrying changes to the containing type of
4200/// first subject of the current diff node.
4201///
4202/// @return The diff node carrying changes to the containing type of
4203/// first subject of the current diff node.
4204const diff_sptr
4206{return priv_->containing_type_diff_;}
4207
4208/// Test whether the current diff node carries any change.
4209///
4210/// @return true iff the current diff node carries any change.
4211bool
4213{
4215}
4216
4217/// Test whether the current diff node carries any local change.
4218///
4219/// @return true iff the current diff node carries any local change.
4220enum change_kind
4222{
4223 ir::change_kind k = ir::NO_CHANGE_KIND;
4225 return k & ir::ALL_LOCAL_CHANGES_MASK;
4226 return ir::NO_CHANGE_KIND;
4227}
4228
4229/// Get the pretty representation of the current @ref ptr_to_mbr_diff
4230/// node.
4231///
4232/// @return the pretty representation of the current diff node.
4233const string&
4235{
4236 if (diff::priv_->pretty_representation_.empty())
4237 {
4238 std::ostringstream o;
4239 o << "ptr_to_mbr_diff["
4240 << first_subject()->get_pretty_representation()
4241 << ", "
4242 << second_subject()->get_pretty_representation()
4243 << "]";
4244 diff::priv_->pretty_representation_ = o.str();
4245 }
4246 return diff::priv_->pretty_representation_;
4247}
4248
4249void
4250ptr_to_mbr_diff::report(ostream& out, const string& indent) const
4251{
4252 context()->get_reporter()->report(*this, out, indent);
4253}
4254
4255/// Populate the vector of children node of the @ref diff base type
4256/// sub-object of this instance of @ref ptr_to_mbr_diff.
4257///
4258/// The children node can then later be retrieved using
4259/// diff::children_node().
4260void
4262{
4265}
4266
4267/// Destructor of @ref ptr_to_mbr_diff.
4269{
4270}
4271
4272/// Compute the diff between two @ref ptr_to_mbr_type types.
4273///
4274/// Note that the two types must have been created in the same @ref
4275/// environment, otherwise, this function aborts.
4276///
4277/// @param first the first pointer-to-member type to consider for the diff.
4278///
4279/// @param second the second pointer-to-member type to consider for the diff.
4280///
4281/// @param ctxt the diff context to use.
4284 const ptr_to_mbr_type_sptr& second,
4285 diff_context_sptr& ctxt)
4286{
4287 diff_sptr member_type_diff =
4288 compute_diff(is_type(first->get_member_type()),
4289 is_type(second->get_member_type()),
4290 ctxt);
4291
4292 diff_sptr containing_type_diff =
4293 compute_diff(is_type(first->get_containing_type()),
4294 is_type(second->get_containing_type()),
4295 ctxt);
4296
4297 ptr_to_mbr_diff_sptr result(new ptr_to_mbr_diff(first, second,
4298 member_type_diff,
4299 containing_type_diff,
4300 ctxt));
4301 ctxt->initialize_canonical_diff(result);
4302 return result;
4303}
4304
4305// </ptr_to_mbr_diff stuff>
4306
4307// <qualified_type_diff stuff>
4308
4309/// Populate the vector of children node of the @ref diff base type
4310/// sub-object of this instance of @ref qualified_type_diff.
4311///
4312/// The children node can then later be retrieved using
4313/// diff::children_node().
4314void
4317
4318/// Constructor for qualified_type_diff.
4319///
4320/// @param first the first qualified type of the diff.
4321///
4322/// @param second the second qualified type of the diff.
4323///
4324/// @param ctxt the diff context to use.
4325qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
4326 qualified_type_def_sptr second,
4327 diff_sptr under,
4328 diff_context_sptr ctxt)
4329 : type_diff_base(first, second, ctxt),
4330 priv_(new priv(under))
4331{}
4332
4333/// Getter for the first qualified type of the diff.
4334///
4335/// @return the first qualified type of the diff.
4336const qualified_type_def_sptr
4338{return dynamic_pointer_cast<qualified_type_def>(first_subject());}
4339
4340/// Getter for the second qualified type of the diff.
4341///
4342/// @return the second qualified type of the diff.
4343const qualified_type_def_sptr
4345{return dynamic_pointer_cast<qualified_type_def>(second_subject());}
4346
4347/// Getter for the diff between the underlying types of the two
4348/// qualified types.
4349///
4350/// @return the diff between the underlying types of the two qualified
4351/// types.
4354{return priv_->underlying_type_diff;}
4355
4356/// Getter for the diff between the most underlying non-qualified
4357/// types of two qualified types.
4358///
4359/// @return the diff between the most underlying non-qualified types
4360/// of two qualified types.
4363{
4364 if (!priv_->leaf_underlying_type_diff)
4365 priv_->leaf_underlying_type_diff
4366 = compute_diff_for_types(get_leaf_type(first_qualified_type()),
4368 context());
4369
4370 return priv_->leaf_underlying_type_diff;
4371}
4372
4373/// Setter for the diff between the underlying types of the two
4374/// qualified types.
4375///
4376/// @return the diff between the underlying types of the two qualified
4377/// types.
4378void
4380{priv_->underlying_type_diff = d;}
4381
4382/// @return the pretty representation of the current instance of @ref
4383/// qualified_type_diff.
4384const string&
4386{
4387 if (diff::priv_->pretty_representation_.empty())
4388 {
4389 std::ostringstream o;
4390 o << "qualified_type_diff["
4391 << first_subject()->get_pretty_representation()
4392 << ", "
4393 << second_subject()->get_pretty_representation()
4394 << "]";
4395 diff::priv_->pretty_representation_ = o.str();
4396 }
4397 return diff::priv_->pretty_representation_;
4398}
4399
4400/// Return true iff the current diff node carries a change.
4401///
4402/// @return true iff the current diff node carries a change.
4403bool
4406
4407/// @return the kind of local change carried by the current diff node.
4408/// The value returned is zero if the current node carries no local
4409/// change.
4410enum change_kind
4412{
4413 ir::change_kind k = ir::NO_CHANGE_KIND;
4415 return k & ir::ALL_LOCAL_CHANGES_MASK;
4416 return ir::NO_CHANGE_KIND;
4417}
4418
4419/// Report the diff in a serialized form.
4420///
4421/// @param out the output stream to serialize to.
4422///
4423/// @param indent the string to use to indent the lines of the report.
4424void
4425qualified_type_diff::report(ostream& out, const string& indent) const
4426{
4427 context()->get_reporter()->report(*this, out, indent);
4428}
4429
4430/// Compute the diff between two qualified types.
4431///
4432/// Note that the two types must have been created in the same @ref
4433/// environment, otherwise, this function aborts.
4434///
4435/// @param first the first qualified type to consider for the diff.
4436///
4437/// @param second the second qualified type to consider for the diff.
4438///
4439/// @param ctxt the diff context to use.
4440qualified_type_diff_sptr
4441compute_diff(const qualified_type_def_sptr first,
4442 const qualified_type_def_sptr second,
4443 diff_context_sptr ctxt)
4444{
4445 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
4446 second->get_underlying_type(),
4447 ctxt);
4448 qualified_type_diff_sptr result(new qualified_type_diff(first, second,
4449 d, ctxt));
4450 ctxt->initialize_canonical_diff(result);
4451 return result;
4452}
4453
4454// </qualified_type_diff stuff>
4455
4456// <enum_diff stuff>
4457
4458/// Clear the lookup tables useful for reporting an enum_diff.
4459///
4460/// This function must be updated each time a lookup table is added or
4461/// removed from the class_diff::priv.
4462void
4463enum_diff::clear_lookup_tables()
4464{
4465 priv_->deleted_enumerators_.clear();
4466 priv_->inserted_enumerators_.clear();
4467 priv_->changed_enumerators_.clear();
4468}
4469
4470/// Tests if the lookup tables are empty.
4471///
4472/// @return true if the lookup tables are empty, false otherwise.
4473bool
4474enum_diff::lookup_tables_empty() const
4475{
4476 return (priv_->deleted_enumerators_.empty()
4477 && priv_->inserted_enumerators_.empty()
4478 && priv_->changed_enumerators_.empty());
4479}
4480
4481/// If the lookup tables are not yet built, walk the differences and
4482/// fill the lookup tables.
4483void
4484enum_diff::ensure_lookup_tables_populated()
4485{
4486 if (!lookup_tables_empty())
4487 return;
4488
4489 {
4490 edit_script e = priv_->enumerators_changes_;
4491
4492 for (vector<deletion>::const_iterator it = e.deletions().begin();
4493 it != e.deletions().end();
4494 ++it)
4495 {
4496 unsigned i = it->index();
4497 const enum_type_decl::enumerator& n =
4498 first_enum()->get_enumerators()[i];
4499 const string& name = n.get_name();
4500 ABG_ASSERT(priv_->deleted_enumerators_.find(n.get_name())
4501 == priv_->deleted_enumerators_.end());
4502 priv_->deleted_enumerators_[name] = n;
4503 }
4504
4505 for (vector<insertion>::const_iterator it = e.insertions().begin();
4506 it != e.insertions().end();
4507 ++it)
4508 {
4509 for (vector<unsigned>::const_iterator iit =
4510 it->inserted_indexes().begin();
4511 iit != it->inserted_indexes().end();
4512 ++iit)
4513 {
4514 unsigned i = *iit;
4515 const enum_type_decl::enumerator& n =
4516 second_enum()->get_enumerators()[i];
4517 const string& name = n.get_name();
4518 ABG_ASSERT(priv_->inserted_enumerators_.find(n.get_name())
4519 == priv_->inserted_enumerators_.end());
4520 string_enumerator_map::const_iterator j =
4521 priv_->deleted_enumerators_.find(name);
4522 if (j == priv_->deleted_enumerators_.end())
4523 priv_->inserted_enumerators_[name] = n;
4524 else
4525 {
4526 if (j->second != n)
4527 priv_->changed_enumerators_[j->first] =
4528 std::make_pair(j->second, n);
4529 priv_->deleted_enumerators_.erase(j);
4530 }
4531 }
4532 }
4533 }
4534}
4535
4536/// Populate the vector of children node of the @ref diff base type
4537/// sub-object of this instance of @ref enum_diff.
4538///
4539/// The children node can then later be retrieved using
4540/// diff::children_node().
4541void
4544
4545/// Constructor for enum_diff.
4546///
4547/// @param first the first enum type of the diff.
4548///
4549/// @param second the second enum type of the diff.
4550///
4551/// @param underlying_type_diff the diff of the two underlying types
4552/// of the two enum types.
4553///
4554/// @param ctxt the diff context to use.
4556 const enum_type_decl_sptr second,
4557 const diff_sptr underlying_type_diff,
4558 const diff_context_sptr ctxt)
4559 : type_diff_base(first, second, ctxt),
4560 priv_(new priv(underlying_type_diff))
4561{}
4562
4563/// @return the first enum of the diff.
4566{return dynamic_pointer_cast<enum_type_decl>(first_subject());}
4567
4568/// @return the second enum of the diff.
4571{return dynamic_pointer_cast<enum_type_decl>(second_subject());}
4572
4573/// @return the diff of the two underlying enum types.
4576{return priv_->underlying_type_diff_;}
4577
4578/// @return a map of the enumerators that were deleted.
4581{return priv_->deleted_enumerators_;}
4582
4583/// @return a map of the enumerators that were inserted
4586{return priv_->inserted_enumerators_;}
4587
4588/// @return a map of the enumerators that were changed
4591{return priv_->changed_enumerators_;}
4592
4593/// @return the pretty representation of the current instance of @ref
4594/// enum_diff.
4595const string&
4597{
4598 if (diff::priv_->pretty_representation_.empty())
4599 {
4600 std::ostringstream o;
4601 o << "enum_diff["
4602 << first_subject()->get_pretty_representation()
4603 << ", "
4604 << second_subject()->get_pretty_representation()
4605 << "]";
4606 diff::priv_->pretty_representation_ = o.str();
4607 }
4608 return diff::priv_->pretty_representation_;
4609}
4610
4611/// Return true iff the current diff node carries a change.
4612///
4613/// @return true iff the current diff node carries a change.
4614bool
4616{return first_enum() != second_enum();}
4617
4618/// @return the kind of local change carried by the current diff node.
4619/// The value returned is zero if the current node carries no local
4620/// change.
4621enum change_kind
4623{
4624 ir::change_kind k = ir::NO_CHANGE_KIND;
4625 if (!equals(*first_enum(), *second_enum(), &k))
4626 return k & ir::ALL_LOCAL_CHANGES_MASK;
4627 return ir::NO_CHANGE_KIND;
4628}
4629
4630/// Report the differences between the two enums.
4631///
4632/// @param out the output stream to send the report to.
4633///
4634/// @param indent the string to use for indentation.
4635void
4636enum_diff::report(ostream& out, const string& indent) const
4637{
4638 context()->get_reporter()->report(*this, out, indent);
4639}
4640
4641/// Compute the set of changes between two instances of @ref
4642/// enum_type_decl.
4643///
4644/// Note that the two types must have been created in the same @ref
4645/// environment, otherwise, this function aborts.
4646///
4647/// @param first a pointer to the first enum_type_decl to consider.
4648///
4649/// @param second a pointer to the second enum_type_decl to consider.
4650///
4651/// @return the resulting diff of the two enums @p first and @p
4652/// second.
4653///
4654/// @param ctxt the diff context to use.
4655enum_diff_sptr
4657 const enum_type_decl_sptr second,
4658 diff_context_sptr ctxt)
4659{
4660 diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
4661 second->get_underlying_type(),
4662 ctxt);
4663 enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
4664 if (first != second)
4665 {
4666 compute_diff(first->get_enumerators().begin(),
4667 first->get_enumerators().end(),
4668 second->get_enumerators().begin(),
4669 second->get_enumerators().end(),
4670 d->priv_->enumerators_changes_);
4671 d->ensure_lookup_tables_populated();
4672 }
4673 ctxt->initialize_canonical_diff(d);
4674
4675 return d;
4676}
4677// </enum_diff stuff>
4678
4679// <class_or_union_diff stuff>
4680
4681/// Test if the current diff node carries a member type change for a
4682/// member type which name is the same as the name of a given type
4683/// declaration.
4684///
4685/// @param d the type declaration which name should be equal to the
4686/// name of the member type that might have changed.
4687///
4688/// @return the member type that has changed, iff there were a member
4689/// type (which name is the same as the name of @p d) that changed.
4690/// Note that the member type that is returned is the new value of the
4691/// member type that changed.
4694{
4695 string qname = d->get_qualified_name();
4696 string_diff_sptr_map::const_iterator it =
4697 changed_member_types_.find(qname);
4698
4699 return ((it == changed_member_types_.end())
4701 : it->second->second_subject());
4702}
4703
4704/// Test if the current diff node carries a data member change for a
4705/// data member which name is the same as the name of a given type
4706/// declaration.
4707///
4708/// @param d the type declaration which name should be equal to the
4709/// name of the data member that might have changed.
4710///
4711/// @return the data member that has changed, iff there were a data
4712/// member type (which name is the same as the name of @p d) that
4713/// changed. Note that the data member that is returned is the new
4714/// value of the data member that changed.
4715decl_base_sptr
4717{
4718 string qname = d->get_qualified_name();
4719 string_var_diff_sptr_map::const_iterator it =
4720 subtype_changed_dm_.find(qname);
4721
4722 if (it == subtype_changed_dm_.end())
4723 return decl_base_sptr();
4724 return it->second->second_var();
4725}
4726
4727/// Test if the current diff node carries a member class template
4728/// change for a member class template which name is the same as the
4729/// name of a given type declaration.
4730///
4731/// @param d the type declaration which name should be equal to the
4732/// name of the member class template that might have changed.
4733///
4734/// @return the member class template that has changed, iff there were
4735/// a member class template (which name is the same as the name of @p
4736/// d) that changed. Note that the member class template that is
4737/// returned is the new value of the member class template that
4738/// changed.
4739decl_base_sptr
4741{
4742 string qname = d->get_qualified_name();
4743 string_diff_sptr_map::const_iterator it =
4744 changed_member_class_tmpls_.find(qname);
4745
4746 return ((it == changed_member_class_tmpls_.end())
4747 ? decl_base_sptr()
4748 : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
4749}
4750
4751/// Get the number of non static data members that were deleted.
4752///
4753/// @return the number of non static data members that were deleted.
4754size_t
4756{
4757 size_t result = 0;
4758
4759 for (string_decl_base_sptr_map::const_iterator i =
4760 deleted_data_members_.begin();
4761 i != deleted_data_members_.end();
4762 ++i)
4763 if (is_member_decl(i->second)
4764 && !get_member_is_static(i->second))
4765 ++result;
4766
4767 return result;
4768}
4769
4770/// Get the number of non static data members that were inserted.
4771///
4772/// @return the number of non static data members that were inserted.
4773size_t
4775{
4776 size_t result = 0;
4777
4778 for (string_decl_base_sptr_map::const_iterator i =
4779 inserted_data_members_.begin();
4780 i != inserted_data_members_.end();
4781 ++i)
4782 if (is_member_decl(i->second)
4783 && !get_member_is_static(i->second))
4784 ++result;
4785
4786 return result;
4787}
4788
4789/// Get the number of data member sub-type changes carried by the
4790/// current diff node that were filtered out.
4791///
4792/// @param local_only if true, it means that only (filtered) local
4793/// changes are considered.
4794///
4795/// @return the number of data member sub-type changes carried by the
4796/// current diff node that were filtered out.
4797size_t
4799{
4800 size_t num_filtered= 0;
4801 for (var_diff_sptrs_type::const_iterator i =
4802 sorted_subtype_changed_dm_.begin();
4803 i != sorted_subtype_changed_dm_.end();
4804 ++i)
4805 {
4806 if (local_only)
4807 {
4808 if ((*i)->has_changes()
4809 && !(*i)->has_local_changes_to_be_reported())
4810 ++num_filtered;
4811 }
4812 else
4813 {
4814 if ((*i)->is_filtered_out())
4815 ++num_filtered;
4816 }
4817 }
4818 return num_filtered;
4819}
4820
4821/// Get the number of data member changes carried by the current diff
4822/// node that were filtered out.
4823///
4824/// @param local_only if true, it means that only (filtered) local
4825/// changes are considered.
4826///
4827/// @return the number of data member changes carried by the current
4828/// diff node that were filtered out.
4829size_t
4831{
4832 size_t num_filtered= 0;
4833
4834 for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
4835 i != changed_dm_.end();
4836 ++i)
4837 {
4838 diff_sptr diff = i->second;
4839 if (local_only)
4840 {
4842 || diff->is_filtered_out())
4843 ++num_filtered;
4844 }
4845 else
4846 {
4847 if (diff->is_filtered_out())
4848 ++num_filtered;
4849 }
4850 }
4851 return num_filtered;
4852}
4853
4854/// Skip the processing of the current member function if its
4855/// virtual-ness is disallowed by the user.
4856///
4857/// This is to be used in the member functions below that are used to
4858/// count the number of filtered inserted, deleted and changed member
4859/// functions.
4860#define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
4861 do { \
4862 if (get_member_function_is_virtual(f) \
4863 || get_member_function_is_virtual(s)) \
4864 { \
4865 if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
4866 continue; \
4867 } \
4868 else \
4869 { \
4870 if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
4871 continue; \
4872 } \
4873 } while (false)
4874
4875/// Get the number of member functions changes carried by the current
4876/// diff node that were filtered out.
4877///
4878/// @return the number of member functions changes carried by the
4879/// current diff node that were filtered out.
4880size_t
4882(const diff_context_sptr& ctxt)
4883{
4884 size_t count = 0;
4885 diff_category allowed_category = ctxt->get_allowed_category();
4886
4887 for (function_decl_diff_sptrs_type::const_iterator i =
4888 sorted_changed_member_functions_.begin();
4889 i != sorted_changed_member_functions_.end();
4890 ++i)
4891 {
4892 method_decl_sptr f =
4893 dynamic_pointer_cast<method_decl>
4894 ((*i)->first_function_decl());
4895 ABG_ASSERT(f);
4896
4897 method_decl_sptr s =
4898 dynamic_pointer_cast<method_decl>
4899 ((*i)->second_function_decl());
4900 ABG_ASSERT(s);
4901
4903
4904 diff_sptr diff = *i;
4905 ctxt->maybe_apply_filters(diff);
4906
4907 if (diff->is_filtered_out())
4908 ++count;
4909 }
4910
4911 return count;
4912}
4913
4914/// Get the number of member functions insertions carried by the current
4915/// diff node that were filtered out.
4916///
4917/// @return the number of member functions insertions carried by the
4918/// current diff node that were filtered out.
4919size_t
4921(const diff_context_sptr& ctxt)
4922{
4923 size_t count = 0;
4924 diff_category allowed_category = ctxt->get_allowed_category();
4925
4926 for (string_member_function_sptr_map::const_iterator i =
4927 inserted_member_functions_.begin();
4928 i != inserted_member_functions_.end();
4929 ++i)
4930 {
4931 method_decl_sptr f = i->second,
4932 s = i->second;
4933
4935
4936 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4937 ctxt->maybe_apply_filters(diff);
4938
4940 && diff->is_filtered_out())
4941 ++count;
4942 }
4943
4944 return count;
4945}
4946
4947/// Get the number of member functions deletions carried by the current
4948/// diff node that were filtered out.
4949///
4950/// @return the number of member functions deletions carried by the
4951/// current diff node that were filtered out.
4952size_t
4954(const diff_context_sptr& ctxt)
4955{
4956 size_t count = 0;
4957 diff_category allowed_category = ctxt->get_allowed_category();
4958
4959 for (string_member_function_sptr_map::const_iterator i =
4960 deleted_member_functions_.begin();
4961 i != deleted_member_functions_.end();
4962 ++i)
4963 {
4964 method_decl_sptr f = i->second,
4965 s = i->second;
4966
4968
4969 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
4970 ctxt->maybe_apply_filters(diff);
4971
4973 && diff->is_filtered_out())
4974 ++count;
4975 }
4976
4977 return count;
4978}
4979
4980/// Clear the lookup tables useful for reporting.
4981///
4982/// This function must be updated each time a lookup table is added or
4983/// removed from the class_or_union_diff::priv.
4984void
4986{
4987 priv_->deleted_member_types_.clear();
4988 priv_->inserted_member_types_.clear();
4989 priv_->changed_member_types_.clear();
4990 priv_->deleted_data_members_.clear();
4991 priv_->inserted_data_members_.clear();
4992 priv_->subtype_changed_dm_.clear();
4993 priv_->deleted_member_functions_.clear();
4994 priv_->inserted_member_functions_.clear();
4995 priv_->changed_member_functions_.clear();
4996 priv_->deleted_member_class_tmpls_.clear();
4997 priv_->inserted_member_class_tmpls_.clear();
4998 priv_->changed_member_class_tmpls_.clear();
4999}
5000
5001/// Tests if the lookup tables are empty.
5002///
5003/// @return true if the lookup tables are empty, false otherwise.
5004bool
5006{
5007 return (priv_->deleted_member_types_.empty()
5008 && priv_->inserted_member_types_.empty()
5009 && priv_->changed_member_types_.empty()
5010 && priv_->deleted_data_members_.empty()
5011 && priv_->inserted_data_members_.empty()
5012 && priv_->subtype_changed_dm_.empty()
5013 && priv_->inserted_member_functions_.empty()
5014 && priv_->deleted_member_functions_.empty()
5015 && priv_->changed_member_functions_.empty()
5016 && priv_->deleted_member_class_tmpls_.empty()
5017 && priv_->inserted_member_class_tmpls_.empty()
5018 && priv_->changed_member_class_tmpls_.empty());
5019}
5020
5021/// If the lookup tables are not yet built, walk the differences and
5022/// fill them.
5023void
5025{
5026 {
5027 edit_script& e = priv_->member_types_changes_;
5028
5029 for (vector<deletion>::const_iterator it = e.deletions().begin();
5030 it != e.deletions().end();
5031 ++it)
5032 {
5033 unsigned i = it->index();
5034 decl_base_sptr d =
5035 get_type_declaration(first_class_or_union()->get_member_types()[i]);
5036 class_or_union_sptr record_type = is_class_or_union_type(d);
5037 if (record_type && record_type->get_is_declaration_only())
5038 continue;
5039 string name = d->get_name();
5040 priv_->deleted_member_types_[name] = d;
5041 }
5042
5043 for (vector<insertion>::const_iterator it = e.insertions().begin();
5044 it != e.insertions().end();
5045 ++it)
5046 {
5047 for (vector<unsigned>::const_iterator iit =
5048 it->inserted_indexes().begin();
5049 iit != it->inserted_indexes().end();
5050 ++iit)
5051 {
5052 unsigned i = *iit;
5053 decl_base_sptr d =
5054 get_type_declaration(second_class_or_union()->get_member_types()[i]);
5055 class_or_union_sptr record_type = is_class_or_union_type(d);
5056 if (record_type && record_type->get_is_declaration_only())
5057 continue;
5058 string name = d->get_name();
5059 string_decl_base_sptr_map::const_iterator j =
5060 priv_->deleted_member_types_.find(name);
5061 if (j != priv_->deleted_member_types_.end())
5062 {
5063 if (*j->second != *d)
5064 priv_->changed_member_types_[name] =
5065 compute_diff(j->second, d, context());
5066
5067 priv_->deleted_member_types_.erase(j);
5068 }
5069 else
5070 priv_->inserted_member_types_[name] = d;
5071 }
5072 }
5073 }
5074
5075 {
5076 edit_script& e = priv_->data_members_changes_;
5077
5078 for (vector<deletion>::const_iterator it = e.deletions().begin();
5079 it != e.deletions().end();
5080 ++it)
5081 {
5082 unsigned i = it->index();
5083 var_decl_sptr data_member =
5084 is_var_decl(first_class_or_union()->get_non_static_data_members()[i]);
5085 string name = data_member->get_anon_dm_reliable_name();
5086
5087 ABG_ASSERT(priv_->deleted_data_members_.find(name)
5088 == priv_->deleted_data_members_.end());
5089 priv_->deleted_data_members_[name] = data_member;
5090 }
5091
5092 for (vector<insertion>::const_iterator it = e.insertions().begin();
5093 it != e.insertions().end();
5094 ++it)
5095 {
5096 for (vector<unsigned>::const_iterator iit =
5097 it->inserted_indexes().begin();
5098 iit != it->inserted_indexes().end();
5099 ++iit)
5100 {
5101 unsigned i = *iit;
5102 decl_base_sptr d =
5103 second_class_or_union()->get_non_static_data_members()[i];
5104 var_decl_sptr added_dm = is_var_decl(d);
5105 string name = added_dm->get_anon_dm_reliable_name();
5106 ABG_ASSERT(priv_->inserted_data_members_.find(name)
5107 == priv_->inserted_data_members_.end());
5108
5109 bool ignore_added_anonymous_data_member = false;
5110 if (is_anonymous_data_member(added_dm))
5111 {
5112 //
5113 // Handle insertion of anonymous data member to
5114 // replace existing data members.
5115 //
5116 // For instance consider this:
5117 // struct S
5118 // {
5119 // int a;
5120 // int b;
5121 // int c;
5122 // };// end struct S
5123 //
5124 // Where the data members 'a' and 'b' are replaced
5125 // by an anonymous data member without changing the
5126 // effective bit layout of the structure:
5127 //
5128 // struct S
5129 // {
5130 // struct
5131 // {
5132 // union
5133 // {
5134 // int a;
5135 // char a_1;
5136 // };
5137 // union
5138 // {
5139 // int b;
5140 // char b_1;
5141 // };
5142 // };
5143 // int c;
5144 // }; // end struct S
5145 //
5146 var_decl_sptr replaced_dm, replacing_dm;
5147 bool added_anon_dm_changes_dm = false;
5148 // The vector of data members replaced by anonymous
5149 // data members.
5150 vector<var_decl_sptr> dms_replaced_by_anon_dm;
5151
5152 //
5153 // Let's start collecting the set of data members
5154 // which have been replaced by anonymous types in a
5155 // harmless way. These are going to be collected into
5156 // dms_replaced_by_anon_dm and, ultimately, into
5157 // priv_->dms_replaced_by_adms_
5158 //
5159 for (string_decl_base_sptr_map::const_iterator it =
5160 priv_->deleted_data_members_.begin();
5161 it != priv_->deleted_data_members_.end();
5162 ++it)
5163 {
5164 // We don't support this pattern for anonymous
5165 // data members themselves being replaced. If
5166 // that occurs then we'll just report it verbatim.
5167 if (is_anonymous_data_member(it->second))
5168 continue;
5169
5170 string deleted_dm_name = it->second->get_name();
5171 if ((replacing_dm =
5173 deleted_dm_name)))
5174 {
5175 // So it looks like replacing_dm might have
5176 // replaced the data member which name is
5177 // 'deleted_dm_name'. Let's look deeper to be
5178 // sure.
5179 //
5180 // Note that replacing_dm is part (member) of
5181 // an anonymous data member that might replace
5182 // replaced_dm.
5183
5184 // So let's get that replaced data member.
5185 replaced_dm = is_var_decl(it->second);
5186 size_t replaced_dm_offset =
5187 get_data_member_offset(replaced_dm),
5188 replacing_dm_offset =
5189 get_absolute_data_member_offset(replacing_dm);
5190
5191 if (replaced_dm_offset != replacing_dm_offset)
5192 {
5193 // So the replacing data member and the
5194 // replaced data member don't have the
5195 // same offset. This is not the pattern we
5196 // are looking for. Rather, it looks like
5197 // the anonymous data member has *changed*
5198 // the data member.
5199 added_anon_dm_changes_dm = true;
5200 break;
5201 }
5202
5203 if (replaced_dm->get_type()->get_size_in_bits()
5204 == replaced_dm->get_type()->get_size_in_bits())
5205 dms_replaced_by_anon_dm.push_back(replaced_dm);
5206 else
5207 {
5208 added_anon_dm_changes_dm = true;
5209 break;
5210 }
5211 }
5212 }
5213
5214 // Now walk dms_replaced_by_anon_dm to fill up
5215 // priv_->dms_replaced_by_adms_ with the set of data
5216 // members replaced by anonymous data members.
5217 if (!added_anon_dm_changes_dm
5218 && !dms_replaced_by_anon_dm.empty())
5219 {
5220 // See if the added data member isn't too big.
5221 type_base_sptr added_dm_type = added_dm->get_type();
5222 ABG_ASSERT(added_dm_type);
5223 var_decl_sptr new_next_dm =
5225 added_dm);
5226 var_decl_sptr old_next_dm =
5227 first_class_or_union()->find_data_member(new_next_dm);
5228
5229 if (!old_next_dm
5230 || (old_next_dm
5231 && (get_absolute_data_member_offset(old_next_dm)
5232 == get_absolute_data_member_offset(new_next_dm))))
5233 {
5234 // None of the data members that are replaced
5235 // by the added union should be considered as
5236 // having been deleted.
5237 ignore_added_anonymous_data_member = true;
5238 for (vector<var_decl_sptr>::const_iterator i =
5239 dms_replaced_by_anon_dm.begin();
5240 i != dms_replaced_by_anon_dm.end();
5241 ++i)
5242 {
5243 string n = (*i)->get_name();
5244 priv_->dms_replaced_by_adms_[n] =
5245 added_dm;
5246 priv_->deleted_data_members_.erase(n);
5247 }
5248 }
5249 }
5250 }
5251
5252 if (!ignore_added_anonymous_data_member)
5253 {
5254 // Detect changed data members.
5255 //
5256 // A changed data member (that we shall name D) is a data
5257 // member that satisfies the conditions below:
5258 //
5259 // 1/ It must have been added.
5260 //
5261 // 2/ It must have been deleted as well.
5262 //
5263 // 3/ It there must be a non-empty difference between the
5264 // deleted D and the added D.
5265 string_decl_base_sptr_map::const_iterator j =
5266 priv_->deleted_data_members_.find(name);
5267 if (j != priv_->deleted_data_members_.end())
5268 {
5269 if (*j->second != *d)
5270 {
5271 var_decl_sptr old_dm = is_var_decl(j->second);
5272 priv_->subtype_changed_dm_[name]=
5273 compute_diff(old_dm, added_dm, context());
5274 }
5275 priv_->deleted_data_members_.erase(j);
5276 }
5277 else
5278 priv_->inserted_data_members_[name] = d;
5279 }
5280 }
5281 }
5282
5283 // Now detect when a data member is deleted from offset N and
5284 // another one is added to offset N. In that case, we want to be
5285 // able to say that the data member at offset N changed.
5286 for (string_decl_base_sptr_map::const_iterator i =
5287 priv_->deleted_data_members_.begin();
5288 i != priv_->deleted_data_members_.end();
5289 ++i)
5290 {
5291 unsigned offset = get_data_member_offset(i->second);
5292 priv_->deleted_dm_by_offset_[offset] = i->second;
5293 }
5294
5295 for (string_decl_base_sptr_map::const_iterator i =
5296 priv_->inserted_data_members_.begin();
5297 i != priv_->inserted_data_members_.end();
5298 ++i)
5299 {
5300 unsigned offset = get_data_member_offset(i->second);
5301 priv_->inserted_dm_by_offset_[offset] = i->second;
5302 }
5303
5304 for (unsigned_decl_base_sptr_map::const_iterator i =
5305 priv_->inserted_dm_by_offset_.begin();
5306 i != priv_->inserted_dm_by_offset_.end();
5307 ++i)
5308 {
5309 unsigned_decl_base_sptr_map::const_iterator j =
5310 priv_->deleted_dm_by_offset_.find(i->first);
5311 if (j != priv_->deleted_dm_by_offset_.end())
5312 {
5313 var_decl_sptr old_dm = is_var_decl(j->second);
5314 var_decl_sptr new_dm = is_var_decl(i->second);
5315 priv_->changed_dm_[i->first] =
5316 compute_diff(old_dm, new_dm, context());
5317 }
5318 }
5319
5320 for (unsigned_var_diff_sptr_map::const_iterator i =
5321 priv_->changed_dm_.begin();
5322 i != priv_->changed_dm_.end();
5323 ++i)
5324 {
5325 priv_->deleted_dm_by_offset_.erase(i->first);
5326 priv_->inserted_dm_by_offset_.erase(i->first);
5327 priv_->deleted_data_members_.erase
5328 (i->second->first_var()->get_anon_dm_reliable_name());
5329 priv_->inserted_data_members_.erase
5330 (i->second->second_var()->get_anon_dm_reliable_name());
5331 }
5332 }
5333 sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
5334 priv_->sorted_subtype_changed_dm_);
5335 sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
5336 priv_->sorted_changed_dm_);
5337
5338 {
5339 edit_script& e = priv_->member_class_tmpls_changes_;
5340
5341 for (vector<deletion>::const_iterator it = e.deletions().begin();
5342 it != e.deletions().end();
5343 ++it)
5344 {
5345 unsigned i = it->index();
5346 decl_base_sptr d =
5347 first_class_or_union()->get_member_class_templates()[i]->
5348 as_class_tdecl();
5349 string name = d->get_name();
5350 ABG_ASSERT(priv_->deleted_member_class_tmpls_.find(name)
5351 == priv_->deleted_member_class_tmpls_.end());
5352 priv_->deleted_member_class_tmpls_[name] = d;
5353 }
5354
5355 for (vector<insertion>::const_iterator it = e.insertions().begin();
5356 it != e.insertions().end();
5357 ++it)
5358 {
5359 for (vector<unsigned>::const_iterator iit =
5360 it->inserted_indexes().begin();
5361 iit != it->inserted_indexes().end();
5362 ++iit)
5363 {
5364 unsigned i = *iit;
5365 decl_base_sptr d =
5366 second_class_or_union()->get_member_class_templates()[i]->
5367 as_class_tdecl();
5368 string name = d->get_name();
5369 ABG_ASSERT(priv_->inserted_member_class_tmpls_.find(name)
5370 == priv_->inserted_member_class_tmpls_.end());
5371 string_decl_base_sptr_map::const_iterator j =
5372 priv_->deleted_member_class_tmpls_.find(name);
5373 if (j != priv_->deleted_member_class_tmpls_.end())
5374 {
5375 if (*j->second != *d)
5376 priv_->changed_member_types_[name]=
5377 compute_diff(j->second, d, context());
5378 priv_->deleted_member_class_tmpls_.erase(j);
5379 }
5380 else
5381 priv_->inserted_member_class_tmpls_[name] = d;
5382 }
5383 }
5384 }
5385 sort_string_diff_sptr_map(priv_->changed_member_types_,
5386 priv_->sorted_changed_member_types_);
5387}
5388
5389/// Allocate the memory for the priv_ pimpl data member of the @ref
5390/// class_or_union_diff class.
5391void
5393{
5394 if (!priv_)
5395 priv_.reset(new priv);
5396}
5397
5398/// Constructor for the @ref class_or_union_diff class.
5399///
5400/// @param first_scope the first @ref class_or_union of the diff node.
5401///
5402/// @param second_scope the second @ref class_or_union of the diff node.
5403///
5404/// @param ctxt the context of the diff.
5405class_or_union_diff::class_or_union_diff(class_or_union_sptr first_scope,
5406 class_or_union_sptr second_scope,
5407 diff_context_sptr ctxt)
5408 : type_diff_base(first_scope, second_scope, ctxt)
5409 //priv_(new priv)
5410{}
5411
5412/// Getter of the private data of the @ref class_or_union_diff type.
5413///
5414/// Note that due to an optimization, the private data of @ref
5415/// class_or_union_diff can be shared among several instances of
5416/// class_or_union_diff, so you should never try to access
5417/// class_or_union_diff::priv directly.
5418///
5419/// When class_or_union_diff::priv is shared, this function returns
5420/// the correct shared one.
5421///
5422/// @return the (possibly) shared private data of the current instance
5423/// of @ref class_or_union_diff.
5424const class_or_union_diff::priv_ptr&
5426{
5427 if (priv_)
5428 return priv_;
5429
5430 // If the current class_or_union_diff::priv member is empty, then look for
5431 // the shared one, from the canonical type.
5432 class_or_union_diff *canonical =
5433 dynamic_cast<class_or_union_diff*>(get_canonical_diff());
5434 ABG_ASSERT(canonical);
5435 ABG_ASSERT(canonical->priv_);
5436
5437 return canonical->priv_;
5438}
5439
5440/// Destructor of class_or_union_diff.
5442{
5443}
5444
5445/// @return the first @ref class_or_union involved in the diff.
5446class_or_union_sptr
5449
5450/// @return the second @ref class_or_union involved in the diff.
5451class_or_union_sptr
5454
5455/// @return the edit script of the member types of the two @ref
5456/// class_or_union.
5457const edit_script&
5459{return get_priv()->member_types_changes_;}
5460
5461/// @return the edit script of the member types of the two @ref
5462/// class_or_union.
5465{return get_priv()->member_types_changes_;}
5466
5467/// @return the edit script of the data members of the two @ref
5468/// class_or_union.
5469const edit_script&
5471{return get_priv()->data_members_changes_;}
5472
5473/// @return the edit script of the data members of the two @ref
5474/// class_or_union.
5477{return get_priv()->data_members_changes_;}
5478
5479/// Getter for the data members that got inserted.
5480///
5481/// @return a map of data members that got inserted.
5484{return get_priv()->inserted_data_members_;}
5485
5486/// Getter for the data members that got deleted.
5487///
5488/// @return a map of data members that got deleted.
5491{return get_priv()->deleted_data_members_;}
5492
5493/// @return the edit script of the member functions of the two @ref
5494/// class_or_union.
5495const edit_script&
5497{return get_priv()->member_fns_changes_;}
5498
5499/// Getter for the virtual members functions that have had a change in
5500/// a sub-type, without having a change in their symbol name.
5501///
5502/// @return a sorted vector of virtual member functions that have a
5503/// sub-type change.
5506{return get_priv()->sorted_changed_member_functions_;}
5507
5508/// @return the edit script of the member functions of the two
5509/// classes.
5512{return get_priv()->member_fns_changes_;}
5513
5514/// @return a map of member functions that got deleted.
5517{return get_priv()->deleted_member_functions_;}
5518
5519/// @return a map of member functions that got inserted.
5522{return get_priv()->inserted_member_functions_;}
5523
5524/// Getter of the map of data members that got replaced by another
5525/// data member. The key of the map is the offset at which the
5526/// element got replaced and the value is a pointer to the @ref
5527/// var_diff representing the replacement of the data member.
5528///
5529/// @return sorted vector of changed data member.
5532{return get_priv()->changed_dm_;}
5533
5534/// Getter of the sorted vector of data members that got replaced by
5535/// another data member.
5536///
5537/// @return sorted vector of changed data member.
5540{return get_priv()->sorted_changed_dm_;}
5541
5542/// Count the number of /filtered/ data members that got replaced by
5543/// another data member.
5544///
5545/// @return the number of changed data member that got filtered out.
5546size_t
5548{return get_priv()->count_filtered_changed_dm(local);}
5549
5550/// Getter of the sorted vector of data members with a (sub-)type change.
5551///
5552/// @return sorted vector of changed data member.
5555{return get_priv()->sorted_subtype_changed_dm_;}
5556
5557/// Count the number of /filtered/ data members with a sub-type change.
5558///
5559/// @return the number of changed data member that got filtered out.
5560size_t
5562{return get_priv()->count_filtered_subtype_changed_dm(local);}
5563
5564/// Get the map of data members that got replaced by anonymous data
5565/// members.
5566///
5567/// The key of a map entry is the name of the replaced data member and
5568/// the value is the anonymous data member that replaces it.
5569///
5570/// @return the map of data members replaced by anonymous data
5571/// members.
5574{return get_priv()->dms_replaced_by_adms_;}
5575
5576/// Get an ordered vector of of data members that got replaced by
5577/// anonymous data members.
5578///
5579/// This returns a vector of pair of two data members: the one that
5580/// was replaced, and the anonymous data member that replaced it.
5581///
5582/// @return the sorted vector data members replaced by anonymous data members.
5585{
5586 if (priv_->dms_replaced_by_adms_ordered_.empty())
5587 {
5588 for (string_decl_base_sptr_map::const_iterator it =
5589 priv_->dms_replaced_by_adms_.begin();
5590 it != priv_->dms_replaced_by_adms_.end();
5591 ++it)
5592 {
5593 const var_decl_sptr dm =
5594 first_class_or_union()->find_data_member(it->first);
5595 ABG_ASSERT(dm);
5596 changed_var_sptr changed_dm(dm, is_data_member(it->second));
5597 priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
5598 }
5599 sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
5600 }
5601
5602 return priv_->dms_replaced_by_adms_ordered_;
5603}
5604
5605/// @return the edit script of the member function templates of the two
5606/// @ref class_or_union.
5607const edit_script&
5609{return get_priv()->member_fn_tmpls_changes_;}
5610
5611/// @return the edit script of the member function templates of the
5612/// two @ref class_or_union.
5615{return get_priv()->member_fn_tmpls_changes_;}
5616
5617/// @return the edit script of the member class templates of the two
5618/// @ref class_or_union.
5619const edit_script&
5621{return get_priv()->member_class_tmpls_changes_;}
5622
5623/// @return the edit script of the member class templates of the two
5624/// @ref class_or_union.
5627{return get_priv()->member_class_tmpls_changes_;}
5628
5629/// Test if the current diff node carries a change.
5630bool
5633
5634/// @return the kind of local change carried by the current diff node.
5635/// The value returned is zero if the current node carries no local
5636/// change.
5637enum change_kind
5639{
5640 ir::change_kind k = ir::NO_CHANGE_KIND;
5642 return k & ir::ALL_LOCAL_CHANGES_MASK;
5643 return ir::NO_CHANGE_KIND;
5644}
5645
5646
5647/// Report the changes carried by the current @ref class_or_union_diff
5648/// node in a textual format.
5649///
5650/// @param out the output stream to write the textual report to.
5651///
5652/// @param indent the number of white space to use as indentation.
5653void
5654class_or_union_diff::report(ostream& out, const string& indent) const
5655{
5656 context()->get_reporter()->report(*this, out, indent);
5657}
5658
5659/// Populate the vector of children node of the @ref diff base type
5660/// sub-object of this instance of @ref class_or_union_diff.
5661///
5662/// The children node can then later be retrieved using
5663/// diff::children_node().
5664void
5666{
5667 // data member changes
5668 for (var_diff_sptrs_type::const_iterator i =
5669 get_priv()->sorted_subtype_changed_dm_.begin();
5670 i != get_priv()->sorted_subtype_changed_dm_.end();
5671 ++i)
5672 if (diff_sptr d = *i)
5674
5675 for (var_diff_sptrs_type::const_iterator i =
5676 get_priv()->sorted_changed_dm_.begin();
5677 i != get_priv()->sorted_changed_dm_.end();
5678 ++i)
5679 if (diff_sptr d = *i)
5681
5682 // member types changes
5683 for (diff_sptrs_type::const_iterator i =
5684 get_priv()->sorted_changed_member_types_.begin();
5685 i != get_priv()->sorted_changed_member_types_.end();
5686 ++i)
5687 if (diff_sptr d = *i)
5689
5690 // member function changes
5691 for (function_decl_diff_sptrs_type::const_iterator i =
5692 get_priv()->sorted_changed_member_functions_.begin();
5693 i != get_priv()->sorted_changed_member_functions_.end();
5694 ++i)
5695 if (diff_sptr d = *i)
5697}
5698
5699// </class_or_union_diff stuff>
5700
5701//<class_diff stuff>
5702
5703/// Clear the lookup tables useful for reporting.
5704///
5705/// This function must be updated each time a lookup table is added or
5706/// removed from the class_diff::priv.
5707void
5708class_diff::clear_lookup_tables(void)
5709{
5710 priv_->deleted_bases_.clear();
5711 priv_->inserted_bases_.clear();
5712 priv_->changed_bases_.clear();
5713}
5714
5715/// Tests if the lookup tables are empty.
5716///
5717/// @return true if the lookup tables are empty, false otherwise.
5718bool
5719class_diff::lookup_tables_empty(void) const
5720{
5721 return (priv_->deleted_bases_.empty()
5722 && priv_->inserted_bases_.empty()
5723 && priv_->changed_bases_.empty());
5724}
5725
5726/// Find a virtual destructor in a map of member functions
5727///
5728/// @param map the map of member functions. Note that the key of the
5729/// map is the member function name. The key is the member function.
5730///
5731/// @return an iterator to the destructor found or, if no virtual destructor
5732/// was found, return map.end()
5733static string_member_function_sptr_map::const_iterator
5734find_virtual_dtor_in_map(const string_member_function_sptr_map& map)
5735{
5736 for (string_member_function_sptr_map::const_iterator i = map.begin();
5737 i !=map.end();
5738 ++i)
5739 {
5740 if (get_member_function_is_dtor(i->second)
5741 && get_member_function_is_virtual(i->second))
5742 return i;
5743 }
5744 return map.end();
5745}
5746
5747/// If the lookup tables are not yet built, walk the differences and
5748/// fill them.
5749void
5750class_diff::ensure_lookup_tables_populated(void) const
5751{
5753
5754 if (!lookup_tables_empty())
5755 return;
5756
5757 {
5758 edit_script& e = get_priv()->base_changes_;
5759
5760 for (vector<deletion>::const_iterator it = e.deletions().begin();
5761 it != e.deletions().end();
5762 ++it)
5763 {
5764 unsigned i = it->index();
5766 first_class_decl()->get_base_specifiers()[i];
5767 string name = b->get_base_class()->get_qualified_name();
5768 ABG_ASSERT(get_priv()->deleted_bases_.find(name)
5769 == get_priv()->deleted_bases_.end());
5770 get_priv()->deleted_bases_[name] = b;
5771 }
5772
5773 for (vector<insertion>::const_iterator it = e.insertions().begin();
5774 it != e.insertions().end();
5775 ++it)
5776 {
5777 for (vector<unsigned>::const_iterator iit =
5778 it->inserted_indexes().begin();
5779 iit != it->inserted_indexes().end();
5780 ++iit)
5781 {
5782 unsigned i = *iit;
5784 second_class_decl()->get_base_specifiers()[i];
5785 string name = b->get_base_class()->get_qualified_name();
5786 ABG_ASSERT(get_priv()->inserted_bases_.find(name)
5787 == get_priv()->inserted_bases_.end());
5788 string_base_sptr_map::const_iterator j =
5789 get_priv()->deleted_bases_.find(name);
5790 if (j != get_priv()->deleted_bases_.end())
5791 {
5792 if (j->second != b)
5793 get_priv()->changed_bases_[name] =
5794 compute_diff(j->second, b, context());
5795 else
5796 // The base class changed place. IOW, the base
5797 // classes got re-arranged. Let's keep track of the
5798 // base classes that moved.
5799 get_priv()->moved_bases_.push_back(b);
5800 get_priv()->deleted_bases_.erase(j);
5801 }
5802 else
5803 get_priv()->inserted_bases_[name] = b;
5804 }
5805 }
5806 }
5807
5808 sort_string_base_sptr_map(get_priv()->deleted_bases_,
5809 get_priv()->sorted_deleted_bases_);
5810 sort_string_base_sptr_map(get_priv()->inserted_bases_,
5811 get_priv()->sorted_inserted_bases_);
5812 sort_string_base_diff_sptr_map(get_priv()->changed_bases_,
5813 get_priv()->sorted_changed_bases_);
5814
5815 {
5816 const class_or_union_diff::priv_ptr &p = class_or_union_diff::get_priv();
5817
5818 edit_script& e = p->member_fns_changes_;
5819
5820 for (vector<deletion>::const_iterator it = e.deletions().begin();
5821 it != e.deletions().end();
5822 ++it)
5823 {
5824 unsigned i = it->index();
5825 method_decl_sptr mem_fn =
5826 first_class_decl()->get_virtual_mem_fns()[i];
5827 string name = mem_fn->get_linkage_name();
5828 if (name.empty())
5829 name = mem_fn->get_pretty_representation();
5830 ABG_ASSERT(!name.empty());
5831 if (p->deleted_member_functions_.find(name)
5832 != p->deleted_member_functions_.end())
5833 continue;
5834 p->deleted_member_functions_[name] = mem_fn;
5835 }
5836
5837 for (vector<insertion>::const_iterator it = e.insertions().begin();
5838 it != e.insertions().end();
5839 ++it)
5840 {
5841 for (vector<unsigned>::const_iterator iit =
5842 it->inserted_indexes().begin();
5843 iit != it->inserted_indexes().end();
5844 ++iit)
5845 {
5846 unsigned i = *iit;
5847
5848 method_decl_sptr mem_fn =
5849 second_class_decl()->get_virtual_mem_fns()[i];
5850 string name = mem_fn->get_linkage_name();
5851 if (name.empty())
5852 name = mem_fn->get_pretty_representation();
5853 ABG_ASSERT(!name.empty());
5854 if (p->inserted_member_functions_.find(name)
5855 != p->inserted_member_functions_.end())
5856 continue;
5857 string_member_function_sptr_map::const_iterator j =
5858 p->deleted_member_functions_.find(name);
5859
5860 if (j != p->deleted_member_functions_.end())
5861 {
5862 if (*j->second != *mem_fn)
5863 p->changed_member_functions_[name] =
5864 compute_diff(static_pointer_cast<function_decl>(j->second),
5865 static_pointer_cast<function_decl>(mem_fn),
5866 context());
5867 p->deleted_member_functions_.erase(j);
5868 }
5869 else
5870 p->inserted_member_functions_[name] = mem_fn;
5871 }
5872 }
5873
5874 // Now walk the allegedly deleted member functions; check if their
5875 // underlying symbols are deleted as well; otherwise, consider
5876 // that the member function in question hasn't been deleted.
5877
5878 // Also, while walking the deleted member functions, we attend at
5879 // a particular cleanup business related to (virtual) C++
5880 // destructors:
5881 //
5882 // In the binary, there can be at least three types of
5883 // destructors, defined in the document
5884 // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#definitions:
5885 //
5886 // 1/ Base object destructor (aka D2 destructor):
5887 //
5888 // "A function that runs the destructors for non-static data
5889 // members of T and non-virtual direct base classes of T. "
5890 //
5891 // 2/ Complete object destructor (aka D1 destructor):
5892 //
5893 // "A function that, in addition to the actions required of a
5894 // base object destructor, runs the destructors for the
5895 // virtual base classes of T."
5896 //
5897 // 3/ Deleting destructor (aka D0 destructor):
5898 //
5899 // "A function that, in addition to the actions required of a
5900 // complete object destructor, calls the appropriate
5901 // deallocation function (i.e,. operator delete) for T."
5902 //
5903 // With binaries generated by GCC, these destructors might be ELF
5904 // clones of each others, meaning, their ELF symbols can be
5905 // aliases.
5906 //
5907 // Also, note that because the actual destructor invoked by user
5908 // code is virtual, it's invoked through the vtable. So the
5909 // presence of the underlying D0, D1, D2 in the binary might vary
5910 // without that variation being an ABI issue, provided that the
5911 // destructor invoked through the vtable is present.
5912 //
5913 // So, a particular virtual destructor implementation for a class
5914 // might disapear and be replaced by another one in a subsequent
5915 // version of the binary. If all versions of the binary have an
5916 // actual virtual destructor, things might be considered fine.
5917 vector<string> to_delete;
5918 corpus_sptr f = context()->get_first_corpus(),
5919 s = context()->get_second_corpus();
5920 if (s)
5921 for (string_member_function_sptr_map::const_iterator i =
5922 deleted_member_fns().begin();
5923 i != deleted_member_fns().end();
5924 ++i)
5925 {
5926 if (get_member_function_is_virtual(i->second))
5927 {
5928 if (get_member_function_is_dtor(i->second))
5929 {
5930 // If a particular virtual destructor is deleted,
5931 // but the new binary still have a virtual
5932 // destructor for that class we consider that things
5933 // are fine. For instance, in the
5934 // tests/data/test-diff-pkg/tbb-4.1-9.20130314.fc22.x86_64--tbb-4.3-3.20141204.fc23.x86_64-report-0.txt
5935 // test, a new D4 destructor replaces the old ones.
5936 // But because the virtual destructor is still
5937 // there, this is not an ABI issue. So let's detect
5938 // this case.
5939 auto it =
5940 find_virtual_dtor_in_map(p->inserted_member_functions_);
5941 if (it != p->inserted_member_functions_.end())
5942 {
5943 // So the deleted virtual destructor is not
5944 // really deleted, because a proper virtual
5945 // destructor was added to the new version.
5946 // Let's remove the deleted/added virtual
5947 // destructor then.
5948 string name =
5949 (!i->second->get_linkage_name().empty())
5950 ? i->second->get_linkage_name()
5951 : i->second->get_pretty_representation();
5952 to_delete.push_back(name);
5953 p->inserted_member_functions_.erase(it);
5954 }
5955 }
5956 continue;
5957 }
5958 // We assume that all non-virtual member functions functions
5959 // we look at here have ELF symbols.
5960 if (!i->second->get_symbol()
5961 || s->lookup_function_symbol(*i->second->get_symbol()))
5962 to_delete.push_back(i->first);
5963 }
5964
5965
5966 for (vector<string>::const_iterator i = to_delete.begin();
5967 i != to_delete.end();
5968 ++i)
5969 p->deleted_member_functions_.erase(*i);
5970
5971 // Do something similar for added functions.
5972 to_delete.clear();
5973 if (f)
5974 for (string_member_function_sptr_map::const_iterator i =
5975 inserted_member_fns().begin();
5976 i != inserted_member_fns().end();
5977 ++i)
5978 {
5979 if (get_member_function_is_virtual(i->second))
5980 continue;
5981 // We assume that all non-virtual member functions functions
5982 // we look at here have ELF symbols.
5983 if (!i->second->get_symbol()
5984 || f->lookup_function_symbol(*i->second->get_symbol()))
5985 to_delete.push_back(i->first);
5986 }
5987
5988 for (vector<string>::const_iterator i = to_delete.begin();
5989 i != to_delete.end();
5990 ++i)
5991 p->inserted_member_functions_.erase(*i);
5992
5993 sort_string_member_function_sptr_map(p->deleted_member_functions_,
5994 p->sorted_deleted_member_functions_);
5995
5996 sort_string_member_function_sptr_map(p->inserted_member_functions_,
5997 p->sorted_inserted_member_functions_);
5998
6000 (p->changed_member_functions_,
6001 p->sorted_changed_member_functions_);
6002 }
6003}
6004
6005/// Allocate the memory for the priv_ pimpl data member of the @ref
6006/// class_diff class.
6007void
6008class_diff::allocate_priv_data()
6009{
6011 if (!priv_)
6012 priv_.reset(new priv);
6013}
6014
6015/// Test whether a given base class has changed. A base class has
6016/// changed if it's in both in deleted *and* inserted bases.
6017///
6018///@param d the declaration for the base class to consider.
6019///
6020/// @return the new base class if the given base class has changed, or
6021/// NULL if it hasn't.
6024{
6025 string qname = d->get_base_class()->get_qualified_name();
6026 string_base_diff_sptr_map::const_iterator it =
6027 changed_bases_.find(qname);
6028
6029 return (it == changed_bases_.end())
6031 : it->second->second_base();
6032
6033}
6034
6035/// Count the number of bases classes whose changes got filtered out.
6036///
6037/// @return the number of bases classes whose changes got filtered
6038/// out.
6039size_t
6041{
6042 size_t num_filtered = 0;
6043 for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
6044 i != sorted_changed_bases_.end();
6045 ++i)
6046 {
6047 diff_sptr diff = *i;
6048 if (diff && diff->is_filtered_out())
6049 ++num_filtered;
6050 }
6051 return num_filtered;
6052}
6053
6054/// Populate the vector of children node of the @ref diff base type
6055/// sub-object of this instance of @ref class_diff.
6056///
6057/// The children node can then later be retrieved using
6058/// diff::children_node().
6059void
6061{
6063
6064 // base class changes.
6065 for (base_diff_sptrs_type::const_iterator i =
6066 get_priv()->sorted_changed_bases_.begin();
6067 i != get_priv()->sorted_changed_bases_.end();
6068 ++i)
6069 if (diff_sptr d = *i)
6071}
6072
6073/// Constructor of class_diff
6074///
6075/// @param first_scope the first class of the diff.
6076///
6077/// @param second_scope the second class of the diff.
6078///
6079/// @param ctxt the diff context to use.
6081 class_decl_sptr second_scope,
6082 diff_context_sptr ctxt)
6083 : class_or_union_diff(first_scope, second_scope, ctxt)
6084 // We don't initialize the priv_ data member here. This is an
6085 // optimization to reduce memory consumption (and also execution
6086 // time) for cases where there are a lot of instances of
6087 // class_diff in the same equivalence class. In compute_diff(),
6088 // the priv_ is set to the priv_ of the canonical diff node.
6089 // See PR libabigail/17948.
6090{}
6091
6092class_diff::~class_diff()
6093{}
6094
6095/// Getter of the private data of the @ref class_diff type.
6096///
6097/// Note that due to an optimization, the private data of @ref
6098/// class_diff can be shared among several instances of class_diff, so
6099/// you should never try to access class_diff::priv directly.
6100///
6101/// When class_diff::priv is shared, this function returns the correct
6102/// shared one.
6103///
6104/// @return the (possibly) shared private data of the current instance
6105/// of class_diff.
6106const class_diff::priv_ptr&
6107class_diff::get_priv() const
6108{
6109 if (priv_)
6110 return priv_;
6111
6112 // If the current class_diff::priv member is empty, then look for
6113 // the shared one, from the canonical type.
6114 class_diff *canonical =
6115 dynamic_cast<class_diff*>(get_canonical_diff());
6116 ABG_ASSERT(canonical);
6117 ABG_ASSERT(canonical->priv_);
6118
6119 return canonical->priv_;
6120}
6121
6122/// @return the pretty representation of the current instance of @ref
6123/// class_diff.
6124const string&
6126{
6127 if (diff::priv_->pretty_representation_.empty())
6128 {
6129 std::ostringstream o;
6130 o << "class_diff["
6131 << first_subject()->get_pretty_representation()
6132 << ", "
6133 << second_subject()->get_pretty_representation()
6134 << "]";
6135 diff::priv_->pretty_representation_ = o.str();
6136 }
6137 return diff::priv_->pretty_representation_;
6138}
6139
6140/// Return true iff the current diff node carries a change.
6141///
6142/// @return true iff the current diff node carries a change.
6143bool
6145{return (first_class_decl() != second_class_decl());}
6146
6147/// @return the kind of local change carried by the current diff node.
6148/// The value returned is zero if the current node carries no local
6149/// change.
6150enum change_kind
6152{
6153 ir::change_kind k = ir::NO_CHANGE_KIND;
6154 if (!equals(*first_class_decl(), *second_class_decl(), &k))
6155 return k & ir::ALL_LOCAL_CHANGES_MASK;
6156 return ir::NO_CHANGE_KIND;
6157}
6158
6159/// @return the first class invoveld in the diff.
6160shared_ptr<class_decl>
6162{return dynamic_pointer_cast<class_decl>(first_subject());}
6163
6164/// Getter of the second class involved in the diff.
6165///
6166/// @return the second class invoveld in the diff
6167shared_ptr<class_decl>
6169{return dynamic_pointer_cast<class_decl>(second_subject());}
6170
6171/// @return the edit script of the bases of the two classes.
6172const edit_script&
6174{return get_priv()->base_changes_;}
6175
6176/// Getter for the deleted base classes of the diff.
6177///
6178/// @return a map containing the deleted base classes, keyed with
6179/// their pretty representation.
6182{return get_priv()->deleted_bases_;}
6183
6184/// Getter for the inserted base classes of the diff.
6185///
6186/// @return a map containing the inserted base classes, keyed with
6187/// their pretty representation.
6190{return get_priv()->inserted_bases_;}
6191
6192/// Getter for the changed base classes of the diff.
6193///
6194/// @return a sorted vector containing the changed base classes
6197{return get_priv()->sorted_changed_bases_;}
6198
6199/// Getter for the vector of bases that "moved".
6200/// That is, the vector of base types which position changed. If this
6201/// vector is not empty, it means the bases of the underlying class
6202/// type got re-ordered.
6203///
6204/// @return the vector of bases that moved.
6205const vector<class_decl::base_spec_sptr>&
6207{return get_priv()->moved_bases_;}
6208
6209/// @return the edit script of the bases of the two classes.
6212{return get_priv()->base_changes_;}
6213
6214/// Produce a basic report about the changes between two class_decl.
6215///
6216/// @param out the output stream to report the changes to.
6217///
6218/// @param indent the string to use as an indentation prefix in the
6219/// report.
6220void
6221class_diff::report(ostream& out, const string& indent) const
6222{
6223 context()->get_reporter()->report(*this, out, indent);
6224}
6225
6226/// Compute the set of changes between two instances of class_decl.
6227///
6228/// Note that the two types must have been created in the same @ref
6229/// environment, otherwise, this function aborts.
6230///
6231/// @param first the first class_decl to consider.
6232///
6233/// @param second the second class_decl to consider.
6234///
6235/// @return changes the resulting changes.
6236///
6237/// @param ctxt the diff context to use.
6240 const class_decl_sptr second,
6241 diff_context_sptr ctxt)
6242{
6245
6246 class_diff_sptr changes(new class_diff(f, s, ctxt));
6247
6248 ctxt->initialize_canonical_diff(changes);
6249 ABG_ASSERT(changes->get_canonical_diff());
6250
6251 if (!ctxt->get_canonical_diff_for(first, second))
6252 {
6253 // Either first or second is a decl-only class; let's set the
6254 // canonical diff here in that case.
6255 diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
6256 ABG_ASSERT(canonical_diff);
6257 ctxt->set_canonical_diff_for(first, second, canonical_diff);
6258 }
6259
6260 // Ok, so this is an optimization. Do not freak out if it looks
6261 // weird, because, well, it does look weird. This speeds up
6262 // greatly, for instance, the test case given at PR
6263 // libabigail/17948.
6264 //
6265 // We are setting the private data of the new instance of class_diff
6266 // (which is 'changes') to the private data of its canonical
6267 // instance. That is, we are sharing the private data of 'changes'
6268 // with the private data of its canonical instance to consume less
6269 // memory in cases where the equivalence class of 'changes' is huge.
6270 //
6271 // But if changes is its own canonical instance, then we initialize
6272 // its private data properly
6273 if (is_class_diff(changes->get_canonical_diff()) == changes.get())
6274 // changes is its own canonical instance, so it gets a brand new
6275 // private data.
6276 changes->allocate_priv_data();
6277 else
6278 {
6279 // changes has a non-empty equivalence class so it's going to
6280 // share its private data with its canonical instance. Next
6281 // time class_diff::get_priv() is invoked, it's going to return
6282 // the shared private data of the canonical instance.
6283 return changes;
6284 }
6285
6286 // Compare base specs
6287 compute_diff(f->get_base_specifiers().begin(),
6288 f->get_base_specifiers().end(),
6289 s->get_base_specifiers().begin(),
6290 s->get_base_specifiers().end(),
6291 changes->base_changes());
6292
6293 // Do *not* compare member types because it generates lots of noise
6294 // and I doubt it's really useful.
6295#if 0
6296 compute_diff(f->get_member_types().begin(),
6297 f->get_member_types().end(),
6298 s->get_member_types().begin(),
6299 s->get_member_types().end(),
6300 changes->member_types_changes());
6301#endif
6302
6303 // Compare data member
6304 compute_diff(f->get_non_static_data_members().begin(),
6305 f->get_non_static_data_members().end(),
6306 s->get_non_static_data_members().begin(),
6307 s->get_non_static_data_members().end(),
6308 changes->data_members_changes());
6309
6310 // Compare virtual member functions
6311 compute_diff(f->get_virtual_mem_fns().begin(),
6312 f->get_virtual_mem_fns().end(),
6313 s->get_virtual_mem_fns().begin(),
6314 s->get_virtual_mem_fns().end(),
6315 changes->member_fns_changes());
6316
6317 // Compare member function templates
6318 compute_diff(f->get_member_function_templates().begin(),
6319 f->get_member_function_templates().end(),
6320 s->get_member_function_templates().begin(),
6321 s->get_member_function_templates().end(),
6322 changes->member_fn_tmpls_changes());
6323
6324 // Likewise, do not compare member class templates
6325#if 0
6326 compute_diff(f->get_member_class_templates().begin(),
6327 f->get_member_class_templates().end(),
6328 s->get_member_class_templates().begin(),
6329 s->get_member_class_templates().end(),
6330 changes->member_class_tmpls_changes());
6331#endif
6332
6333 changes->ensure_lookup_tables_populated();
6334
6335 return changes;
6336}
6337
6338//</class_diff stuff>
6339
6340// <base_diff stuff>
6341
6342/// Populate the vector of children node of the @ref diff base type
6343/// sub-object of this instance of @ref base_diff.
6344///
6345/// The children node can then later be retrieved using
6346/// diff::children_node().
6347void
6350
6351/// @param first the first base spec to consider.
6352///
6353/// @param second the second base spec to consider.
6354///
6355/// @param ctxt the context of the diff. Note that this context
6356/// object must stay alive at least during the life time of the
6357/// current instance of @ref base_diff. Otherwise memory corruption
6358/// issues occur.
6361 class_diff_sptr underlying,
6362 diff_context_sptr ctxt)
6363 : diff(first, second, ctxt),
6364 priv_(new priv(underlying))
6365{}
6366
6367/// Getter for the first base spec of the diff object.
6368///
6369/// @return the first base specifier for the diff object.
6372{return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
6373
6374/// Getter for the second base spec of the diff object.
6375///
6376/// @return the second base specifier for the diff object.
6379{return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
6380
6381/// Getter for the diff object for the diff of the underlying base
6382/// classes.
6383///
6384/// @return the diff object for the diff of the underlying base
6385/// classes.
6386const class_diff_sptr
6388{return priv_->underlying_class_diff_;}
6389
6390/// Setter for the diff object for the diff of the underlyng base
6391/// classes.
6392///
6393/// @param d the new diff object for the diff of the underlying base
6394/// classes.
6395void
6397{priv_->underlying_class_diff_ = d;}
6398
6399/// @return the pretty representation for the current instance of @ref
6400/// base_diff.
6401const string&
6403{
6404 if (diff::priv_->pretty_representation_.empty())
6405 {
6406 std::ostringstream o;
6407 o << "base_diff["
6408 << first_subject()->get_pretty_representation()
6409 << ", "
6410 << second_subject()->get_pretty_representation()
6411 << "]";
6412 diff::priv_->pretty_representation_ = o.str();
6413 }
6414 return diff::priv_->pretty_representation_;
6415}
6416
6417/// Return true iff the current diff node carries a change.
6418///
6419/// Return true iff the current diff node carries a change.
6420bool
6422{return first_base() != second_base();}
6423
6424/// @return the kind of local change carried by the current diff node.
6425/// The value returned is zero if the current node carries no local
6426/// change.
6427enum change_kind
6429{
6430 ir::change_kind k = ir::NO_CHANGE_KIND;
6431 if (!equals(*first_base(), *second_base(), &k))
6432 return k & ir::ALL_LOCAL_CHANGES_MASK;
6433 return ir::NO_CHANGE_KIND;
6434}
6435
6436/// Generates a report for the current instance of base_diff.
6437///
6438/// @param out the output stream to send the report to.
6439///
6440/// @param indent the string to use for indentation.
6441void
6442base_diff::report(ostream& out, const string& indent) const
6443{
6444 context()->get_reporter()->report(*this, out, indent);
6445}
6446
6447/// Constructs the diff object representing a diff between two base
6448/// class specifications.
6449///
6450/// Note that the two artifacts must have been created in the same
6451/// @ref environment, otherwise, this function aborts.
6452///
6453/// @param first the first base class specification.
6454///
6455/// @param second the second base class specification.
6456///
6457/// @param ctxt the content of the diff.
6458///
6459/// @return the resulting diff object.
6462 const class_decl::base_spec_sptr second,
6463 diff_context_sptr ctxt)
6464{
6465 class_diff_sptr cl = compute_diff(first->get_base_class(),
6466 second->get_base_class(),
6467 ctxt);
6468 base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
6469
6470 ctxt->initialize_canonical_diff(changes);
6471
6472 return changes;
6473}
6474
6475// </base_diff stuff>
6476
6477
6478// <union_diff stuff>
6479
6480/// Clear the lookup tables useful for reporting.
6481///
6482/// This function must be updated each time a lookup table is added or
6483/// removed from the union_diff::priv.
6484void
6485union_diff::clear_lookup_tables(void)
6487
6488/// Tests if the lookup tables are empty.
6489///
6490/// @return true if the lookup tables are empty, false otherwise.
6491bool
6492union_diff::lookup_tables_empty(void) const
6494
6495/// If the lookup tables are not yet built, walk the differences and
6496/// fill them.
6497void
6498union_diff::ensure_lookup_tables_populated(void) const
6500
6501/// Allocate the memory for the priv_ pimpl data member of the @ref
6502/// union_diff class.
6503void
6504union_diff::allocate_priv_data()
6505{
6507}
6508
6509/// Constructor for the @ref union_diff type.
6510///
6511/// @param first_union the first object of the comparison.
6512///
6513/// @param second_union the second object of the comparison.
6514///
6515/// @param ctxt the context of the comparison.
6516union_diff::union_diff(union_decl_sptr first_union,
6517 union_decl_sptr second_union,
6518 diff_context_sptr ctxt)
6519 : class_or_union_diff(first_union, second_union, ctxt)
6520{}
6521
6522/// Destructor of the union_diff node.
6524{}
6525
6526/// @return the first object of the comparison.
6527union_decl_sptr
6529{return is_union_type(first_subject());}
6530
6531/// @return the second object of the comparison.
6532union_decl_sptr
6534{return is_union_type(second_subject());}
6535
6536/// @return the pretty representation of the current diff node.
6537const string&
6539{
6540 if (diff::priv_->pretty_representation_.empty())
6541 {
6542 std::ostringstream o;
6543 o << "union_diff["
6544 << first_subject()->get_pretty_representation()
6545 << ", "
6546 << second_subject()->get_pretty_representation()
6547 << "]";
6548 diff::priv_->pretty_representation_ = o.str();
6549 }
6550 return diff::priv_->pretty_representation_;
6551}
6552
6553/// Report the changes carried by the current @ref union_diff node in
6554/// a textual format.
6555///
6556/// @param out the output stream to write the textual report to.
6557///
6558/// @param indent the number of white space to use as indentation.
6559void
6560union_diff::report(ostream& out, const string& indent) const
6561{
6562 context()->get_reporter()->report(*this, out, indent);
6563}
6564
6565/// Compute the difference between two @ref union_decl types.
6566///
6567/// Note that the two types must hav been created in the same
6568/// environment, otherwise, this function aborts.
6569///
6570/// @param first the first @ref union_decl to consider.
6571///
6572/// @param second the second @ref union_decl to consider.
6573///
6574/// @param ctxt the context of the diff to use.
6575union_diff_sptr
6576compute_diff(const union_decl_sptr first,
6577 const union_decl_sptr second,
6578 diff_context_sptr ctxt)
6579{
6580 union_diff_sptr changes(new union_diff(first, second, ctxt));
6581
6582 ctxt->initialize_canonical_diff(changes);
6583 ABG_ASSERT(changes->get_canonical_diff());
6584
6585 // Ok, so this is an optimization. Do not freak out if it looks
6586 // weird, because, well, it does look weird. This speeds up
6587 // greatly, for instance, the test case given at PR
6588 // libabigail/17948.
6589 //
6590 // We are setting the private data of the new instance of class_diff
6591 // (which is 'changes') to the private data of its canonical
6592 // instance. That is, we are sharing the private data of 'changes'
6593 // with the private data of its canonical instance to consume less
6594 // memory in cases where the equivalence class of 'changes' is huge.
6595 //
6596 // But if changes is its own canonical instance, then we initialize
6597 // its private data properly.
6598 if (is_union_diff(changes->get_canonical_diff()) == changes.get())
6599 // changes is its own canonical instance, so it gets a brand new
6600 // private data.
6601 changes->allocate_priv_data();
6602 else
6603 {
6604 // changes has a non-empty equivalence class so it's going to
6605 // share its private data with its canonical instance. Next
6606 // time class_diff::get_priv() is invoked, it's going to return
6607 // the shared private data of the canonical instance.
6608 return changes;
6609 }
6610
6611 // Compare data member
6612 compute_diff(first->get_non_static_data_members().begin(),
6613 first->get_non_static_data_members().end(),
6614 second->get_non_static_data_members().begin(),
6615 second->get_non_static_data_members().end(),
6616 changes->data_members_changes());
6617
6618#if 0
6619 // Compare member functions
6620 compute_diff(first->get_mem_fns().begin(),
6621 first->get_mem_fns().end(),
6622 second->get_mem_fns().begin(),
6623 second->get_mem_fns().end(),
6624 changes->member_fns_changes());
6625
6626 // Compare member function templates
6627 compute_diff(first->get_member_function_templates().begin(),
6628 first->get_member_function_templates().end(),
6629 second->get_member_function_templates().begin(),
6630 second->get_member_function_templates().end(),
6631 changes->member_fn_tmpls_changes());
6632#endif
6633
6634 changes->ensure_lookup_tables_populated();
6635
6636 return changes;
6637}
6638
6639// </union_diff stuff>
6640
6641//<scope_diff stuff>
6642
6643/// Clear the lookup tables that are useful for reporting.
6644///
6645/// This function must be updated each time a lookup table is added or
6646/// removed.
6647void
6648scope_diff::clear_lookup_tables()
6649{
6650 priv_->deleted_types_.clear();
6651 priv_->deleted_decls_.clear();
6652 priv_->inserted_types_.clear();
6653 priv_->inserted_decls_.clear();
6654 priv_->changed_types_.clear();
6655 priv_->changed_decls_.clear();
6656 priv_->removed_types_.clear();
6657 priv_->removed_decls_.clear();
6658 priv_->added_types_.clear();
6659 priv_->added_decls_.clear();
6660}
6661
6662/// Tests if the lookup tables are empty.
6663///
6664/// This function must be updated each time a lookup table is added or
6665/// removed.
6666///
6667/// @return true iff all the lookup tables are empty.
6668bool
6669scope_diff::lookup_tables_empty() const
6670{
6671 return (priv_->deleted_types_.empty()
6672 && priv_->deleted_decls_.empty()
6673 && priv_->inserted_types_.empty()
6674 && priv_->inserted_decls_.empty()
6675 && priv_->changed_types_.empty()
6676 && priv_->changed_decls_.empty()
6677 && priv_->removed_types_.empty()
6678 && priv_->removed_decls_.empty()
6679 && priv_->added_types_.empty()
6680 && priv_->added_decls_.empty());
6681}
6682
6683/// If the lookup tables are not yet built, walk the member_changes_
6684/// member and fill the lookup tables.
6685void
6686scope_diff::ensure_lookup_tables_populated()
6687{
6688 if (!lookup_tables_empty())
6689 return;
6690
6691 edit_script& e = priv_->member_changes_;
6692
6693 // Populate deleted types & decls lookup tables.
6694 for (const auto& deletion : e.deletions())
6695 {
6696 unsigned i = deletion.index();
6697 decl_base_sptr decl = deleted_member_at(i);
6698 string qname = decl->get_qualified_name();
6699 if (is_type(decl))
6700 {
6701 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
6702 if (klass_decl && klass_decl->get_is_declaration_only())
6703 continue;
6704
6705 // Unique types are artifically put in a scope because they
6706 // have to belong somewhere, but they should not be
6707 // considered added/removed from any scope because they are
6708 // artificial and always present in the system.
6709 if (is_unique_type(is_type(decl)))
6710 continue;
6711
6712 ABG_ASSERT(priv_->deleted_types_.find(qname)
6713 == priv_->deleted_types_.end());
6714 priv_->deleted_types_[qname] = decl;
6715 }
6716 else
6717 {
6718 ABG_ASSERT(priv_->deleted_decls_.find(qname)
6719 == priv_->deleted_decls_.end());
6720 priv_->deleted_decls_[qname] = decl;
6721 }
6722 }
6723
6724 // Populate inserted types & decls as well as chagned types & decls
6725 // lookup tables.
6726 for (vector<insertion>::const_iterator it = e.insertions().begin();
6727 it != e.insertions().end();
6728 ++it)
6729 {
6730 for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
6731 i != it->inserted_indexes().end();
6732 ++i)
6733 {
6734 decl_base_sptr decl = inserted_member_at(i);
6735 string qname = decl->get_qualified_name();
6736 if (is_type(decl))
6737 {
6738 class_decl_sptr klass_decl =
6739 dynamic_pointer_cast<class_decl>(decl);
6740 if (klass_decl && klass_decl->get_is_declaration_only())
6741 continue;
6742
6743 // Unique types are artifically put in a scope because they
6744 // have to belong somewhere, but they should not be
6745 // considered added/removed from any scope because they are
6746 // artificial and always present in the system.
6747 if (is_unique_type(is_type(decl)))
6748 continue;
6749
6750 ABG_ASSERT(priv_->inserted_types_.find(qname)
6751 == priv_->inserted_types_.end());
6752 string_decl_base_sptr_map::const_iterator j =
6753 priv_->deleted_types_.find(qname);
6754 if (j != priv_->deleted_types_.end())
6755 {
6756 if (*j->second != *decl)
6757 priv_->changed_types_[qname] =
6758 compute_diff(j->second, decl, context());
6759 priv_->deleted_types_.erase(j);
6760 }
6761 else
6762 priv_->inserted_types_[qname] = decl;
6763 }
6764 else
6765 {
6766 ABG_ASSERT(priv_->inserted_decls_.find(qname)
6767 == priv_->inserted_decls_.end());
6768 string_decl_base_sptr_map::const_iterator j =
6769 priv_->deleted_decls_.find(qname);
6770 if (j != priv_->deleted_decls_.end())
6771 {
6772 if (*j->second != *decl)
6773 priv_->changed_decls_[qname] =
6774 compute_diff(j->second, decl, context());
6775 priv_->deleted_decls_.erase(j);
6776 }
6777 else
6778 priv_->inserted_decls_[qname] = decl;
6779 }
6780 }
6781 }
6782
6783 sort_string_diff_sptr_map(priv_->changed_decls_,
6784 priv_->sorted_changed_decls_);
6785 sort_string_diff_sptr_map(priv_->changed_types_,
6786 priv_->sorted_changed_types_);
6787
6788 // Populate removed types/decls lookup tables
6789 for (string_decl_base_sptr_map::const_iterator i =
6790 priv_->deleted_types_.begin();
6791 i != priv_->deleted_types_.end();
6792 ++i)
6793 {
6794 string_decl_base_sptr_map::const_iterator r =
6795 priv_->inserted_types_.find(i->first);
6796 if (r == priv_->inserted_types_.end())
6797 priv_->removed_types_[i->first] = i->second;
6798 }
6799 for (string_decl_base_sptr_map::const_iterator i =
6800 priv_->deleted_decls_.begin();
6801 i != priv_->deleted_decls_.end();
6802 ++i)
6803 {
6804 string_decl_base_sptr_map::const_iterator r =
6805 priv_->inserted_decls_.find(i->first);
6806 if (r == priv_->inserted_decls_.end())
6807 priv_->removed_decls_[i->first] = i->second;
6808 }
6809
6810 // Populate added types/decls.
6811 for (string_decl_base_sptr_map::const_iterator i =
6812 priv_->inserted_types_.begin();
6813 i != priv_->inserted_types_.end();
6814 ++i)
6815 {
6816 string_decl_base_sptr_map::const_iterator r =
6817 priv_->deleted_types_.find(i->first);
6818 if (r == priv_->deleted_types_.end())
6819 priv_->added_types_[i->first] = i->second;
6820 }
6821 for (string_decl_base_sptr_map::const_iterator i =
6822 priv_->inserted_decls_.begin();
6823 i != priv_->inserted_decls_.end();
6824 ++i)
6825 {
6826 string_decl_base_sptr_map::const_iterator r =
6827 priv_->deleted_decls_.find(i->first);
6828 if (r == priv_->deleted_decls_.end())
6829 priv_->added_decls_[i->first] = i->second;
6830 }
6831}
6832
6833/// Populate the vector of children node of the @ref diff base type
6834/// sub-object of this instance of @ref scope_diff.
6835///
6836/// The children node can then later be retrieved using
6837/// diff::children_node().
6838void
6840{
6841 for (diff_sptrs_type::const_iterator i = changed_types().begin();
6842 i != changed_types().end();
6843 ++i)
6844 if (*i)
6846
6847 for (diff_sptrs_type::const_iterator i = changed_decls().begin();
6848 i != changed_decls().end();
6849 ++i)
6850 if (*i)
6852}
6853
6854/// Constructor for scope_diff
6855///
6856/// @param first_scope the first scope to consider for the diff.
6857///
6858/// @param second_scope the second scope to consider for the diff.
6859///
6860/// @param ctxt the diff context to use. Note that this context
6861/// object must stay alive at least during the life time of the
6862/// current instance of @ref scope_diff. Otherwise memory corruption
6863/// issues occur.
6865 scope_decl_sptr second_scope,
6866 diff_context_sptr ctxt)
6867 : diff(first_scope, second_scope, ctxt),
6868 priv_(new priv)
6869{}
6870
6871/// Getter for the first scope of the diff.
6872///
6873/// @return the first scope of the diff.
6874const scope_decl_sptr
6876{return dynamic_pointer_cast<scope_decl>(first_subject());}
6877
6878/// Getter for the second scope of the diff.
6879///
6880/// @return the second scope of the diff.
6881const scope_decl_sptr
6883{return dynamic_pointer_cast<scope_decl>(second_subject());}
6884
6885/// Accessor of the edit script of the members of a scope.
6886///
6887/// This edit script is computed using the equality operator that
6888/// applies to shared_ptr<decl_base>.
6889///
6890/// That has interesting consequences. For instance, consider two
6891/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
6892/// S0'. C0 and C0' have the same qualified name, but have different
6893/// members. The edit script will consider that C0 has been deleted
6894/// from S0 and that S0' has been inserted. This is a low level
6895/// canonical representation of the changes; a higher level
6896/// representation would give us a simpler way to say "the class C0
6897/// has been modified into C0'". But worry not. We do have such
6898/// higher representation as well; that is what changed_types() and
6899/// changed_decls() is for.
6900///
6901/// @return the edit script of the changes encapsulatd in this
6902/// instance of scope_diff.
6903const edit_script&
6905{return priv_->member_changes_;}
6906
6907/// Accessor of the edit script of the members of a scope.
6908///
6909/// This edit script is computed using the equality operator that
6910/// applies to shared_ptr<decl_base>.
6911///
6912/// That has interesting consequences. For instance, consider two
6913/// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
6914/// S0'. C0 and C0' have the same qualified name, but have different
6915/// members. The edit script will consider that C0 has been deleted
6916/// from S0 and that S0' has been inserted. This is a low level
6917/// canonical representation of the changes; a higher level
6918/// representation would give us a simpler way to say "the class C0
6919/// has been modified into C0'". But worry not. We do have such
6920/// higher representation as well; that is what changed_types() and
6921/// changed_decls() is for.
6922///
6923/// @return the edit script of the changes encapsulatd in this
6924/// instance of scope_diff.
6927{return priv_->member_changes_;}
6928
6929/// Accessor that eases the manipulation of the edit script associated
6930/// to this instance. It returns the scope member that is reported
6931/// (in the edit script) as deleted at a given index.
6932///
6933/// @param i the index (in the edit script) of an element of the first
6934/// scope that has been reported as being delete.
6935///
6936/// @return the scope member that has been reported by the edit script
6937/// as being deleted at index i.
6938const decl_base_sptr
6940{
6941 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
6942 return scope->get_member_decls()[i];
6943}
6944
6945/// Accessor that eases the manipulation of the edit script associated
6946/// to this instance. It returns the scope member (of the first scope
6947/// of this diff instance) that is reported (in the edit script) as
6948/// deleted at a given iterator.
6949///
6950/// @param i the iterator of an element of the first scope that has
6951/// been reported as being delete.
6952///
6953/// @return the scope member of the first scope of this diff that has
6954/// been reported by the edit script as being deleted at iterator i.
6955const decl_base_sptr
6956scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
6957{return deleted_member_at(i->index());}
6958
6959/// Accessor that eases the manipulation of the edit script associated
6960/// to this instance. It returns the scope member (of the second
6961/// scope of this diff instance) that is reported as being inserted
6962/// from a given index.
6963///
6964/// @param i the index of an element of the second scope this diff
6965/// that has been reported by the edit script as being inserted.
6966///
6967/// @return the scope member of the second scope of this diff that has
6968/// been reported as being inserted from index i.
6969const decl_base_sptr
6971{
6972 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
6973 return scope->get_member_decls()[i];
6974}
6975
6976/// Accessor that eases the manipulation of the edit script associated
6977/// to this instance. It returns the scope member (of the second
6978/// scope of this diff instance) that is reported as being inserted
6979/// from a given iterator.
6980///
6981/// @param i the iterator of an element of the second scope this diff
6982/// that has been reported by the edit script as being inserted.
6983///
6984/// @return the scope member of the second scope of this diff that has
6985/// been reported as being inserted from iterator i.
6986const decl_base_sptr
6987scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
6988{return inserted_member_at(*i);}
6989
6990/// @return a sorted vector of the types which content has changed
6991/// from the first scope to the other.
6992const diff_sptrs_type&
6994{return priv_->sorted_changed_types_;}
6995
6996/// @return a sorted vector of the decls which content has changed
6997/// from the first scope to the other.
6998const diff_sptrs_type&
7000{return priv_->sorted_changed_decls_;}
7001
7003scope_diff::removed_types() const
7004{return priv_->removed_types_;}
7005
7007scope_diff::removed_decls() const
7008{return priv_->removed_decls_;}
7009
7011scope_diff::added_types() const
7012{return priv_->added_types_;}
7013
7015scope_diff::added_decls() const
7016{return priv_->added_decls_;}
7017
7018/// @return the pretty representation for the current instance of @ref
7019/// scope_diff.
7020const string&
7022{
7023 if (diff::priv_->pretty_representation_.empty())
7024 {
7025 std::ostringstream o;
7026 o << "scope_diff["
7027 << first_subject()->get_pretty_representation()
7028 << ", "
7029 << second_subject()->get_pretty_representation()
7030 << "]";
7031 diff::priv_->pretty_representation_ = o.str();
7032 }
7033 return diff::priv_->pretty_representation_;
7034}
7035
7036/// Return true iff the current diff node carries a change.
7037///
7038/// Return true iff the current diff node carries a change.
7039bool
7041{
7042 // TODO: add the number of really removed/added stuff.
7043 return changed_types().size() + changed_decls().size();
7044}
7045
7046/// @return the kind of local change carried by the current diff node.
7047/// The value returned is zero if the current node carries no local
7048/// change.
7049enum change_kind
7051{
7052 ir::change_kind k = ir::NO_CHANGE_KIND;
7053 if (!equals(*first_scope(), *second_scope(), &k))
7054 return k & ir::ALL_LOCAL_CHANGES_MASK;
7055 return ir::NO_CHANGE_KIND;
7056}
7057
7058/// Report the changes of one scope against another.
7059///
7060/// @param out the out stream to report the changes to.
7061///
7062/// @param indent the string to use for indentation.
7063void
7064scope_diff::report(ostream& out, const string& indent) const
7065{
7066 context()->get_reporter()->report(*this, out, indent);
7067}
7068
7069/// Compute the diff between two scopes.
7070///
7071/// Note that the two decls must have been created in the same @ref
7072/// environment, otherwise, this function aborts.
7073///
7074/// @param first the first scope to consider in computing the diff.
7075///
7076/// @param second the second scope to consider in the diff
7077/// computation. The second scope is diffed against the first scope.
7078///
7079/// @param d a pointer to the diff object to populate with the
7080/// computed diff.
7081///
7082/// @return return the populated \a d parameter passed to this
7083/// function.
7084///
7085/// @param ctxt the diff context to use.
7088 const scope_decl_sptr second,
7090 diff_context_sptr ctxt)
7091{
7092 ABG_ASSERT(d->first_scope() == first && d->second_scope() == second);
7093
7094 compute_diff(first->get_member_decls().begin(),
7095 first->get_member_decls().end(),
7096 second->get_member_decls().begin(),
7097 second->get_member_decls().end(),
7098 d->member_changes());
7099
7100 d->ensure_lookup_tables_populated();
7101 d->context(ctxt);
7102
7103 return d;
7104}
7105
7106/// Compute the diff between two scopes.
7107///
7108/// Note that the two decls must have been created in the same @ref
7109/// environment, otherwise, this function aborts.
7110///
7111/// @param first_scope the first scope to consider in computing the diff.
7112///
7113/// @param second_scope the second scope to consider in the diff
7114/// computation. The second scope is diffed against the first scope.
7115///
7116/// @param ctxt the diff context to use.
7117///
7118/// @return return the resulting diff
7121 const scope_decl_sptr second_scope,
7122 diff_context_sptr ctxt)
7123{
7124 scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
7125 d = compute_diff(first_scope, second_scope, d, ctxt);
7126 ctxt->initialize_canonical_diff(d);
7127 return d;
7128}
7129
7130//</scope_diff stuff>
7131
7132// <fn_parm_diff stuff>
7133
7134/// Constructor for the fn_parm_diff type.
7135///
7136/// @param first the first subject of the diff.
7137///
7138/// @param second the second subject of the diff.
7139///
7140/// @param ctxt the context of the diff. Note that this context
7141/// object must stay alive at least during the life time of the
7142/// current instance of @ref fn_parm_diff. Otherwise memory
7143/// corruption issues occur.
7144fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
7145 const function_decl::parameter_sptr second,
7146 diff_context_sptr ctxt)
7147 : decl_diff_base(first, second, ctxt),
7148 priv_(new priv)
7149{
7150 ABG_ASSERT(first->get_index() == second->get_index());
7151 priv_->type_diff = compute_diff(first->get_type(),
7152 second->get_type(),
7153 ctxt);
7154 ABG_ASSERT(priv_->type_diff);
7155}
7156
7157/// Getter for the first subject of this diff node.
7158///
7159/// @return the first function_decl::parameter_sptr subject of this
7160/// diff node.
7163{return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
7164
7165/// Getter for the second subject of this diff node.
7166///
7167/// @return the second function_decl::parameter_sptr subject of this
7168/// diff node.
7171{return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
7172
7173/// Getter for the diff representing the changes on the type of the
7174/// function parameter involved in the current instance of @ref
7175/// fn_parm_diff.
7176///
7177/// @return a diff_sptr representing the changes on the type of the
7178/// function parameter we are interested in.
7181{return priv_->type_diff;}
7182
7183/// Build and return a textual representation of the current instance
7184/// of @ref fn_parm_diff.
7185///
7186/// @return the string representing the current instance of
7187/// fn_parm_diff.
7188const string&
7190{
7191 if (diff::priv_->pretty_representation_.empty())
7192 {
7193 std::ostringstream o;
7194 o << "function_parameter_diff["
7195 << first_subject()->get_pretty_representation()
7196 << ", "
7197 << second_subject()->get_pretty_representation()
7198 << "]";
7199 diff::priv_->pretty_representation_ = o.str();
7200 }
7201 return diff::priv_->pretty_representation_;
7202}
7203
7204/// Return true iff the current diff node carries a change.
7205///
7206/// @return true iff the current diff node carries a change.
7207bool
7209{return *first_parameter() != *second_parameter();}
7210
7211/// Check if the current diff node carries a local change.
7212///
7213/// @return the kind of local change carried by the current diff node.
7214/// The value returned is zero if the current node carries no local
7215/// change.
7216enum change_kind
7218{
7219 ir::change_kind k = ir::NO_CHANGE_KIND;
7220 if (!equals(*first_parameter(), *second_parameter(), &k))
7221 return k & ir::ALL_LOCAL_CHANGES_MASK;
7222 return ir::NO_CHANGE_KIND;
7223}
7224
7225/// Emit a textual report about the current fn_parm_diff instance.
7226///
7227/// @param out the output stream to emit the textual report to.
7228///
7229/// @param indent the indentation string to use in the report.
7230void
7231fn_parm_diff::report(ostream& out, const string& indent) const
7232{
7233 context()->get_reporter()->report(*this, out, indent);
7234}
7235
7236/// Populate the vector of children nodes of the @ref diff base type
7237/// sub-object of this instance of @ref fn_parm_diff.
7238///
7239/// The children nodes can then later be retrieved using
7240/// diff::children_nodes()
7241void
7243{
7244 if (type_diff())
7246}
7247
7248/// Compute the difference between two function_decl::parameter_sptr;
7249/// that is, between two function parameters. Return a resulting
7250/// fn_parm_diff_sptr that represents the changes.
7251///
7252/// Note that the two decls must have been created in the same @ref
7253/// environment, otherwise, this function aborts.
7254///
7255/// @param first the first subject of the diff.
7256///
7257/// @param second the second subject of the diff.
7258///
7259/// @param ctxt the context of the diff.
7260///
7261/// @return fn_parm_diff_sptr the resulting diff node.
7264 const function_decl::parameter_sptr second,
7265 diff_context_sptr ctxt)
7266{
7267 if (!first || !second)
7268 return fn_parm_diff_sptr();
7269
7270 fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
7271 ctxt->initialize_canonical_diff(result);
7272
7273 return result;
7274}
7275// </fn_parm_diff stuff>
7276
7277// <function_type_diff stuff>
7278
7279void
7280function_type_diff::ensure_lookup_tables_populated()
7281{
7282 priv_->return_type_diff_ =
7283 compute_diff(first_function_type()->get_return_type(),
7284 second_function_type()->get_return_type(),
7285 context());
7286
7287 string parm_name;
7289 for (vector<deletion>::const_iterator i =
7290 priv_->parm_changes_.deletions().begin();
7291 i != priv_->parm_changes_.deletions().end();
7292 ++i)
7293 {
7294 parm = *(first_function_type()->get_first_parm()
7295 + i->index());
7296 parm_name = parm->get_name_id();
7297 // If for a reason the type name is empty we want to know and
7298 // fix that.
7299 ABG_ASSERT(!parm_name.empty());
7300 priv_->deleted_parms_[parm_name] = parm;
7301 priv_->deleted_parms_by_id_[parm->get_index()] = parm;
7302 }
7303
7304 for (vector<insertion>::const_iterator i =
7305 priv_->parm_changes_.insertions().begin();
7306 i != priv_->parm_changes_.insertions().end();
7307 ++i)
7308 {
7309 for (vector<unsigned>::const_iterator j =
7310 i->inserted_indexes().begin();
7311 j != i->inserted_indexes().end();
7312 ++j)
7313 {
7314 parm = *(second_function_type()->get_first_parm() + *j);
7315 parm_name = parm->get_name_id();
7316 // If for a reason the type name is empty we want to know and
7317 // fix that.
7318 ABG_ASSERT(!parm_name.empty());
7319 {
7320 string_parm_map::const_iterator k =
7321 priv_->deleted_parms_.find(parm_name);
7322 if (k != priv_->deleted_parms_.end())
7323 {
7324 if (*k->second != *parm)
7325 priv_->subtype_changed_parms_[parm_name] =
7326 compute_diff(k->second, parm, context());
7327 priv_->deleted_parms_.erase(parm_name);
7328 }
7329 else
7330 priv_->added_parms_[parm_name] = parm;
7331 }
7332 {
7333 unsigned_parm_map::const_iterator k =
7334 priv_->deleted_parms_by_id_.find(parm->get_index());
7335 if (k != priv_->deleted_parms_by_id_.end())
7336 {
7337 if (*k->second != *parm
7338 && (k->second->get_name_id() != parm_name))
7339 priv_->changed_parms_by_id_[parm->get_index()] =
7340 compute_diff(k->second, parm, context());
7341 priv_->added_parms_.erase(parm_name);
7342 priv_->deleted_parms_.erase(k->second->get_name_id());
7343 priv_->deleted_parms_by_id_.erase(parm->get_index());
7344 }
7345 else
7346 priv_->added_parms_by_id_[parm->get_index()] = parm;
7347 }
7348 }
7349 }
7350
7351 sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
7352 priv_->sorted_subtype_changed_parms_);
7353 sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
7354 priv_->sorted_changed_parms_by_id_);
7355 sort_string_parm_map(priv_->deleted_parms_,
7356 priv_->sorted_deleted_parms_);
7357
7358 sort_string_parm_map(priv_->added_parms_,
7359 priv_->sorted_added_parms_);
7360}
7361
7362/// In the vector of deleted parameters, get the one that is at a given
7363/// index.
7364///
7365/// @param i the index of the deleted parameter to get.
7366///
7367/// @return the parameter returned.
7369function_type_diff::deleted_parameter_at(int i) const
7370{return first_function_type()->get_parameters()[i];}
7371
7372/// Getter for the sorted vector of deleted parameters.
7373///
7374/// @return the sorted vector of deleted parameters.
7375const vector<function_decl::parameter_sptr>&
7377{return priv_->sorted_deleted_parms_;}
7378
7379/// Getter for the sorted vector of added parameters .
7380///
7381/// @return the sorted vector of added parameters.
7382const vector<function_decl::parameter_sptr>&
7384{return priv_->sorted_added_parms_;}
7385
7386/// In the vector of inserted parameters, get the one that is at a
7387/// given index.
7388///
7389/// @param i the index of the inserted parameter to get.
7390///
7391/// @return the parameter returned.
7393function_type_diff::inserted_parameter_at(int i) const
7394{return second_function_type()->get_parameters()[i];}
7395
7396/// Consutrctor of the @ref function_type type.
7397///
7398/// @param first the first @ref function_type subject of the diff to
7399/// create.
7400///
7401/// @param second the second @ref function_type subject of the diff to
7402/// create.
7403///
7404/// @param ctxt the diff context to be used by the newly created
7405/// instance of function_type_diff. Note that this context object
7406/// must stay alive at least during the life time of the current
7407/// instance of @ref function_type_diff. Otherwise memory corruption
7408/// issues occur.
7410 const function_type_sptr second,
7411 diff_context_sptr ctxt)
7412 : type_diff_base(first, second, ctxt),
7413 priv_(new priv)
7414{}
7415
7416/// Getter for the first subject of the diff.
7417///
7418/// @return the first function type involved in the diff.
7421{return dynamic_pointer_cast<function_type>(first_subject());}
7422
7423/// Getter for the second subject of the diff.
7424///
7425/// @return the second function type involved in the diff.
7428{return dynamic_pointer_cast<function_type>(second_subject());}
7429
7430/// Getter for the diff of the return types of the two function types
7431/// of the current diff.
7432///
7433/// @return the diff of the return types of the two function types of
7434/// the current diff.
7435const diff_sptr
7437{return priv_->return_type_diff_;}
7438
7439/// Getter for the map of function parameter changes of the current diff.
7440///
7441/// @return a map of function parameter changes of the current diff.
7444{return priv_->subtype_changed_parms_;}
7445
7446/// Getter for the map of parameters that got removed.
7447///
7448/// @return the map of parameters that got removed.
7449const string_parm_map&
7451{return priv_->deleted_parms_;}
7452
7453/// Getter for the map of parameters that got added.
7454///
7455/// @return the map of parameters that got added.
7456const string_parm_map&
7458{return priv_->added_parms_;}
7459
7460/// Build and return a copy of a pretty representation of the current
7461/// instance of @ref function_type_diff.
7462///
7463/// @return a copy of the pretty representation of the current
7464/// instance of @ref function_type_diff.
7465const string&
7467{
7468 if (diff::priv_->pretty_representation_.empty())
7469 {
7470 std::ostringstream o;
7471 o << "function_type_diff["
7473 << ", "
7475 << "]";
7476 diff::priv_->pretty_representation_ = o.str();
7477 }
7478 return diff::priv_->pretty_representation_;
7479}
7480
7481/// Test if the current diff node carries changes.
7482///
7483/// @return true iff the current diff node carries changes.
7484bool
7487
7488/// Test if the current diff node carries local changes.
7489///
7490/// A local change is a change that is carried by this diff node, not
7491/// by any of its children nodes.
7492///
7493/// @return the kind of local change carried by the current diff node.
7494/// The value returned is zero if the current node carries no local
7495/// change.
7496enum change_kind
7498{
7499 ir::change_kind k = ir::NO_CHANGE_KIND;
7501 return k & ir::ALL_LOCAL_CHANGES_MASK;
7502 return ir::NO_CHANGE_KIND;
7503}
7504
7505/// Build and emit a textual report about the current @ref
7506/// function_type_diff instance.
7507///
7508/// @param out the output stream.
7509///
7510/// @param indent the indentation string to use.
7511void
7512function_type_diff::report(ostream& out, const string& indent) const
7513{
7514 context()->get_reporter()->report(*this, out, indent);
7515}
7516
7517/// Populate the vector of children node of the @ref diff base type
7518/// sub-object of this instance of @ref function_type_diff.
7519///
7520/// The children node can then later be retrieved using
7521/// diff::children_node().
7522void
7524{
7525 if (diff_sptr d = return_type_diff())
7527
7528 for (vector<fn_parm_diff_sptr>::const_iterator i =
7529 priv_->sorted_subtype_changed_parms_.begin();
7530 i != priv_->sorted_subtype_changed_parms_.end();
7531 ++i)
7532 if (diff_sptr d = *i)
7534
7535 for (vector<fn_parm_diff_sptr>::const_iterator i =
7536 priv_->sorted_changed_parms_by_id_.begin();
7537 i != priv_->sorted_changed_parms_by_id_.end();
7538 ++i)
7539 if (diff_sptr d = *i)
7541}
7542
7543/// Compute the diff between two instances of @ref function_type.
7544///
7545/// Note that the two types must have been created in the same @ref
7546/// environment, otherwise, this function aborts.
7547///
7548/// @param first the first @ref function_type to consider for the diff.
7549///
7550/// @param second the second @ref function_type to consider for the diff.
7551///
7552/// @param ctxt the diff context to use.
7553///
7554/// @return the resulting diff between the two @ref function_type.
7557 const function_type_sptr second,
7558 diff_context_sptr ctxt)
7559{
7560 if (!first || !second)
7561 {
7562 // TODO: implement this for either first or second being NULL.
7563 return function_type_diff_sptr();
7564 }
7565
7566 function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
7567
7568 diff_utils::compute_diff(first->get_first_parm(),
7569 first->get_parameters().end(),
7570 second->get_first_parm(),
7571 second->get_parameters().end(),
7572 result->priv_->parm_changes_);
7573
7574 result->ensure_lookup_tables_populated();
7575
7576 ctxt->initialize_canonical_diff(result);
7577
7578 return result;
7579}
7580// </function_type_diff stuff>
7581
7582// <function_decl_diff stuff>
7583
7584/// Build the lookup tables of the diff, if necessary.
7585void
7586function_decl_diff::ensure_lookup_tables_populated()
7587{
7588}
7589
7590/// Populate the vector of children node of the @ref diff base type
7591/// sub-object of this instance of @ref function_decl_diff.
7592///
7593/// The children node can then later be retrieved using
7594/// diff::children_node().
7595void
7597{
7598 if (diff_sptr d = type_diff())
7600}
7601
7602/// Constructor for function_decl_diff
7603///
7604/// @param first the first function considered by the diff.
7605///
7606/// @param second the second function considered by the diff.
7607///
7608/// @param ctxt the context of the diff. Note that this context
7609/// object must stay alive at least during the life time of the
7610/// current instance of @ref function_decl_diff. Otherwise memory
7611/// corruption issues occur.
7613 const function_decl_sptr second,
7614 diff_context_sptr ctxt)
7615 : decl_diff_base(first, second, ctxt),
7616 priv_(new priv)
7617{
7618}
7619
7620/// @return the first function considered by the diff.
7623{return dynamic_pointer_cast<function_decl>(first_subject());}
7624
7625/// @return the second function considered by the diff.
7628{return dynamic_pointer_cast<function_decl>(second_subject());}
7629
7631function_decl_diff::type_diff() const
7632{return priv_->type_diff_;}
7633
7634/// @return the pretty representation for the current instance of @ref
7635/// function_decl_diff.
7636const string&
7638{
7639 if (diff::priv_->pretty_representation_.empty())
7640 {
7641 std::ostringstream o;
7642 o << "function_diff["
7643 << first_subject()->get_pretty_representation()
7644 << ", "
7645 << second_subject()->get_pretty_representation()
7646 << "]";
7647 diff::priv_->pretty_representation_ = o.str();
7648 }
7649 return diff::priv_->pretty_representation_;
7650}
7651
7652/// Return true iff the current diff node carries a change.
7653///
7654/// @return true iff the current diff node carries a change.
7655bool
7658
7659/// @return the kind of local change carried by the current diff node.
7660/// The value returned is zero if the current node carries no local
7661/// change.
7662enum change_kind
7664{
7665 ir::change_kind k = ir::NO_CHANGE_KIND;
7667 return k & ir::ALL_LOCAL_CHANGES_MASK;
7668 return ir::NO_CHANGE_KIND;
7669}
7670
7671/// Serialize a report of the changes encapsulated in the current
7672/// instance of @ref function_decl_diff over to an output stream.
7673///
7674/// @param out the output stream to serialize the report to.
7675///
7676/// @param indent the string to use an an indentation prefix.
7677void
7678function_decl_diff::report(ostream& out, const string& indent) const
7679{
7680 context()->get_reporter()->report(*this, out, indent);
7681}
7682
7683/// Compute the diff between two function_decl.
7684///
7685/// Note that the two decls must have been created in the same @ref
7686/// environment, otherwise, this function aborts.
7687///
7688/// @param first the first function_decl to consider for the diff
7689///
7690/// @param second the second function_decl to consider for the diff
7691///
7692/// @param ctxt the diff context to use.
7693///
7694/// @return the computed diff
7697 const function_decl_sptr second,
7698 diff_context_sptr ctxt)
7699{
7700 if (!first || !second)
7701 {
7702 // TODO: implement this for either first or second being NULL.
7703 return function_decl_diff_sptr();
7704 }
7705
7706 function_type_diff_sptr type_diff = compute_diff(first->get_type(),
7707 second->get_type(),
7708 ctxt);
7709
7710 function_decl_diff_sptr result(new function_decl_diff(first, second,
7711 ctxt));
7712 result->priv_->type_diff_ = type_diff;
7713
7714 result->ensure_lookup_tables_populated();
7715
7716 ctxt->initialize_canonical_diff(result);
7717
7718 return result;
7719}
7720
7721// </function_decl_diff stuff>
7722
7723// <type_decl_diff stuff>
7724
7725/// Constructor for type_decl_diff.
7726///
7727/// @param first the first subject of the diff.
7728///
7729/// @param second the second subject of the diff.
7730///
7731/// @param ctxt the context of the diff. Note that this context
7732/// object must stay alive at least during the life time of the
7733/// current instance of @ref type_decl_diff. Otherwise memory
7734/// corruption issues occur.
7735type_decl_diff::type_decl_diff(const type_decl_sptr first,
7736 const type_decl_sptr second,
7737 diff_context_sptr ctxt)
7738 : type_diff_base(first, second, ctxt)
7739{}
7740
7741/// Getter for the first subject of the type_decl_diff.
7742///
7743/// @return the first type_decl involved in the diff.
7744const type_decl_sptr
7746{return dynamic_pointer_cast<type_decl>(first_subject());}
7747
7748/// Getter for the second subject of the type_decl_diff.
7749///
7750/// @return the second type_decl involved in the diff.
7751const type_decl_sptr
7753{return dynamic_pointer_cast<type_decl>(second_subject());}
7754
7755/// @return the pretty representation for the current instance of @ref
7756/// type_decl_diff.
7757const string&
7759{
7760 if (diff::priv_->pretty_representation_.empty())
7761 {
7762 std::ostringstream o;
7763 o << "type_decl_diff["
7764 << first_subject()->get_pretty_representation()
7765 << ", "
7766 << second_subject()->get_pretty_representation()
7767 << "]";
7768 diff::priv_->pretty_representation_ = o.str();
7769 }
7770 return diff::priv_->pretty_representation_;
7771}
7772/// Return true iff the current diff node carries a change.
7773///
7774/// @return true iff the current diff node carries a change.
7775bool
7777{return first_type_decl() != second_type_decl();}
7778
7779/// @return the kind of local change carried by the current diff node.
7780/// The value returned is zero if the current node carries no local
7781/// change.
7782enum change_kind
7784{
7785 ir::change_kind k = ir::NO_CHANGE_KIND;
7786 if (!equals(*first_type_decl(), *second_type_decl(), &k))
7787 return k & ir::ALL_LOCAL_CHANGES_MASK;
7788 return ir::NO_CHANGE_KIND;
7789}
7790/// Ouputs a report of the differences between of the two type_decl
7791/// involved in the type_decl_diff.
7792///
7793/// @param out the output stream to emit the report to.
7794///
7795/// @param indent the string to use for indentatino indent.
7796void
7797type_decl_diff::report(ostream& out, const string& indent) const
7798{
7799 context()->get_reporter()->report(*this, out, indent);
7800}
7801
7802/// Compute a diff between two type_decl.
7803///
7804/// Note that the two types must have been created in the same @ref
7805/// environment, otherwise, this function aborts.
7806///
7807/// This function doesn't actually compute a diff. As a type_decl is
7808/// very simple (unlike compound constructs like function_decl or
7809/// class_decl) it's easy to just compare the components of the
7810/// type_decl to know what has changed. Thus this function just
7811/// builds and return a type_decl_diff object. The
7812/// type_decl_diff::report function will just compare the components
7813/// of the the two type_decl and display where and how they differ.
7814///
7815/// @param first a pointer to the first type_decl to
7816/// consider.
7817///
7818/// @param second a pointer to the second type_decl to consider.
7819///
7820/// @param ctxt the diff context to use.
7821///
7822/// @return a pointer to the resulting type_decl_diff.
7825 const type_decl_sptr second,
7826 diff_context_sptr ctxt)
7827{
7828 type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
7829
7830 // We don't need to actually compute a diff here as a type_decl
7831 // doesn't have complicated sub-components. type_decl_diff::report
7832 // just walks the members of the type_decls and display information
7833 // about the ones that have changed. On a similar note,
7834 // type_decl_diff::length returns 0 if the two type_decls are equal,
7835 // and 1 otherwise.
7836
7837 ctxt->initialize_canonical_diff(result);
7838
7839 return result;
7840}
7841
7842// </type_decl_diff stuff>
7843
7844// <typedef_diff stuff>
7845
7846/// Populate the vector of children node of the @ref diff base type
7847/// sub-object of this instance of @ref typedef_diff.
7848///
7849/// The children node can then later be retrieved using
7850/// diff::children_node().
7851void
7854
7855/// Constructor for typedef_diff.
7856///
7857/// @param first the first subject of the diff.
7858///
7859/// @param second the second subject of the diff.
7860///
7861/// @param underlying the underlying diff of the @ref typedef_diff.
7862/// That is the diff between the underlying types of @p first and @p
7863/// second.
7864///
7865/// @param ctxt the context of the diff. Note that this context
7866/// object must stay alive at least during the life time of the
7867/// current instance of @ref typedef_diff. Otherwise memory
7868/// corruption issues occur.
7869typedef_diff::typedef_diff(const typedef_decl_sptr first,
7870 const typedef_decl_sptr second,
7871 const diff_sptr underlying,
7872 diff_context_sptr ctxt)
7873 : type_diff_base(first, second, ctxt),
7874 priv_(new priv(underlying))
7875{}
7876
7877/// Getter for the firt typedef_decl involved in the diff.
7878///
7879/// @return the first subject of the diff.
7882{return dynamic_pointer_cast<typedef_decl>(first_subject());}
7883
7884/// Getter for the second typedef_decl involved in the diff.
7885///
7886/// @return the second subject of the diff.
7889{return dynamic_pointer_cast<typedef_decl>(second_subject());}
7890
7891/// Getter for the diff between the two underlying types of the
7892/// typedefs.
7893///
7894/// @return the diff object reprensenting the difference between the
7895/// two underlying types of the typedefs.
7896const diff_sptr
7898{return priv_->underlying_type_diff_;}
7899
7900/// Setter for the diff between the two underlying types of the
7901/// typedefs.
7902///
7903/// @param d the new diff object reprensenting the difference between
7904/// the two underlying types of the typedefs.
7905void
7907{priv_->underlying_type_diff_ = d;}
7908
7909/// @return the pretty representation for the current instance of @ref
7910/// typedef_diff.
7911const string&
7913{
7914 if (diff::priv_->pretty_representation_.empty())
7915 {
7916 std::ostringstream o;
7917 o << "typedef_diff["
7918 << first_subject()->get_pretty_representation()
7919 << ", "
7920 << second_subject()->get_pretty_representation()
7921 << "]";
7922 diff::priv_->pretty_representation_ = o.str();
7923 }
7924 return diff::priv_->pretty_representation_;
7925}
7926
7927/// Return true iff the current diff node carries a change.
7928///
7929/// @return true iff the current diff node carries a change.
7930bool
7932{
7933 decl_base_sptr second = second_typedef_decl();
7934 return !(*first_typedef_decl() == *second);
7935}
7936
7937/// @return the kind of local change carried by the current diff node.
7938/// The value returned is zero if the current node carries no local
7939/// change.
7940enum change_kind
7942{
7943 ir::change_kind k = ir::NO_CHANGE_KIND;
7945 return k & ir::ALL_LOCAL_CHANGES_MASK;
7946 return ir::NO_CHANGE_KIND;
7947}
7948
7949/// Reports the difference between the two subjects of the diff in a
7950/// serialized form.
7951///
7952/// @param out the output stream to emit the report to.
7953///
7954/// @param indent the indentation string to use.
7955void
7956typedef_diff::report(ostream& out, const string& indent) const
7957{
7958 context()->get_reporter()->report(*this, out, indent);
7959}
7960
7961/// Compute a diff between two typedef_decl.
7962///
7963/// Note that the two types must have been created in the same @ref
7964/// environment, otherwise, this function aborts.
7965///
7966/// @param first a pointer to the first typedef_decl to consider.
7967///
7968/// @param second a pointer to the second typedef_decl to consider.
7969///
7970/// @param ctxt the diff context to use.
7971///
7972/// @return a pointer to the the resulting typedef_diff.
7975 const typedef_decl_sptr second,
7976 diff_context_sptr ctxt)
7977{
7978 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
7979 second->get_underlying_type(),
7980 ctxt);
7981 typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
7982
7983 ctxt->initialize_canonical_diff(result);
7984
7985 return result;
7986}
7987
7988/// Return the leaf underlying diff node of a @ref typedef_diff node.
7989///
7990/// If the underlying diff node of a @ref typedef_diff node is itself
7991/// a @ref typedef_diff node, then recursively look at the underlying
7992/// diff nodes to get the first one that is not a a @ref typedef_diff
7993/// node. This is what a leaf underlying diff node means.
7994///
7995/// Otherwise, if the underlying diff node of @ref typedef_diff is
7996/// *NOT* a @ref typedef_diff node, then just return the underlying
7997/// diff node.
7998///
7999/// And if the diff node considered is not a @ref typedef_diff node,
8000/// then just return it.
8001///
8002/// @return the leaf underlying diff node of a @p diff.
8003const diff*
8005{
8006 const typedef_diff* d = dynamic_cast<const typedef_diff*>(diff);
8007 if (!d)
8008 return diff;
8009
8010 if (const typedef_diff* deef =
8011 dynamic_cast<const typedef_diff*>(d->underlying_type_diff().get()))
8013
8014 return d->underlying_type_diff().get();
8015}
8016
8017// </typedef_diff stuff>
8018
8019// <translation_unit_diff stuff>
8020
8021/// Constructor for translation_unit_diff.
8022///
8023/// @param first the first translation unit to consider for this diff.
8024///
8025/// @param second the second translation unit to consider for this diff.
8026///
8027/// @param ctxt the context of the diff. Note that this context
8028/// object must stay alive at least during the life time of the
8029/// current instance of @ref translation_unit_diff. Otherwise memory
8030/// corruption issues occur.
8032 translation_unit_sptr second,
8033 diff_context_sptr ctxt)
8034 : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
8035 priv_(new priv(first, second))
8036{
8037}
8038
8039/// Getter for the first translation unit of this diff.
8040///
8041/// @return the first translation unit of this diff.
8044{return priv_->first_;}
8045
8046/// Getter for the second translation unit of this diff.
8047///
8048/// @return the second translation unit of this diff.
8051{return priv_->second_;}
8052
8053/// Return true iff the current diff node carries a change.
8054///
8055/// @return true iff the current diff node carries a change.
8056bool
8058{return scope_diff::has_changes();}
8059
8060/// @return the kind of local change carried by the current diff node.
8061/// The value returned is zero if the current node carries no local
8062/// change.
8063enum change_kind
8065{return ir::NO_CHANGE_KIND;}
8066
8067/// Report the diff in a serialized form.
8068///
8069/// @param out the output stream to serialize the report to.
8070///
8071/// @param indent the prefix to use as indentation for the report.
8072void
8073translation_unit_diff::report(ostream& out, const string& indent) const
8074{scope_diff::report(out, indent);}
8075
8076/// Compute the diff between two translation_units.
8077///
8078/// Note that the two translation units must have been created in the
8079/// same @ref environment, otherwise, this function aborts.
8080///
8081/// @param first the first translation_unit to consider.
8082///
8083/// @param second the second translation_unit to consider.
8084///
8085/// @param ctxt the diff context to use. If null, this function will
8086/// create a new context and set to the diff object returned.
8087///
8088/// @return the newly created diff object.
8091 const translation_unit_sptr second,
8092 diff_context_sptr ctxt)
8093{
8094 ABG_ASSERT(first && second);
8095
8096 if (!ctxt)
8097 ctxt.reset(new diff_context);
8098
8099 // TODO: handle first or second having empty contents.
8100 translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
8101 ctxt));
8102 scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
8103
8104 compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
8105 static_pointer_cast<scope_decl>(second->get_global_scope()),
8106 sc_diff,
8107 ctxt);
8108
8109 ctxt->initialize_canonical_diff(tu_diff);
8110
8111 return tu_diff;
8112}
8113
8114// </translation_unit_diff stuff>
8115
8116// <diff_maps stuff>
8117
8118/// The private data of the @ref diff_maps type.
8119struct diff_maps::priv
8120{
8121 string_diff_ptr_map type_decl_diff_map_;
8122 string_diff_ptr_map enum_diff_map_;
8123 string_diff_ptr_map class_diff_map_;
8124 string_diff_ptr_map union_diff_map_;
8125 string_diff_ptr_map typedef_diff_map_;
8126 string_diff_ptr_map subrange_diff_map_;
8127 string_diff_ptr_map array_diff_map_;
8128 string_diff_ptr_map reference_diff_map_;
8129 string_diff_ptr_map function_type_diff_map_;
8130 string_diff_ptr_map function_decl_diff_map_;
8131 string_diff_ptr_map var_decl_diff_map_;
8132 string_diff_ptr_map distinct_diff_map_;
8133 string_diff_ptr_map fn_parm_diff_map_;
8134 diff_artifact_set_map_type impacted_artifacts_map_;
8135}; // end struct diff_maps::priv
8136
8137/// Default constructor of the @ref diff_maps type.
8139 : priv_(new diff_maps::priv())
8140{}
8141
8142diff_maps::~diff_maps() = default;
8143
8144/// Getter of the map that contains basic type diffs.
8145///
8146/// @return the map that contains basic type diffs.
8149{return priv_->type_decl_diff_map_;}
8150
8151/// Getter of the map that contains basic type diffs.
8152///
8153/// @return the map that contains basic type diffs.
8156{return priv_->type_decl_diff_map_;}
8157
8158/// Getter of the map that contains enum type diffs.
8159///
8160/// @return the map that contains enum type diffs.
8163{return priv_->enum_diff_map_;}
8164
8165/// Getter of the map that contains enum type diffs.
8166///
8167/// @return the map that contains enum type diffs.
8170{return priv_->enum_diff_map_;}
8171
8172/// Getter of the map that contains class type diffs.
8173///
8174/// @return the map that contains class type diffs.
8177{return priv_->class_diff_map_;}
8178
8179/// Getter of the map that contains class type diffs.
8180///
8181/// @return the map that contains class type diffs.
8184{return priv_->class_diff_map_;}
8185
8186/// Getter of the map that contains union type diffs.
8187///
8188/// @return the map that contains union type diffs.
8191{return priv_->union_diff_map_;}
8192
8193/// Getter of the map that contains union type diffs.
8194///
8195/// @return the map that contains union type diffs.
8198{return priv_->union_diff_map_;}
8199
8200/// Getter of the map that contains typedef type diffs.
8201///
8202/// @return the map that contains typedef type diffs.
8205{return priv_->typedef_diff_map_;}
8206
8207/// Getter of the map that contains typedef type diffs.
8208///
8209/// @return the map that contains typedef type diffs.
8212{return priv_->typedef_diff_map_;}
8213
8214/// Getter of the map that contains subrange type diffs.
8215///
8216/// @return the map that contains subrange type diffs.
8219{return priv_->subrange_diff_map_;}
8220
8221/// Getter of the map that contains subrange type diffs.
8222///
8223/// @return the map that contains subrange type diffs.
8226{return priv_->subrange_diff_map_;}
8227
8228/// Getter of the map that contains array type diffs.
8229///
8230/// @return the map that contains array type diffs.
8233{return priv_->array_diff_map_;}
8234
8235/// Getter of the map that contains array type diffs.
8236///
8237/// @return the map that contains array type diffs.
8240{return priv_->array_diff_map_;}
8241
8242/// Getter of the map that contains reference type diffs.
8243///
8244/// @return the map that contains reference type diffs.
8247{return priv_->reference_diff_map_;}
8248
8249/// Getter of the map that contains reference type diffs.
8250///
8251/// @return the map that contains reference type diffs.
8254{{return priv_->reference_diff_map_;}}
8255
8256/// Getter of the map that contains function parameter diffs.
8257///
8258/// @return the map that contains function parameter diffs.
8261{return priv_->fn_parm_diff_map_;}
8262
8263/// Getter of the map that contains function parameter diffs.
8264///
8265/// @return the map that contains function parameter diffs.
8268{return priv_->fn_parm_diff_map_;}
8269
8270/// Getter of the map that contains function type diffs.
8271///
8272/// @return the map that contains function type diffs.
8275{return priv_->function_type_diff_map_;}
8276
8277/// Getter of the map that contains function type diffs.
8278///
8279/// @return the map that contains function type diffs.
8282{return priv_->function_type_diff_map_;}
8283
8284/// Getter of the map that contains function decl diffs.
8285///
8286/// @return the map that contains function decl diffs.
8289{return priv_->function_decl_diff_map_;}
8290
8291/// Getter of the map that contains function decl diffs.
8292///
8293/// @return the map that contains function decl diffs.
8296{return priv_->function_decl_diff_map_;}
8297
8298/// Getter of the map that contains var decl diffs.
8299///
8300/// @return the map that contains var decl diffs.
8303{return priv_->var_decl_diff_map_;}
8304
8305/// Getter of the map that contains var decl diffs.
8306///
8307/// @return the map that contains var decl diffs.
8310{return priv_->var_decl_diff_map_;}
8311
8312/// Getter of the map that contains distinct diffs.
8313///
8314/// @return the map that contains distinct diffs.
8317{return priv_->distinct_diff_map_;}
8318
8319/// Getter of the map that contains distinct diffs.
8320///
8321/// @return the map that contains distinct diffs.
8324{return priv_->distinct_diff_map_;}
8325
8326/// Insert a new diff node into the current instance of @ref diff_maps.
8327///
8328/// @param dif the new diff node to insert into the @ref diff_maps.
8329///
8330/// @param impacted_iface the interface (global function or variable)
8331/// currently being analysed that led to analysing the diff node @p
8332/// dif. In other words, this is the interface impacted by the diff
8333/// node @p dif. Note that this can be nil in cases where we are
8334/// directly analysing changes to a type that is not reachable from
8335/// any global function or variable.
8336///
8337/// @return true iff the diff node could be added to the current
8338/// instance of @ref diff_maps.
8339bool
8341 const type_or_decl_base_sptr& impacted_iface)
8342{
8343 string n = get_pretty_representation(dif->first_subject(),
8344 /*internal=*/true);
8345 if (const type_decl_diff *d = is_diff_of_basic_type(dif))
8346 get_type_decl_diff_map()[n] = const_cast<type_decl_diff*>(d);
8347 else if (const enum_diff *d = is_enum_diff(dif))
8348 get_enum_diff_map()[n] = const_cast<enum_diff*>(d);
8349 else if (const class_diff *d = is_class_diff(dif))
8350 get_class_diff_map()[n] = const_cast<class_diff*>(d);
8351 else if (const union_diff *d = is_union_diff(dif))
8352 get_union_diff_map()[n] = const_cast<union_diff*>(d);
8353 else if (const typedef_diff *d = is_typedef_diff(dif))
8354 get_typedef_diff_map()[n] = const_cast<typedef_diff*>(d);
8355 else if (const subrange_diff *d = is_subrange_diff(dif))
8356 get_subrange_diff_map()[n] = const_cast<subrange_diff*>(d);
8357 else if (const array_diff *d = is_array_diff(dif))
8358 get_array_diff_map()[n] = const_cast<array_diff*>(d);
8359 else if (const reference_diff *d = is_reference_diff(dif))
8360 get_reference_diff_map()[n] = const_cast<reference_diff*>(d);
8361 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
8362 get_fn_parm_diff_map()[n] = const_cast<fn_parm_diff*>(d);
8363 else if (const function_type_diff *d = is_function_type_diff(dif))
8364 get_function_type_diff_map()[n] = const_cast<function_type_diff*>(d);
8365 else if (const var_diff *d = is_var_diff(dif))
8366 get_var_decl_diff_map()[n] = const_cast<var_diff*>(d);
8367 else if (const function_decl_diff *d = is_function_decl_diff(dif))
8368 get_function_decl_diff_map()[n] = const_cast<function_decl_diff*>(d);
8369 else if (const distinct_diff *d = is_distinct_diff(dif))
8370 get_distinct_diff_map()[n] = const_cast<distinct_diff*>(d);
8371 else if (is_base_diff(dif))
8372 // we silently drop this case.
8373 return true;
8374 else
8376
8377 // Update the map that associates this diff node to the set of
8378 // interfaces it impacts.
8379
8380 if (impacted_iface)
8381 {
8382 diff_artifact_set_map_type::iterator i =
8383 priv_->impacted_artifacts_map_.find(dif);
8384
8385 if (i == priv_->impacted_artifacts_map_.end())
8386 {
8388 set.insert(impacted_iface);
8389 priv_->impacted_artifacts_map_[dif] = set;
8390 }
8391 else
8392 i->second.insert(impacted_iface);
8393 }
8394
8395 return true;
8396}
8397
8398/// Lookup the interfaces that are impacted by a given leaf diff node.
8399///
8400/// @param d the diff node to consider.
8401///
8402/// @return the set of artifacts impacted by @p d.
8405{
8406 diff_artifact_set_map_type::iterator i =
8407 priv_->impacted_artifacts_map_.find(d);
8408
8409 if (i == priv_->impacted_artifacts_map_.end())
8410 return 0;
8411
8412 return &i->second;
8413}
8414
8415//
8416// </diff_maps stuff>
8417
8418/// Constructor for the @ref diff_stat type.
8419///
8420/// @param ctxt the context of the corpus diff. Note that this
8421/// context object must stay alive at least during the life time of
8422/// the current instance of @ref corpus_diff::diff_stats. Otherwise
8423/// memory corruption issues occur.
8424corpus_diff::diff_stats::diff_stats(diff_context_sptr ctxt)
8425 : priv_(new priv(ctxt))
8426{}
8427
8428/// Getter for the number of functions removed.
8429///
8430/// @return the number of functions removed.
8431size_t
8433{return priv_->num_func_removed;}
8434
8435/// Setter for the number of functions removed.
8436///
8437/// @param n the new number of functions removed.
8438void
8440{priv_->num_func_removed = n;}
8441
8442/// Getter for the number of removed functions that have been filtered
8443/// out.
8444///
8445/// @return the number of removed functions that have been filtered
8446/// out.
8447size_t
8449{
8450 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_fns())
8451 return num_func_removed();
8452 return priv_->num_removed_func_filtered_out;
8453}
8454
8455/// Setter for the number of removed functions that have been filtered
8456/// out.
8457///
8458/// @param t the new value.
8459void
8461{priv_->num_removed_func_filtered_out = t;}
8462
8463/// Getter for the net number of function removed.
8464///
8465/// This is the difference between the number of functions removed and
8466/// the number of functons removed that have been filtered out.
8467///
8468/// @return the net number of function removed.
8469size_t
8471{
8472 ABG_ASSERT(num_func_removed() >= num_removed_func_filtered_out());
8473 return num_func_removed() - num_removed_func_filtered_out();
8474}
8475
8476/// Getter for the number of functions added.
8477///
8478/// @return the number of functions added.
8479size_t
8481{return priv_->num_func_added;}
8482
8483/// Setter for the number of functions added.
8484///
8485/// @param n the new number of functions added.
8486void
8488{priv_->num_func_added = n;}
8489
8490/// Getter for the number of added function that have been filtered out.
8491///
8492/// @return the number of added function that have been filtered out.
8493size_t
8495{
8496 if (priv_->ctxt() && !priv_->ctxt()->show_added_fns())
8497 return num_func_added();
8498 return priv_->num_added_func_filtered_out;
8499}
8500
8501/// Setter for the number of added function that have been filtered
8502/// out.
8503///
8504/// @param n the new value.
8505void
8507{priv_->num_added_func_filtered_out = n;}
8508
8509/// Getter for the net number of added functions.
8510///
8511/// The net number of added functions is the difference between the
8512/// number of added functions and the number of added functions that
8513/// have been filtered out.
8514///
8515/// @return the net number of added functions.
8516size_t
8518{
8519 ABG_ASSERT(num_func_added() >= num_added_func_filtered_out());
8520 return num_func_added() - num_added_func_filtered_out();
8521}
8522
8523/// Getter for the number of functions that have a change in one of
8524/// their sub-types.
8525///
8526/// @return the number of functions that have a change in one of their
8527/// sub-types.
8528size_t
8530{return priv_->num_func_changed;}
8531
8532/// Setter for the number of functions that have a change in one of
8533/// their sub-types.
8534///
8535/// @@param n the new number of functions that have a change in one of
8536/// their sub-types.
8537void
8539{priv_->num_func_changed = n;}
8540
8541/// Getter for the number of functions that have a change in one of
8542/// their sub-types, and that have been filtered out.
8543///
8544/// @return the number of functions that have a change in one of their
8545/// sub-types, and that have been filtered out.
8546size_t
8548{return priv_->num_changed_func_filtered_out;}
8549
8550/// Setter for the number of functions that have a change in one of
8551/// their sub-types, and that have been filtered out.
8552///
8553/// @param n the new number of functions that have a change in one of their
8554/// sub-types, and that have been filtered out.
8555void
8557{priv_->num_changed_func_filtered_out = n;}
8558
8559/// Getter for the number of functions that carry virtual member
8560/// offset changes.
8561///
8562/// @return the number of functions that carry virtual member changes.
8563size_t
8565{return priv_->num_func_with_virt_offset_changes;}
8566
8567/// Setter for the number of functions that carry virtual member
8568/// offset changes.
8569///
8570/// @param n the new number of functions that carry virtual member
8571/// offset. changes.
8572void
8574{priv_->num_func_with_virt_offset_changes = n;}
8575
8576/// Getter for the number of functions that have a change in their
8577/// sub-types, minus the number of these functions that got filtered
8578/// out from the diff.
8579///
8580/// @return for the the number of functions that have a change in
8581/// their sub-types, minus the number of these functions that got
8582/// filtered out from the diff.
8583size_t
8585{return num_func_changed() - num_changed_func_filtered_out();}
8586
8587/// Getter for the number of variables removed.
8588///
8589/// @return the number of variables removed.
8590size_t
8592{return priv_->num_vars_removed;}
8593
8594/// Setter for the number of variables removed.
8595///
8596/// @param n the new number of variables removed.
8597void
8599{priv_->num_vars_removed = n;}
8600
8601/// Getter for the number removed variables that have been filtered
8602/// out.
8603///
8604/// @return the number removed variables that have been filtered out.
8605size_t
8607{
8608 if (priv_->ctxt() && !priv_->ctxt()->show_deleted_vars())
8609 return num_vars_removed();
8610 return priv_->num_removed_vars_filtered_out;
8611}
8612
8613/// Setter for the number of removed variables that have been filtered
8614/// out.
8615///
8616/// @param n the new value.
8617void
8619{priv_->num_removed_vars_filtered_out = n;}
8620
8621/// Getter for the net number of removed variables.
8622///
8623/// The net number of removed variables is the difference between the
8624/// number of removed variables and the number of removed variables
8625/// that have been filtered out.
8626///
8627/// @return the net number of removed variables.
8628size_t
8630{
8631 ABG_ASSERT(num_vars_removed() >= num_removed_vars_filtered_out());
8632 return num_vars_removed() - num_removed_vars_filtered_out();
8633}
8634
8635/// Getter for the number of variables added.
8636///
8637/// @return the number of variables added.
8638size_t
8640{return priv_->num_vars_added;}
8641
8642/// Setter for the number of variables added.
8643///
8644/// @param n the new number of variables added.
8645void
8647{priv_->num_vars_added = n;}
8648
8649/// Getter for the number of added variables that have been filtered
8650/// out.
8651///
8652/// @return the number of added variables that have been filtered out.
8653size_t
8655{
8656 if (priv_->ctxt() && !priv_->ctxt()->show_added_vars())
8657 return num_vars_added();
8658 return priv_->num_added_vars_filtered_out;
8659}
8660
8661/// Setter for the number of added variables that have been filtered
8662/// out.
8663///
8664/// @param n the new value.
8665void
8667{priv_->num_added_vars_filtered_out = n;}
8668
8669/// Getter for the net number of added variables.
8670///
8671/// The net number of added variables is the difference between the
8672/// number of added variables and the number of added variables that
8673/// have been filetered out.
8674///
8675/// @return the net number of added variables.
8676size_t
8678{
8679 ABG_ASSERT(num_vars_added() >= num_added_vars_filtered_out());
8680 return num_vars_added() - num_added_vars_filtered_out();
8681}
8682
8683/// Getter for the number of variables that have a change in one of
8684/// their sub-types.
8685///
8686/// @return the number of variables that have a change in one of their
8687/// sub-types.
8688size_t
8690{return priv_->num_vars_changed;}
8691
8692/// Setter for the number of variables that have a change in one of
8693/// their sub-types.
8694///
8695/// @param n the new number of variables that have a change in one of
8696/// their sub-types.
8697void
8699{priv_->num_vars_changed = n;}
8700
8701/// Getter for the number of variables that have a change in one of
8702/// their sub-types, and that have been filtered out.
8703///
8704/// @return the number of functions that have a change in one of their
8705/// sub-types, and that have been filtered out.
8706size_t
8708{return priv_->num_changed_vars_filtered_out;}
8709
8710/// Setter for the number of variables that have a change in one of
8711/// their sub-types, and that have been filtered out.
8712///
8713/// @param n the new number of variables that have a change in one of their
8714/// sub-types, and that have been filtered out.
8715void
8717{priv_->num_changed_vars_filtered_out = n;}
8718
8719/// Getter for the number of variables that have a change in their
8720/// sub-types, minus the number of these variables that got filtered
8721/// out from the diff.
8722///
8723/// @return for the the number of variables that have a change in
8724/// their sub-types, minus the number of these variables that got
8725/// filtered out from the diff.
8726size_t
8728{return num_vars_changed() - num_changed_vars_filtered_out();}
8729
8730/// Getter for the number of function symbols (not referenced by any
8731/// debug info) that got removed.
8732///
8733/// @return the number of function symbols (not referenced by any
8734/// debug info) that got removed.
8735size_t
8737{return priv_->num_func_syms_removed;}
8738
8739/// Setter for the number of function symbols (not referenced by any
8740/// debug info) that got removed.
8741///
8742/// @param n the number of function symbols (not referenced by any
8743/// debug info) that got removed.
8744void
8746{priv_->num_func_syms_removed = n;}
8747
8748/// Getter for the number of removed function symbols, not referenced
8749/// by debug info, that have been filtered out.
8750///
8751/// @return the number of removed function symbols, not referenced by
8752/// debug info, that have been filtered out.
8753size_t
8755{
8756 if (priv_->ctxt()
8757 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8758 return num_func_syms_removed();
8759 return priv_->num_removed_func_syms_filtered_out;
8760}
8761
8762/// Setter for the number of removed function symbols, not referenced
8763/// by debug info, that have been filtered out.
8764///
8765/// @param n the new the number of removed function symbols, not
8766/// referenced by debug info, that have been filtered out.
8767void
8769{priv_->num_removed_func_syms_filtered_out = n;}
8770
8771/// Getter of the net number of removed function symbols that are not
8772/// referenced by any debug info.
8773///
8774/// This is the difference between the total number of removed
8775/// function symbols and the number of removed function symbols that
8776/// have been filteted out. Both numbers are for symbols not
8777/// referenced by debug info.
8778///
8779/// return the net number of removed function symbols that are not
8780/// referenced by any debug info.
8781size_t
8783{
8784 ABG_ASSERT(num_func_syms_removed() >= num_removed_func_syms_filtered_out());
8785 return num_func_syms_removed() - num_removed_func_syms_filtered_out();
8786}
8787
8788/// Getter for the number of function symbols (not referenced by any
8789/// debug info) that got added.
8790///
8791/// @return the number of function symbols (not referenced by any
8792/// debug info) that got added.
8793size_t
8795{return priv_->num_func_syms_added;}
8796
8797/// Setter for the number of function symbols (not referenced by any
8798/// debug info) that got added.
8799///
8800/// @param n the new number of function symbols (not referenced by any
8801/// debug info) that got added.
8802void
8804{priv_->num_func_syms_added = n;}
8805
8806/// Getter for the number of added function symbols, not referenced by
8807/// any debug info, that have been filtered out.
8808///
8809/// @return the number of added function symbols, not referenced by
8810/// any debug info, that have been filtered out.
8811size_t
8813{
8814 if (priv_->ctxt()
8815 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8816 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8817 return num_func_syms_added();
8818 return priv_->num_added_func_syms_filtered_out;
8819}
8820
8821/// Setter for the number of added function symbols, not referenced by
8822/// any debug info, that have been filtered out.
8823///
8824/// @param n the new number of added function symbols, not referenced
8825/// by any debug info, that have been filtered out.
8826void
8828{priv_->num_added_func_syms_filtered_out = n;}
8829
8830/// Getter of the net number of added function symbols that are not
8831/// referenced by any debug info.
8832///
8833/// This is the difference between the total number of added
8834/// function symbols and the number of added function symbols that
8835/// have been filteted out. Both numbers are for symbols not
8836/// referenced by debug info.
8837///
8838/// return the net number of added function symbols that are not
8839/// referenced by any debug info.
8840size_t
8842{
8843 ABG_ASSERT(num_func_syms_added() >= num_added_func_syms_filtered_out());
8844 return num_func_syms_added()- num_added_func_syms_filtered_out();
8845}
8846
8847/// Getter for the number of variable symbols (not referenced by any
8848/// debug info) that got removed.
8849///
8850/// @return the number of variable symbols (not referenced by any
8851/// debug info) that got removed.
8852size_t
8854{return priv_->num_var_syms_removed;}
8855
8856/// Setter for the number of variable symbols (not referenced by any
8857/// debug info) that got removed.
8858///
8859/// @param n the number of variable symbols (not referenced by any
8860/// debug info) that got removed.
8861void
8863{priv_->num_var_syms_removed = n;}
8864
8865/// Getter for the number of removed variable symbols, not referenced
8866/// by any debug info, that have been filtered out.
8867///
8868/// @return the number of removed variable symbols, not referenced
8869/// by any debug info, that have been filtered out.
8870size_t
8872{
8873 if (priv_->ctxt()
8874 && !priv_->ctxt()->show_symbols_unreferenced_by_debug_info())
8875 return num_var_syms_removed();
8876 return priv_->num_removed_var_syms_filtered_out;
8877}
8878
8879/// Setter for the number of removed variable symbols, not referenced
8880/// by any debug info, that have been filtered out.
8881///
8882/// @param n the number of removed variable symbols, not referenced by
8883/// any debug info, that have been filtered out.
8884void
8886{priv_->num_removed_var_syms_filtered_out = n;}
8887
8888/// Getter of the net number of removed variable symbols that are not
8889/// referenced by any debug info.
8890///
8891/// This is the difference between the total number of removed
8892/// variable symbols and the number of removed variable symbols that
8893/// have been filteted out. Both numbers are for symbols not
8894/// referenced by debug info.
8895///
8896/// return the net number of removed variable symbols that are not
8897/// referenced by any debug info.
8898size_t
8900{
8901 ABG_ASSERT(num_var_syms_removed() >= num_removed_var_syms_filtered_out());
8902 return num_var_syms_removed() - num_removed_var_syms_filtered_out();
8903}
8904
8905/// Getter for the number of variable symbols (not referenced by any
8906/// debug info) that got added.
8907///
8908/// @return the number of variable symbols (not referenced by any
8909/// debug info) that got added.
8910size_t
8912{return priv_->num_var_syms_added;}
8913
8914/// Setter for the number of variable symbols (not referenced by any
8915/// debug info) that got added.
8916///
8917/// @param n the new number of variable symbols (not referenced by any
8918/// debug info) that got added.
8919void
8921{priv_->num_var_syms_added = n;}
8922
8923/// Getter for the number of added variable symbols, not referenced by
8924/// any debug info, that have been filtered out.
8925///
8926/// @return the number of added variable symbols, not referenced by
8927/// any debug info, that have been filtered out.
8928size_t
8930{
8931 if (priv_->ctxt()
8932 && !(priv_->ctxt()->show_added_symbols_unreferenced_by_debug_info()
8933 && priv_->ctxt()->show_symbols_unreferenced_by_debug_info()))
8934 return num_var_syms_added();
8935 return priv_->num_added_var_syms_filtered_out;
8936}
8937
8938/// Setter for the number of added variable symbols, not referenced by
8939/// any debug info, that have been filtered out.
8940///
8941/// @param n the new number of added variable symbols, not referenced
8942/// by any debug info, that have been filtered out.
8943void
8945{priv_->num_added_var_syms_filtered_out = n;}
8946
8947/// Getter of the net number of added variable symbols that are not
8948/// referenced by any debug info.
8949///
8950/// This is the difference between the total number of added
8951/// variable symbols and the number of added variable symbols that
8952/// have been filteted out. Both numbers are for symbols not
8953/// referenced by debug info.
8954///
8955/// return the net number of added variable symbols that are not
8956/// referenced by any debug info.
8957size_t
8959{
8960 ABG_ASSERT(num_var_syms_added() >= num_added_var_syms_filtered_out());
8961 return num_var_syms_added() - num_added_var_syms_filtered_out();
8962}
8963
8964/// Getter of the number of leaf type change diff nodes.
8965///
8966/// @return the number of leaf type change diff nodes.
8967size_t
8969{return priv_->num_leaf_changes;}
8970
8971/// Setter of the number of leaf type change diff nodes.
8972///
8973/// @param n the new number of leaf type change diff nodes.
8974void
8976{priv_->num_leaf_changes = n;}
8977
8978/// Getter of the number of leaf type change diff nodes that have been
8979/// filtered out.
8980///
8981/// @return the number of leaf type change diff nodes that have been
8982size_t
8984{return priv_->num_leaf_changes_filtered_out;}
8985
8986/// Setter of the number of leaf type change diff nodes that have been
8987/// filtered out.
8988///
8989/// @param n the new number of leaf type change diff nodes that have
8990/// been filtered out.
8991void
8993{priv_->num_leaf_changes_filtered_out = n;}
8994
8995/// Getter of the net number of leaf change diff nodes.
8996///
8997/// This is the difference between the total number of leaf change
8998/// diff nodes, and the number of the leaf change diff nodes that have
8999/// been filtered out.
9000///
9001/// A leaf change is either a type change, a function change or a
9002/// variable change.
9003size_t
9005{
9006 ABG_ASSERT(num_leaf_changes() >= num_leaf_changes_filtered_out());
9007 return num_leaf_changes() - num_leaf_changes_filtered_out();
9008}
9009
9010/// Getter for the number of leaf type change diff nodes.
9011///
9012/// @return the number of leaf type changes diff nodes.
9013size_t
9015{return priv_->num_leaf_type_changes;}
9016
9017/// Setter for the number of leaf type change diff nodes.
9018///
9019/// @param n the new number of leaf type change diff nodes.
9020void
9022{priv_->num_leaf_type_changes = n;}
9023
9024/// Getter for the number of filtered out leaf type change diff nodes.
9025///
9026/// @return the number of filtered out leaf type change diff nodes.
9027size_t
9029{return priv_->num_leaf_type_changes_filtered_out;}
9030
9031/// Setter for the number of filtered out leaf type change diff nodes.
9032/// @param n the new number of filtered out leaf type change diff nodes.
9033void
9035{priv_->num_leaf_type_changes_filtered_out = n;}
9036
9037/// Getter for the net number of leaf type change diff nodes.
9038///
9039/// This is the difference between the number of leaf type changes and
9040/// the number of filtered out leaf type changes.
9041///
9042/// @return the net number of leaf type change diff nodes.
9043size_t
9045{return num_leaf_type_changes() - num_leaf_type_changes_filtered_out();}
9046
9047/// Getter for the number of leaf function change diff nodes.
9048///
9049/// @return the number of leaf function change diff nodes.
9050size_t
9052{return priv_->num_leaf_func_changes;}
9053
9054/// Setter for the number of leaf function change diff nodes.
9055///
9056/// @param n the new number of leaf function change diff nodes.
9057void
9059{priv_->num_leaf_func_changes = n;}
9060
9061/// Getter for the number of leaf function change diff nodes that were
9062/// filtered out.
9063///
9064/// @return the number of leaf function change diff nodes that were
9065/// filtered out.
9066size_t
9068{return priv_->num_leaf_func_changes_filtered_out;}
9069
9070/// Setter for the number of leaf function change diff nodes that were
9071/// filtered out.
9072///
9073/// @param n the new number of leaf function change diff nodes that
9074/// were filtered out.
9075void
9077{priv_->num_leaf_func_changes_filtered_out = n;}
9078
9079/// Getter for the net number of leaf function change diff nodes.
9080///
9081/// This is the difference between the number of leaf function change
9082/// diff nodes and the number of filtered out leaf function change
9083/// diff nodes.
9084///
9085/// @return the net number of leaf function change diff nodes.
9086size_t
9088{return num_leaf_func_changes() - num_leaf_func_changes_filtered_out();}
9089
9090/// Getter for the number of leaf variable change diff nodes.
9091///
9092/// @return the number of leaf variable change diff nodes.
9093size_t
9095{return priv_->num_leaf_var_changes;}
9096
9097/// Setter for the number of leaf variable change diff nodes.
9098///
9099/// @param n the number of leaf variable change diff nodes.
9100void
9102{priv_->num_leaf_var_changes = n;}
9103
9104/// Getter of the number of added types that are unreachable from the
9105/// public interface of the ABI corpus.
9106///
9107/// Public interface means the set of defined and publicly exported
9108/// functions and variables of the ABI corpus.
9109///
9110/// @return the number of added types that are unreachable from the
9111/// public interface of the ABI corpus.
9112size_t
9114{return priv_->num_added_unreachable_types;}
9115
9116/// Setter of the number of added types that are unreachable from the
9117/// public interface (global functions or variables) of the ABI
9118/// corpus.
9119///
9120/// Public interface means the set of defined and publicly exported
9121/// functions and variables of the ABI corpus.
9122///
9123/// @param n the new number of added types that are unreachable from
9124/// the public interface of the ABI corpus.
9125void
9127{priv_->num_added_unreachable_types = n;}
9128
9129/// Getter of the number of added types that are unreachable from
9130/// public interfaces and that are filtered out by suppression
9131/// specifications.
9132///
9133/// @return the number of added types that are unreachable from public
9134/// interfaces and that are filtered out by suppression
9135/// specifications.
9136size_t
9138{return priv_->num_added_unreachable_types_filtered_out;}
9139
9140/// Setter of the number of added types that are unreachable from
9141/// public interfaces and that are filtered out by suppression
9142/// specifications.
9143///
9144/// @param n the new number of added types that are unreachable from
9145/// public interfaces and that are filtered out by suppression
9146/// specifications.
9147void
9149{priv_->num_added_unreachable_types_filtered_out = n;}
9150
9151/// Getter of the number of added types that are unreachable from
9152/// public interfaces and that are *NOT* filtered out by suppression
9153/// specifications.
9154///
9155/// @return the number of added types that are unreachable from public
9156/// interfaces and that are *NOT* filtered out by suppression
9157/// specifications.
9158size_t
9160{
9161 ABG_ASSERT(num_added_unreachable_types()
9162 >=
9163 num_added_unreachable_types_filtered_out());
9164
9165 return (num_added_unreachable_types()
9166 -
9167 num_added_unreachable_types_filtered_out());
9168}
9169
9170/// Getter of the number of removed types that are unreachable from
9171/// the public interface of the ABI corpus.
9172///
9173/// Public interface means the set of defined and publicly exported
9174/// functions and variables of the ABI corpus.
9175///
9176/// @return the number of removed types that are unreachable from
9177/// the public interface of the ABI corpus.
9178size_t
9180{return priv_->num_removed_unreachable_types;}
9181
9182/// Setter of the number of removed types that are unreachable from
9183/// the public interface of the ABI corpus.
9184///
9185/// Public interface means the set of defined and publicly exported
9186/// functions and variables of the ABI corpus.
9187///
9188///@param n the new number of removed types that are unreachable from
9189/// the public interface of the ABI corpus.
9190void
9192{priv_->num_removed_unreachable_types = n;}
9193
9194/// Getter of the number of removed types that are not reachable from
9195/// public interfaces and that have been filtered out by suppression
9196/// specifications.
9197///
9198/// @return the number of removed types that are not reachable from
9199/// public interfaces and that have been filtered out by suppression
9200/// specifications.
9201size_t
9203{return priv_->num_removed_unreachable_types_filtered_out;}
9204
9205/// Setter of the number of removed types that are not reachable from
9206/// public interfaces and that have been filtered out by suppression
9207/// specifications.
9208///
9209/// @param n the new number of removed types that are not reachable
9210/// from public interfaces and that have been filtered out by
9211/// suppression specifications.
9212void
9214{priv_->num_removed_unreachable_types_filtered_out = n;}
9215
9216/// Getter of the number of removed types that are not reachable from
9217/// public interfaces and that have *NOT* been filtered out by
9218/// suppression specifications.
9219///
9220/// @return the number of removed types that are not reachable from
9221/// public interfaces and that have *NOT* been filtered out by
9222/// suppression specifications.
9223size_t
9225{
9226 ABG_ASSERT(num_removed_unreachable_types()
9227 >=
9228 num_removed_unreachable_types_filtered_out());
9229
9230 return (num_removed_unreachable_types()
9231 -
9232 num_removed_unreachable_types_filtered_out());
9233}
9234
9235/// Getter of the number of changed types that are unreachable from
9236/// the public interface of the ABI corpus.
9237///
9238/// Public interface means the set of defined and publicly exported
9239/// functions and variables of the ABI corpus.
9240///
9241/// @return the number of changed types that are unreachable from the
9242/// public interface of the ABI corpus.
9243size_t
9245{return priv_->num_changed_unreachable_types;}
9246
9247/// Setter of the number of changed types that are unreachable from
9248/// the public interface of the ABI corpus.
9249///
9250/// Public interface means the set of defined and publicly exported
9251/// functions and variables of the ABI corpus.
9252///
9253///@param n the new number of changed types that are unreachable from
9254/// the public interface of the ABI corpus.
9255void
9257{priv_->num_changed_unreachable_types = n;}
9258
9259/// Getter of the number of changed types that are unreachable from
9260/// public interfaces and that have been filtered out by suppression
9261/// specifications.
9262///
9263/// @return the number of changed types that are unreachable from
9264/// public interfaces and that have been filtered out by suppression
9265/// specifications.
9266size_t
9268{return priv_->num_changed_unreachable_types_filtered_out;}
9269
9270/// Setter of the number of changed types that are unreachable from
9271/// public interfaces and that have been filtered out by suppression
9272/// specifications.
9273///
9274/// @param n the new number of changed types that are unreachable from
9275/// public interfaces and that have been filtered out by suppression
9276/// specifications.
9277void
9279{priv_->num_changed_unreachable_types_filtered_out = n;}
9280
9281/// Getter of the number of changed types that are unreachable from
9282/// public interfaces and that have *NOT* been filtered out by
9283/// suppression specifications.
9284///
9285/// @return the number of changed types that are unreachable from
9286/// public interfaces and that have *NOT* been filtered out by
9287/// suppression specifications.
9288size_t
9290{
9291 ABG_ASSERT(num_changed_unreachable_types()
9292 >=
9293 num_changed_unreachable_types_filtered_out());
9294
9295 return (num_changed_unreachable_types()
9296 -
9297 num_changed_unreachable_types_filtered_out());
9298}
9299
9300/// Getter for the number of leaf variable changes diff nodes that
9301/// have been filtered out.
9302///
9303/// @return the number of leaf variable changes diff nodes that have
9304/// been filtered out.
9305size_t
9307{return priv_->num_leaf_var_changes_filtered_out;}
9308
9309/// Setter for the number of leaf variable changes diff nodes that
9310/// have been filtered out.
9311///
9312/// @param n the number of leaf variable changes diff nodes that have
9313/// been filtered out.
9314void
9316{priv_->num_leaf_var_changes_filtered_out = n;}
9317
9318/// Getter for the net number of leaf variable change diff nodes.
9319///
9320/// This the difference between the number of leaf variable change
9321/// diff nodes and the number of filtered out leaf variable change
9322/// diff nodes.
9323///
9324/// @return the net number of leaf variable change diff nodes.
9325size_t
9327{return num_leaf_var_changes() - num_leaf_var_changes_filtered_out();}
9328
9329
9330// <corpus_diff stuff>
9331
9332/// Getter of the context associated with this corpus.
9333///
9334/// @return a smart pointer to the context associate with the corpus.
9337{return ctxt_.lock();}
9338
9339/// Tests if the lookup tables are empty.
9340///
9341/// @return true if the lookup tables are empty, false otherwise.
9342bool
9344{
9345 return (deleted_fns_.empty()
9346 && added_fns_.empty()
9347 && changed_fns_map_.empty()
9348 && deleted_vars_.empty()
9349 && added_vars_.empty()
9350 && changed_vars_map_.empty());
9351}
9352
9353/// Clear the lookup tables useful for reporting an enum_diff.
9354void
9356{
9357 deleted_fns_.clear();
9358 added_fns_.clear();
9359 changed_fns_map_.clear();
9360 deleted_vars_.clear();
9361 added_vars_.clear();
9362 changed_vars_map_.clear();
9363}
9364
9365/// If the lookup tables are not yet built, walk the differences and
9366/// fill the lookup tables.
9367void
9369{
9370 if (!lookup_tables_empty())
9371 return;
9372
9373 diff_context_sptr ctxt = get_context();
9374
9375 {
9376 edit_script& e = fns_edit_script_;
9377
9378 for (vector<deletion>::const_iterator it = e.deletions().begin();
9379 it != e.deletions().end();
9380 ++it)
9381 {
9382 unsigned i = it->index();
9383 ABG_ASSERT(i < first_->get_functions().size());
9384
9385 const function_decl* deleted_fn = first_->get_functions()[i];
9386 string n = get_function_id_or_pretty_representation(deleted_fn);
9387 ABG_ASSERT(!n.empty());
9388 // The below is commented out because there can be several
9389 // functions with the same ID in the corpus. So several
9390 // functions with the same ID can be deleted.
9391 // ABG_ASSERT(deleted_fns_.find(n) == deleted_fns_.end());
9392 deleted_fns_[n] = deleted_fn;
9393 }
9394
9395 for (vector<insertion>::const_iterator it = e.insertions().begin();
9396 it != e.insertions().end();
9397 ++it)
9398 {
9399 for (vector<unsigned>::const_iterator iit =
9400 it->inserted_indexes().begin();
9401 iit != it->inserted_indexes().end();
9402 ++iit)
9403 {
9404 unsigned i = *iit;
9405 const function_decl* added_fn = second_->get_functions()[i];
9406 string n = get_function_id_or_pretty_representation(added_fn);
9407 ABG_ASSERT(!n.empty());
9408 // The below is commented out because there can be several
9409 // functions with the same ID in the corpus. So several
9410 // functions with the same ID can be added.
9411 // ABG_ASSERT(added_fns_.find(n) == added_fns_.end());
9412 string_function_ptr_map::const_iterator j =
9413 deleted_fns_.find(n);
9414 if (j != deleted_fns_.end())
9415 {
9416 function_decl_sptr f(const_cast<function_decl*>(j->second),
9417 noop_deleter());
9418 function_decl_sptr s(const_cast<function_decl*>(added_fn),
9419 noop_deleter());
9420 function_decl_diff_sptr d = compute_diff(f, s, ctxt);
9421 if (*j->second != *added_fn)
9422 changed_fns_map_[j->first] = d;
9423 deleted_fns_.erase(j);
9424 }
9425 else
9426 added_fns_[n] = added_fn;
9427 }
9428 }
9429 sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
9430
9431 // Now walk the allegedly deleted functions; check if their
9432 // underlying symbols are deleted as well; otherwise, consider
9433 // that the function in question hasn't been deleted.
9434
9435 vector<string> to_delete;
9436 for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
9437 i != deleted_fns_.end();
9438 ++i)
9439 if (second_->lookup_function_symbol(*i->second->get_symbol()))
9440 to_delete.push_back(i->first);
9441
9442 for (vector<string>::const_iterator i = to_delete.begin();
9443 i != to_delete.end();
9444 ++i)
9445 deleted_fns_.erase(*i);
9446
9447 // Do something similar for added functions.
9448
9449 to_delete.clear();
9450 for (string_function_ptr_map::const_iterator i = added_fns_.begin();
9451 i != added_fns_.end();
9452 ++i)
9453 {
9454 if (first_->lookup_function_symbol(*i->second->get_symbol()))
9455 to_delete.push_back(i->first);
9456 else if (! i->second->get_symbol()->get_version().is_empty()
9457 && i->second->get_symbol()->get_version().is_default())
9458 // We are looking for a symbol that has a default version,
9459 // and which seems to be newly added. Let's see if the same
9460 // symbol with *no* version was already present in the
9461 // former corpus. If yes, then the symbol shouldn't be
9462 // considered as 'added'.
9463 {
9464 elf_symbol::version empty_version;
9465 if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
9466 empty_version))
9467 to_delete.push_back(i->first);
9468 }
9469 }
9470
9471 for (vector<string>::const_iterator i = to_delete.begin();
9472 i != to_delete.end();
9473 ++i)
9474 added_fns_.erase(*i);
9475 }
9476
9477 {
9478 edit_script& e = vars_edit_script_;
9479
9480 for (vector<deletion>::const_iterator it = e.deletions().begin();
9481 it != e.deletions().end();
9482 ++it)
9483 {
9484 unsigned i = it->index();
9485 ABG_ASSERT(i < first_->get_variables().size());
9486
9487 const var_decl* deleted_var = first_->get_variables()[i];
9488 string n = deleted_var->get_id();
9489 ABG_ASSERT(!n.empty());
9490 ABG_ASSERT(deleted_vars_.find(n) == deleted_vars_.end());
9491 deleted_vars_[n] = deleted_var;
9492 }
9493
9494 for (vector<insertion>::const_iterator it = e.insertions().begin();
9495 it != e.insertions().end();
9496 ++it)
9497 {
9498 for (vector<unsigned>::const_iterator iit =
9499 it->inserted_indexes().begin();
9500 iit != it->inserted_indexes().end();
9501 ++iit)
9502 {
9503 unsigned i = *iit;
9504 const var_decl* added_var = second_->get_variables()[i];
9505 string n = added_var->get_id();
9506 ABG_ASSERT(!n.empty());
9507 {
9508 string_var_ptr_map::const_iterator k = added_vars_.find(n);
9509 if ( k != added_vars_.end())
9510 {
9511 ABG_ASSERT(is_member_decl(k->second)
9512 && get_member_is_static(k->second));
9513 continue;
9514 }
9515 }
9516 string_var_ptr_map::const_iterator j =
9517 deleted_vars_.find(n);
9518 if (j != deleted_vars_.end())
9519 {
9520 if (*j->second != *added_var)
9521 {
9522 var_decl_sptr f(const_cast<var_decl*>(j->second),
9523 noop_deleter());
9524 var_decl_sptr s(const_cast<var_decl*>(added_var),
9525 noop_deleter());
9526 changed_vars_map_[n] = compute_diff(f, s, ctxt);
9527 }
9528 deleted_vars_.erase(j);
9529 }
9530 else
9531 added_vars_[n] = added_var;
9532 }
9533 }
9534 sort_string_var_diff_sptr_map(changed_vars_map_,
9535 sorted_changed_vars_);
9536
9537 // Now walk the allegedly deleted variables; check if their
9538 // underlying symbols are deleted as well; otherwise consider
9539 // that the variable in question hasn't been deleted.
9540
9541 vector<string> to_delete;
9542 for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
9543 i != deleted_vars_.end();
9544 ++i)
9545 if (second_->lookup_variable_symbol(*i->second->get_symbol()))
9546 to_delete.push_back(i->first);
9547
9548 for (vector<string>::const_iterator i = to_delete.begin();
9549 i != to_delete.end();
9550 ++i)
9551 deleted_vars_.erase(*i);
9552
9553 // Do something similar for added variables.
9554
9555 to_delete.clear();
9556 for (string_var_ptr_map::const_iterator i = added_vars_.begin();
9557 i != added_vars_.end();
9558 ++i)
9559 if (first_->lookup_variable_symbol(*i->second->get_symbol()))
9560 to_delete.push_back(i->first);
9561 else if (! i->second->get_symbol()->get_version().is_empty()
9562 && i->second->get_symbol()->get_version().is_default())
9563 // We are looking for a symbol that has a default version,
9564 // and which seems to be newly added. Let's see if the same
9565 // symbol with *no* version was already present in the
9566 // former corpus. If yes, then the symbol shouldn't be
9567 // considered as 'added'.
9568 {
9569 elf_symbol::version empty_version;
9570 if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
9571 empty_version))
9572 to_delete.push_back(i->first);
9573 }
9574
9575 for (vector<string>::const_iterator i = to_delete.begin();
9576 i != to_delete.end();
9577 ++i)
9578 added_vars_.erase(*i);
9579 }
9580
9581 // Massage the edit script for added/removed function symbols that
9582 // were not referenced by any debug info and turn them into maps of
9583 // {symbol_name, symbol}.
9584 {
9585 edit_script& e = unrefed_fn_syms_edit_script_;
9586 for (vector<deletion>::const_iterator it = e.deletions().begin();
9587 it != e.deletions().end();
9588 ++it)
9589 {
9590 unsigned i = it->index();
9591 ABG_ASSERT(i < first_->get_unreferenced_function_symbols().size());
9592 elf_symbol_sptr deleted_sym =
9593 first_->get_unreferenced_function_symbols()[i];
9594 if (!second_->lookup_function_symbol(*deleted_sym))
9595 deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
9596 }
9597
9598 for (vector<insertion>::const_iterator it = e.insertions().begin();
9599 it != e.insertions().end();
9600 ++it)
9601 {
9602 for (vector<unsigned>::const_iterator iit =
9603 it->inserted_indexes().begin();
9604 iit != it->inserted_indexes().end();
9605 ++iit)
9606 {
9607 unsigned i = *iit;
9608 ABG_ASSERT(i < second_->get_unreferenced_function_symbols().size());
9609 elf_symbol_sptr added_sym =
9610 second_->get_unreferenced_function_symbols()[i];
9611 if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
9612 == deleted_unrefed_fn_syms_.end()))
9613 {
9614 if (!first_->lookup_function_symbol(*added_sym))
9615 {
9616 bool do_add = true;
9617 if (! added_sym->get_version().is_empty()
9618 && added_sym->get_version().is_default())
9619 {
9620 // So added_seem has a default version. If
9621 // the former corpus had a symbol with the
9622 // same name as added_sym but with *no*
9623 // version, then added_sym shouldn't be
9624 // considered as a newly added symbol.
9625 elf_symbol::version empty_version;
9626 if (first_->lookup_function_symbol(added_sym->get_name(),
9627 empty_version))
9628 do_add = false;
9629 }
9630
9631 if (do_add)
9632 added_unrefed_fn_syms_[added_sym->get_id_string()] =
9633 added_sym;
9634 }
9635 }
9636 else
9637 deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
9638 }
9639 }
9640 }
9641
9642 // Massage the edit script for added/removed variable symbols that
9643 // were not referenced by any debug info and turn them into maps of
9644 // {symbol_name, symbol}.
9645 {
9646 edit_script& e = unrefed_var_syms_edit_script_;
9647 for (vector<deletion>::const_iterator it = e.deletions().begin();
9648 it != e.deletions().end();
9649 ++it)
9650 {
9651 unsigned i = it->index();
9652 ABG_ASSERT(i < first_->get_unreferenced_variable_symbols().size());
9653 elf_symbol_sptr deleted_sym =
9654 first_->get_unreferenced_variable_symbols()[i];
9655 if (!second_->lookup_variable_symbol(*deleted_sym))
9656 deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
9657 }
9658
9659 for (vector<insertion>::const_iterator it = e.insertions().begin();
9660 it != e.insertions().end();
9661 ++it)
9662 {
9663 for (vector<unsigned>::const_iterator iit =
9664 it->inserted_indexes().begin();
9665 iit != it->inserted_indexes().end();
9666 ++iit)
9667 {
9668 unsigned i = *iit;
9669 ABG_ASSERT(i < second_->get_unreferenced_variable_symbols().size());
9670 elf_symbol_sptr added_sym =
9671 second_->get_unreferenced_variable_symbols()[i];
9672 if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
9673 == deleted_unrefed_var_syms_.end())
9674 {
9675 if (!first_->lookup_variable_symbol(*added_sym))
9676 {
9677 bool do_add = true;
9678 if (! added_sym->get_version().is_empty()
9679 && added_sym->get_version().is_default())
9680 {
9681 // So added_seem has a default version. If
9682 // the former corpus had a symbol with the
9683 // same name as added_sym but with *no*
9684 // version, then added_sym shouldn't be
9685 // considered as a newly added symbol.
9686 elf_symbol::version empty_version;
9687 if (first_->lookup_variable_symbol(added_sym->get_name(),
9688 empty_version))
9689 do_add = false;
9690 }
9691
9692 if (do_add)
9693 added_unrefed_var_syms_[added_sym->get_id_string()] =
9694 added_sym;
9695 }
9696 }
9697 else
9698 deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
9699 }
9700 }
9701 }
9702
9703 // Handle the unreachable_types_edit_script_
9704 {
9705 edit_script& e = unreachable_types_edit_script_;
9706
9707 // Populate the map of deleted unreachable types from the
9708 // deletions of the edit script.
9709 for (vector<deletion>::const_iterator it = e.deletions().begin();
9710 it != e.deletions().end();
9711 ++it)
9712 {
9713 unsigned i = it->index();
9714 type_base_sptr t
9715 (first_->get_types_not_reachable_from_public_interfaces()[i]);
9716
9717 if (!is_user_defined_type(t))
9718 continue;
9719
9720 string repr =
9721 abigail::ir::get_pretty_representation(t, /*internal=*/false);
9722 deleted_unreachable_types_[repr] = t;
9723 }
9724
9725 // Populate the map of added and change unreachable types from the
9726 // insertions of the edit script.
9727 for (vector<insertion>::const_iterator it = e.insertions().begin();
9728 it != e.insertions().end();
9729 ++it)
9730 {
9731 for (vector<unsigned>::const_iterator iit =
9732 it->inserted_indexes().begin();
9733 iit != it->inserted_indexes().end();
9734 ++iit)
9735 {
9736 unsigned i = *iit;
9737 type_base_sptr t
9738 (second_->get_types_not_reachable_from_public_interfaces()[i]);
9739
9740 if (!is_user_defined_type(t))
9741 continue;
9742
9743 string repr =
9744 abigail::ir::get_pretty_representation(t, /*internal=*/false);
9745
9746 // Let's see if the inserted type we are looking at was
9747 // reported as deleted as well.
9748 //
9749 // If it's been deleted and a different version of it has
9750 // now been added, it means it's been *changed*. In that
9751 // case we'll compute the diff of that change and store it
9752 // in the map of changed unreachable types.
9753 //
9754 // Otherwise, it means the type's been added so we'll add
9755 // it to the set of added unreachable types.
9756
9757 string_type_base_sptr_map::const_iterator j =
9758 deleted_unreachable_types_.find(repr);
9759 if (j != deleted_unreachable_types_.end())
9760 {
9761 // So there was another type of the same pretty
9762 // representation which was reported as deleted.
9763 // Let's see if they are different or not ...
9764 decl_base_sptr old_type = is_decl(j->second);
9765 decl_base_sptr new_type = is_decl(t);
9766 if (old_type != new_type)
9767 {
9768 // The previously added type is different from this
9769 // one that is added. That means the initial type
9770 // was changed. Let's compute its diff and store it
9771 // as a changed type.
9772 diff_sptr d = compute_diff(old_type, new_type, ctxt);
9773 ABG_ASSERT(d->has_changes());
9774 changed_unreachable_types_[repr]= d;
9775 }
9776
9777 // In any case, the type was both deleted and added,
9778 // so we cannot have it marked as being deleted. So
9779 // let's remove it from the deleted types.
9780 deleted_unreachable_types_.erase(j);
9781 }
9782 else
9783 // The type wasn't previously reported as deleted, so
9784 // it's really added.
9785 added_unreachable_types_[repr] = t;
9786 }
9787 }
9788
9789 // Handle anonymous enums that got changed. An anonymous enum is
9790 // designated by its flat textual representation. So a change to
9791 // any of its enumerators results in a different enum. That is
9792 // represented by a deletion of the previous anonymous enum, and
9793 // the addition of a new one. For the user however, it's the same
9794 // enum that changed. Let's massage this "added/removed" pattern
9795 // to show what the user expects, namely, a changed anonymous
9796 // enum.
9797 {
9798 std::set<type_base_sptr> deleted_anon_types;
9799 std::set<type_base_sptr> added_anon_types;
9800
9801 for (auto entry : deleted_unreachable_types_)
9802 {
9803 if ((is_enum_type(entry.second)
9804 && is_enum_type(entry.second)->get_is_anonymous())
9805 || (is_class_or_union_type(entry.second)
9806 && is_class_or_union_type(entry.second)->get_is_anonymous()))
9807 deleted_anon_types.insert(entry.second);
9808 }
9809
9810
9811 for (auto entry : added_unreachable_types_)
9812 if ((is_enum_type(entry.second)
9813 && is_enum_type(entry.second)->get_is_anonymous())
9814 || (is_class_or_union_type(entry.second)
9815 && is_class_or_union_type(entry.second)->get_is_anonymous()))
9816 added_anon_types.insert(entry.second);
9817
9818 string_type_base_sptr_map added_anon_types_to_erase;
9819 string_type_base_sptr_map removed_anon_types_to_erase;
9820 enum_type_decl_sptr deleted_enum;
9821 class_or_union_sptr deleted_class;
9822
9823 // Look for deleted anonymous types (enums, unions, structs &
9824 // classes) which have enumerators or data members present in an
9825 // added anonymous type ...
9826 for (auto deleted: deleted_anon_types)
9827 {
9828 deleted_enum = is_enum_type(deleted);
9829 deleted_class = is_class_or_union_type(deleted);
9830
9831 // For enums, look for any enumerator of 'deleted_enum' that
9832 // is also present in an added anonymous enum.
9833 if (deleted_enum)
9834 {
9835 for (auto enr : deleted_enum->get_enumerators())
9836 {
9837 bool this_enum_got_changed = false;
9838 for (auto t : added_anon_types)
9839 {
9840 if (enum_type_decl_sptr added_enum = is_enum_type(t))
9841 if (is_enumerator_present_in_enum(enr, *added_enum))
9842 {
9843 // So the enumerator 'enr' from the
9844 // 'deleted_enum' enum is also present in the
9845 // 'added_enum' enum so we assume that
9846 // 'deleted_enum' and 'added_enum' are the same
9847 // enum that got changed. Let's represent it
9848 // using a diff node.
9849 diff_sptr d = compute_diff(deleted_enum,
9850 added_enum, ctxt);
9851 ABG_ASSERT(d->has_changes());
9852 string repr =
9854 /*internal=*/false);
9855 changed_unreachable_types_[repr]= d;
9856 this_enum_got_changed = true;
9857 string r1 =
9859 /*internal=*/false);
9860 string r2 =
9862 /*internal=*/false);
9863 removed_anon_types_to_erase[r1] = deleted_enum;
9864 added_anon_types_to_erase[r2] = added_enum;
9865 break;
9866 }
9867 }
9868 if (this_enum_got_changed)
9869 break;
9870 }
9871 }
9872 else if (deleted_class)
9873 {
9874 // For unions, structs & classes, look for any data
9875 // member of 'deleted_class' that is also present in an
9876 // added anonymous class.
9877 for (auto dm : deleted_class->get_data_members())
9878 {
9879 bool this_class_got_changed = false;
9880 for (auto klass : added_anon_types)
9881 {
9882 if (class_or_union_sptr added_class =
9884 if (class_or_union_types_of_same_kind(deleted_class,
9885 added_class)
9886 && lookup_data_member(added_class, dm))
9887 {
9888 // So the data member 'dm' from the
9889 // 'deleted_class' class is also present in
9890 // the 'added_class' class so we assume that
9891 // 'deleted_class' and 'added_class' are the
9892 // same anonymous class that got changed.
9893 // Let's represent it using a diff node.
9894 diff_sptr d = compute_diff(is_type(deleted_class),
9895 is_type(added_class),
9896 ctxt);
9897 ABG_ASSERT(d->has_changes());
9898 string repr =
9900 /*internal=*/false);
9901 changed_unreachable_types_[repr]= d;
9902 this_class_got_changed = true;
9903 string r1 =
9905 /*internal=*/false);
9906 string r2 =
9908 /*internal=*/false);
9909 removed_anon_types_to_erase[r1] = deleted_class;
9910 added_anon_types_to_erase[r2] = added_class;
9911 break;
9912 }
9913 }
9914 if (this_class_got_changed)
9915 break;
9916 }
9917 }
9918 }
9919
9920 // Now remove the added/removed anonymous types from their maps,
9921 // as they are now represented as a changed type, not an added
9922 // and removed anonymous type.
9923 for (auto entry : added_anon_types_to_erase)
9924 added_unreachable_types_.erase(entry.first);
9925
9926 for (auto entry : removed_anon_types_to_erase)
9927 deleted_unreachable_types_.erase(entry.first);
9928 }
9929 }
9930}
9931
9932/// Test if a change reports about a given @ref function_decl that is
9933/// changed in a certain way is suppressed by a given suppression
9934/// specifiation
9935///
9936/// @param fn the @ref function_decl to consider.
9937///
9938/// @param suppr the suppression specification to consider.
9939///
9940/// @param k the kind of change that happened to @p fn.
9941///
9942/// @param ctxt the context of the current diff.
9943///
9944/// @return true iff the suppression specification @p suppr suppresses
9945/// change reports about function @p fn, if that function changes in
9946/// the way expressed by @p k.
9947static bool
9948function_is_suppressed(const function_decl* fn,
9949 const suppression_sptr suppr,
9951 const diff_context_sptr ctxt)
9952{
9954 if (!fn_suppr)
9955 return false;
9956 return fn_suppr->suppresses_function(fn, k, ctxt);
9957}
9958
9959/// Test if a change reports about a given @ref var_decl that is
9960/// changed in a certain way is suppressed by a given suppression
9961/// specifiation
9962///
9963/// @param fn the @ref var_decl to consider.
9964///
9965/// @param suppr the suppression specification to consider.
9966///
9967/// @param k the kind of change that happened to @p fn.
9968///
9969/// @param ctxt the context of the current diff.
9970///
9971/// @return true iff the suppression specification @p suppr suppresses
9972/// change reports about variable @p fn, if that variable changes in
9973/// the way expressed by @p k.
9974static bool
9975variable_is_suppressed(const var_decl* var,
9976 const suppression_sptr suppr,
9978 const diff_context_sptr ctxt)
9979{
9981 if (!var_suppr)
9982 return false;
9983 return var_suppr->suppresses_variable(var, k, ctxt);
9984}
9985
9986/// Apply suppression specifications for this corpus diff to the set
9987/// of added/removed functions/variables, as well as to types not
9988/// reachable from global functions/variables.
9989void
9991{
9992 diff_context_sptr ctxt = get_context();
9993
9994 const suppressions_type& suppressions = ctxt->suppressions();
9995 for (suppressions_type::const_iterator i = suppressions.begin();
9996 i != suppressions.end();
9997 ++i)
9998 {
9999 // Added/Deleted functions.
10001 {
10002 // Added functions
10003 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10004 e != added_fns_.end();
10005 ++e)
10006 if (function_is_suppressed(e->second, fn_suppr,
10008 ctxt))
10009 suppressed_added_fns_[e->first] = e->second;
10010
10011 // Deleted functions.
10012 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10013 e != deleted_fns_.end();
10014 ++e)
10015 if (function_is_suppressed(e->second, fn_suppr,
10017 ctxt))
10018 suppressed_deleted_fns_[e->first] = e->second;
10019
10020 // Added function symbols not referenced by any debug info
10021 for (string_elf_symbol_map::const_iterator e =
10022 added_unrefed_fn_syms_.begin();
10023 e != added_unrefed_fn_syms_.end();
10024 ++e)
10025 if (fn_suppr->suppresses_function_symbol(e->second,
10027 ctxt))
10028 suppressed_added_unrefed_fn_syms_[e->first] = e->second;
10029
10030 // Removed function symbols not referenced by any debug info
10031 for (string_elf_symbol_map::const_iterator e =
10032 deleted_unrefed_fn_syms_.begin();
10033 e != deleted_unrefed_fn_syms_.end();
10034 ++e)
10035 if (fn_suppr->suppresses_function_symbol(e->second,
10037 ctxt))
10038 suppressed_deleted_unrefed_fn_syms_[e->first] = e->second;
10039 }
10040 // Added/Delete virtual member functions changes that might be
10041 // suppressed by a type_suppression that matches the enclosing
10042 // class of the virtual member function.
10043 else if (type_suppression_sptr type_suppr = is_type_suppression(*i))
10044 {
10045 // Added virtual functions
10046 for (string_function_ptr_map::const_iterator e = added_fns_.begin();
10047 e != added_fns_.end();
10048 ++e)
10049 if (is_member_function(e->second)
10050 && get_member_function_is_virtual(e->second))
10051 {
10052 const function_decl *f = e->second;
10053 class_decl_sptr c =
10054 is_class_type(is_method_type(f->get_type())->get_class_type());
10055 ABG_ASSERT(c);
10056 if (type_suppr->suppresses_type(c, ctxt))
10057 suppressed_added_fns_[e->first] = e->second;
10058 }
10059 // Deleted virtual functions
10060 for (string_function_ptr_map::const_iterator e = deleted_fns_.begin();
10061 e != deleted_fns_.end();
10062 ++e)
10063 if (is_member_function(e->second)
10064 && get_member_function_is_virtual(e->second))
10065 {
10066 const function_decl *f = e->second;
10067 class_decl_sptr c =
10068 is_class_type(is_method_type(f->get_type())->get_class_type());
10069 ABG_ASSERT(c);
10070 if (type_suppr->suppresses_type(c, ctxt))
10071 suppressed_deleted_fns_[e->first] = e->second;
10072 }
10073
10074 // Apply this type suppression to deleted types
10075 // non-reachable from a public interface.
10076 for (string_type_base_sptr_map::const_iterator e =
10077 deleted_unreachable_types_.begin();
10078 e != deleted_unreachable_types_.end();
10079 ++e)
10080 if (type_suppr->suppresses_type(e->second, ctxt))
10081 suppressed_deleted_unreachable_types_[e->first] = e->second;
10082
10083 // Apply this type suppression to added types
10084 // non-reachable from a public interface.
10085 for (string_type_base_sptr_map::const_iterator e =
10086 added_unreachable_types_.begin();
10087 e != added_unreachable_types_.end();
10088 ++e)
10089 if (type_suppr->suppresses_type(e->second, ctxt))
10090 suppressed_added_unreachable_types_[e->first] = e->second;
10091 }
10092 // Added/Deleted variables
10093 else if (variable_suppression_sptr var_suppr =
10095 {
10096 // Added variables
10097 for (string_var_ptr_map::const_iterator e = added_vars_.begin();
10098 e != added_vars_.end();
10099 ++e)
10100 if (variable_is_suppressed(e->second, var_suppr,
10102 ctxt))
10103 suppressed_added_vars_[e->first] = e->second;
10104
10105 //Deleted variables
10106 for (string_var_ptr_map::const_iterator e = deleted_vars_.begin();
10107 e != deleted_vars_.end();
10108 ++e)
10109 if (variable_is_suppressed(e->second, var_suppr,
10111 ctxt))
10112 suppressed_deleted_vars_[e->first] = e->second;
10113
10114 // Added variable symbols not referenced by any debug info
10115 for (string_elf_symbol_map::const_iterator e =
10116 added_unrefed_var_syms_.begin();
10117 e != added_unrefed_var_syms_.end();
10118 ++e)
10119 if (var_suppr->suppresses_variable_symbol(e->second,
10121 ctxt))
10122 suppressed_added_unrefed_var_syms_[e->first] = e->second;
10123
10124 // Removed variable symbols not referenced by any debug info
10125 for (string_elf_symbol_map::const_iterator e =
10126 deleted_unrefed_var_syms_.begin();
10127 e != deleted_unrefed_var_syms_.end();
10128 ++e)
10129 if (var_suppr->suppresses_variable_symbol(e->second,
10131 ctxt))
10132 suppressed_deleted_unrefed_var_syms_[e->first] = e->second;
10133 }
10134 }
10135}
10136
10137/// Test if the change reports for a given deleted function have
10138/// been deleted.
10139///
10140/// @param fn the function to consider.
10141///
10142/// @return true iff the change reports for a give given deleted
10143/// function have been deleted.
10144bool
10146{
10147 if (!fn)
10148 return false;
10149
10150 string_function_ptr_map::const_iterator i =
10151 suppressed_deleted_fns_.find(fn->get_id());
10152
10153 return (i != suppressed_deleted_fns_.end());
10154}
10155
10156/// Test if an added type that is unreachable from public interface
10157/// has been suppressed by a suppression specification.
10158///
10159/// @param t the added unreachable type to be considered.
10160///
10161/// @return true iff @p t has been suppressed by a suppression
10162/// specification.
10163bool
10165{
10166 if (!t)
10167 return false;
10168
10169 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10170 string_type_base_sptr_map::const_iterator i =
10171 suppressed_added_unreachable_types_.find(repr);
10172 if (i == suppressed_added_unreachable_types_.end())
10173 return false;
10174
10175 return true;
10176}
10177
10178/// Test if a deleted type that is unreachable from public interface
10179/// has been suppressed by a suppression specification.
10180///
10181/// @param t the deleted unreachable type to be considered.
10182///
10183/// @return true iff @p t has been suppressed by a suppression
10184/// specification.
10185bool
10187{
10188 if (!t)
10189 return false;
10190
10191 string repr = abigail::ir::get_pretty_representation(t, /*internal=*/false);
10192 string_type_base_sptr_map::const_iterator i =
10193 suppressed_deleted_unreachable_types_.find(repr);
10194 if (i == suppressed_deleted_unreachable_types_.end())
10195 return false;
10196
10197 return true;
10198}
10199
10200/// Test if the change reports for a give given added function has
10201/// been deleted.
10202///
10203/// @param fn the function to consider.
10204///
10205/// @return true iff the change reports for a give given added
10206/// function has been deleted.
10207bool
10209{
10210 if (!fn)
10211 return false;
10212
10213 string_function_ptr_map::const_iterator i =
10214 suppressed_added_fns_.find(fn->get_id());
10215
10216 return (i != suppressed_added_fns_.end());
10217}
10218
10219/// Test if the change reports for a give given deleted variable has
10220/// been deleted.
10221///
10222/// @param var the variable to consider.
10223///
10224/// @return true iff the change reports for a give given deleted
10225/// variable has been deleted.
10226bool
10228{
10229 if (!var)
10230 return false;
10231
10232 string_var_ptr_map::const_iterator i =
10233 suppressed_deleted_vars_.find(var->get_id());
10234
10235 return (i != suppressed_deleted_vars_.end());
10236}
10237
10238/// Test if the change reports for a given added variable have been
10239/// suppressed.
10240///
10241/// @param var the variable to consider.
10242///
10243/// @return true iff the change reports for a given deleted
10244/// variable has been deleted.
10245bool
10247{
10248 if (!var)
10249 return false;
10250
10251 string_var_ptr_map::const_iterator i =
10252 suppressed_added_vars_.find(var->get_id());
10253
10254 return (i != suppressed_added_vars_.end());
10255}
10256
10257/// Test if the change reports for a given deleted function symbol
10258/// (that is not referenced by any debug info) has been suppressed.
10259///
10260/// @param var the function to consider.
10261///
10262/// @return true iff the change reports for a given deleted function
10263/// symbol has been suppressed.
10264bool
10266{
10267 if (!s)
10268 return false;
10269
10270 string_elf_symbol_map::const_iterator i =
10271 suppressed_deleted_unrefed_fn_syms_.find(s->get_id_string());
10272
10273 return (i != suppressed_deleted_unrefed_fn_syms_.end());
10274}
10275
10276/// Test if the change reports for a given added function symbol
10277/// (that is not referenced by any debug info) has been suppressed.
10278///
10279/// @param var the function to consider.
10280///
10281/// @return true iff the change reports for a given added function
10282/// symbol has been suppressed.
10283bool
10285{
10286 if (!s)
10287 return false;
10288
10289 string_elf_symbol_map::const_iterator i =
10290 suppressed_added_unrefed_fn_syms_.find(s->get_id_string());
10291
10292 return (i != suppressed_added_unrefed_fn_syms_.end());
10293}
10294
10295/// Test if the change reports for a given deleted variable symbol
10296/// (that is not referenced by any debug info) has been suppressed.
10297///
10298/// @param var the variable to consider.
10299///
10300/// @return true iff the change reports for a given deleted variable
10301/// symbol has been suppressed.
10302bool
10304{
10305 if (!s)
10306 return false;
10307
10308 string_elf_symbol_map::const_iterator i =
10309 suppressed_deleted_unrefed_var_syms_.find(s->get_id_string());
10310
10311 return (i != suppressed_deleted_unrefed_var_syms_.end());
10312}
10313
10314/// Test if the change reports for a given added variable symbol
10315/// (that is not referenced by any debug info) has been suppressed.
10316///
10317/// @param var the variable to consider.
10318///
10319/// @return true iff the change reports for a given added variable
10320/// symbol has been suppressed.
10321bool
10323{
10324 if (!s)
10325 return false;
10326
10327 string_elf_symbol_map::const_iterator i =
10328 suppressed_added_unrefed_var_syms_.find(s->get_id_string());
10329
10330 return (i != suppressed_added_unrefed_var_syms_.end());
10331}
10332
10333#ifdef do_count_diff_map_changes
10334#undef do_count_diff_map_changes
10335#endif
10336#define do_count_diff_map_changes(diff_map, n_changes, n_filtered) \
10337 { \
10338 string_diff_ptr_map::const_iterator i; \
10339 for (i = diff_map.begin(); \
10340 i != diff_map.end(); \
10341 ++i) \
10342 { \
10343 if (const var_diff* d = is_var_diff(i->second)) \
10344 if (is_data_member(d->first_var())) \
10345 continue; \
10346 \
10347 if (i->second->has_local_changes()) \
10348 ++n_changes; \
10349 if (!i->second->get_canonical_diff()->to_be_reported()) \
10350 ++n_filtered; \
10351 } \
10352 }
10353
10354/// Count the number of leaf changes as well as the number of the
10355/// changes that have been filtered out.
10356///
10357/// @param num_changes out parameter. This is set to the total number
10358/// of leaf changes.
10359///
10360/// @param num_filtered out parameter. This is set to the number of
10361/// leaf changes that have been filtered out.
10362void
10363corpus_diff::priv::count_leaf_changes(size_t &num_changes, size_t &num_filtered)
10364{
10365 count_leaf_type_changes(num_changes, num_filtered);
10366
10367 // Now count the non-type changes.
10368 do_count_diff_map_changes(leaf_diffs_.get_function_decl_diff_map(),
10369 num_changes, num_filtered);
10370 do_count_diff_map_changes(leaf_diffs_.get_var_decl_diff_map(),
10371 num_changes, num_filtered);
10372}
10373
10374/// Count the number of leaf *type* changes as well as the number of
10375/// the leaf type changes that have been filtered out.
10376///
10377/// @param num_changes out parameter. This is set to the total number
10378/// of leaf type changes.
10379///
10380/// @param num_filtered out parameter. This is set to the number of
10381/// leaf type changes that have been filtered out.
10382void
10384 size_t &num_filtered)
10385{
10386 do_count_diff_map_changes(leaf_diffs_.get_type_decl_diff_map(),
10387 num_changes, num_filtered);
10388 do_count_diff_map_changes(leaf_diffs_.get_enum_diff_map(),
10389 num_changes, num_filtered);
10390 do_count_diff_map_changes(leaf_diffs_.get_class_diff_map(),
10391 num_changes, num_filtered);
10392 do_count_diff_map_changes(leaf_diffs_.get_union_diff_map(),
10393 num_changes, num_filtered);
10394 do_count_diff_map_changes(leaf_diffs_.get_typedef_diff_map(),
10395 num_changes, num_filtered);
10396 do_count_diff_map_changes(leaf_diffs_.get_subrange_diff_map(),
10397 num_changes, num_filtered);
10398 do_count_diff_map_changes(leaf_diffs_.get_array_diff_map(),
10399 num_changes, num_filtered);
10400 do_count_diff_map_changes(leaf_diffs_.get_distinct_diff_map(),
10401 num_changes, num_filtered);
10402 do_count_diff_map_changes(leaf_diffs_.get_fn_parm_diff_map(),
10403 num_changes, num_filtered);
10404}
10405
10406/// Count the number of types not reachable from the interface (i.e,
10407/// not reachable from global functions or variables).
10408///
10409/// @param num_added this is set to the number of added types not
10410/// reachable from the interface.
10411///
10412/// @param num_deleted this is set to the number of deleted types not
10413/// reachable from the interface.
10414///
10415/// @param num_changed this is set to the number of changed types not
10416/// reachable from the interface.
10417///
10418/// @param num_filtered_added this is set to the number of added types
10419/// not reachable from the interface and that have been filtered out
10420/// by suppression specifications.
10421///
10422/// @param num_filtered_deleted this is set to the number of deleted
10423/// types not reachable from the interface and that have been filtered
10424/// out by suppression specifications.
10425///
10426/// @param num_filtered_changed this is set to the number of changed
10427/// types not reachable from the interface and that have been filtered
10428/// out by suppression specifications.
10429void
10431 size_t &num_deleted,
10432 size_t &num_changed,
10433 size_t &num_filtered_added,
10434 size_t &num_filtered_deleted,
10435 size_t &num_filtered_changed)
10436{
10437 num_added = added_unreachable_types_.size();
10438 num_deleted = deleted_unreachable_types_.size();
10439 num_changed = changed_unreachable_types_.size();
10440 num_filtered_added = suppressed_added_unreachable_types_.size();
10441 num_filtered_deleted = suppressed_deleted_unreachable_types_.size();
10442
10443 for (vector<diff_sptr>::const_iterator i =
10446 ++i)
10447 if (!(*i)->to_be_reported())
10448 ++num_filtered_changed;
10449}
10450
10451/// Get the map of diff nodes representing changed unreachable types.
10452///
10453/// @return the map of diff nodes representing changed unreachable
10454/// types.
10457{return changed_unreachable_types_;}
10458
10459/// Get the sorted vector of diff nodes representing changed
10460/// unreachable types.
10461///
10462/// Upon the first invocation of this method, if the vector is empty,
10463/// this function gets the diff nodes representing changed
10464/// unreachable, sort them, and return the sorted vector.
10465///
10466/// @return the sorted vector of diff nodes representing changed
10467/// unreachable types.
10468const vector<diff_sptr>&
10470{
10471if (changed_unreachable_types_sorted_.empty())
10472 if (!changed_unreachable_types_.empty())
10473 sort_string_diff_sptr_map(changed_unreachable_types_,
10474 changed_unreachable_types_sorted_);
10475
10476 return changed_unreachable_types_sorted_;
10477}
10478
10479/// Compute the diff stats.
10480///
10481/// To know the number of functions that got filtered out, this
10482/// function applies the categorizing filters to the diff sub-trees of
10483/// each function changes diff, prior to calculating the stats.
10484///
10485/// @param num_removed the number of removed functions.
10486///
10487/// @param num_added the number of added functions.
10488///
10489/// @param num_changed the number of changed functions.
10490///
10491/// @param num_filtered_out the number of changed functions that are
10492/// got filtered out from the report
10493void
10495{
10496 stat.num_func_removed(deleted_fns_.size());
10497 stat.num_removed_func_filtered_out(suppressed_deleted_fns_.size());
10498 stat.num_func_added(added_fns_.size());
10499 stat.num_added_func_filtered_out(suppressed_added_fns_.size());
10500 stat.num_func_changed(changed_fns_map_.size());
10501
10502 stat.num_vars_removed(deleted_vars_.size());
10503 stat.num_removed_vars_filtered_out(suppressed_deleted_vars_.size());
10504 stat.num_vars_added(added_vars_.size());
10505 stat.num_added_vars_filtered_out(suppressed_added_vars_.size());
10506 stat.num_vars_changed(changed_vars_map_.size());
10507
10508 diff_context_sptr ctxt = get_context();
10509
10511 if (ctxt->perform_change_categorization())
10512 {
10513 if (get_context()->do_log())
10514 {
10515 std::cerr << "in apply_filters_and_compute_diff_stats:"
10516 << "applying filters to "
10517 << changed_fns_.size()
10518 << " changed fns ...\n";
10519 t.start();
10520 }
10521 // Walk the changed function diff nodes to apply the categorization
10522 // filters.
10524 for (function_decl_diff_sptrs_type::const_iterator i =
10525 changed_fns_.begin();
10526 i != changed_fns_.end();
10527 ++i)
10528 {
10529 diff_sptr diff = *i;
10530 ctxt->maybe_apply_filters(diff);
10531 }
10532
10533 if (get_context()->do_log())
10534 {
10535 t.stop();
10536 std::cerr << "in apply_filters_and_compute_diff_stats:"
10537 << "filters to changed fn applied!:" << t << "\n";
10538
10539 std::cerr << "in apply_filters_and_compute_diff_stats:"
10540 << "applying filters to "
10541 << sorted_changed_vars_.size()
10542 << " changed vars ...\n";
10543 t.start();
10544 }
10545
10546 // Walk the changed variable diff nodes to apply the categorization
10547 // filters.
10548 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
10549 i != sorted_changed_vars_.end();
10550 ++i)
10551 {
10552 diff_sptr diff = *i;
10553 ctxt->maybe_apply_filters(diff);
10554 }
10555
10556 if (get_context()->do_log())
10557 {
10558 t.stop();
10559 std::cerr << "in apply_filters_and_compute_diff_stats:"
10560 << "filters to changed vars applied!:" << t << "\n";
10561
10562 std::cerr << "in apply_filters_and_compute_diff_stats:"
10563 << "applying filters to unreachable types ...\n";
10564 t.start();
10565 }
10566
10567 // walk the changed unreachable types to apply categorization
10568 // filters
10570 ctxt->maybe_apply_filters(diff);
10571
10572 for (auto& entry : changed_unreachable_types())
10573 ctxt->maybe_apply_filters(entry.second);
10574
10575 if (get_context()->do_log())
10576 {
10577 t.stop();
10578 std::cerr << "in apply_filters_and_compute_diff_stats:"
10579 << "filters to unreachable types applied!:" << t << "\n";
10580
10581 std::cerr << "in apply_filters_and_compute_diff_stats:"
10582 << "categorizing redundant changed sub nodes ...\n";
10583 t.start();
10584 }
10585
10586 categorize_redundant_changed_sub_nodes();
10587
10588 if (get_context()->do_log())
10589 {
10590 t.stop();
10591 std::cerr << "in apply_filters_and_compute_diff_stats:"
10592 << "redundant changed sub nodes categorized!:" << t << "\n";
10593
10594 std::cerr << "in apply_filters_and_compute_diff_stats:"
10595 << "count changed fns ...\n";
10596 t.start();
10597 }
10598 }
10599
10600 // Walk the changed function diff nodes to count the number of
10601 // filtered-out functions and the number of functions with virtual
10602 // offset changes.
10603 for (function_decl_diff_sptrs_type::const_iterator i =
10604 changed_fns_.begin();
10605 i != changed_fns_.end();
10606 ++i)
10607 {
10608 if ((*i)->is_filtered_out())
10609 {
10611 (stat.num_changed_func_filtered_out() + 1);
10612
10613 if ((*i)->has_local_changes())
10616 }
10617 else
10618 {
10619 if ((*i)->get_category() & VIRTUAL_MEMBER_CHANGE_CATEGORY)
10622 }
10623
10624 if ((*i)->has_local_changes())
10626 (stat.num_leaf_func_changes() + 1);
10627 }
10628
10629 if (get_context()->do_log())
10630 {
10631 t.stop();
10632 std::cerr << "in apply_filters_and_compute_diff_stats:"
10633 << "changed fn counted!:" << t << "\n";
10634
10635 std::cerr << "in apply_filters_and_compute_diff_stats:"
10636 << "count changed vars ...\n";
10637 t.start();
10638 }
10639
10640 // Walk the changed variables diff nodes to count the number of
10641 // filtered-out variables.
10642 for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
10643 i != sorted_changed_vars_.end();
10644 ++i)
10645 {
10646 if ((*i)->is_filtered_out())
10647 {
10649 (stat.num_changed_vars_filtered_out() + 1);
10650
10651 if ((*i)->has_local_changes())
10654 }
10655 if ((*i)->has_local_changes())
10657 (stat.num_leaf_var_changes() + 1);
10658 }
10659
10660 if (get_context()->do_log())
10661 {
10662 t.stop();
10663 std::cerr << "in apply_filters_and_compute_diff_stats:"
10664 << "changed vars counted!:" << t << "\n";
10665
10666 std::cerr << "in apply_filters_and_compute_diff_stats:"
10667 << "count leaf changed types ...\n";
10668 t.start();
10669 }
10670
10671 stat.num_func_syms_added(added_unrefed_fn_syms_.size());
10672 stat.num_added_func_syms_filtered_out(suppressed_added_unrefed_fn_syms_.size());
10673 stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
10674 stat.num_removed_func_syms_filtered_out(suppressed_deleted_unrefed_fn_syms_.size());
10675 stat.num_var_syms_added(added_unrefed_var_syms_.size());
10676 stat.num_added_var_syms_filtered_out(suppressed_added_unrefed_var_syms_.size());
10677 stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
10678 stat.num_removed_var_syms_filtered_out(suppressed_deleted_unrefed_var_syms_.size());
10679
10680 // Walk the general leaf type diff nodes to count them
10681 {
10682 size_t num_type_changes = 0, num_type_filtered = 0;
10683 count_leaf_type_changes(num_type_changes, num_type_filtered);
10684
10685 stat.num_leaf_type_changes(num_type_changes);
10686 stat.num_leaf_type_changes_filtered_out(num_type_filtered);
10687 }
10688
10689 if (get_context()->do_log())
10690 {
10691 t.stop();
10692 std::cerr << "in apply_filters_and_compute_diff_stats:"
10693 << "changed leaf types counted!:" << t << "\n";
10694
10695 std::cerr << "in apply_filters_and_compute_diff_stats:"
10696 << "count leaf changed artefacts ...\n";
10697 t.start();
10698 }
10699
10700 // Walk the general leaf artefacts diff nodes to count them
10701 {
10702 size_t num_changes = 0, num_filtered = 0;
10703 count_leaf_changes(num_changes, num_filtered);
10704
10705 stat.num_leaf_changes(num_changes);
10706 stat.num_leaf_changes_filtered_out(num_filtered);
10707 }
10708
10709 if (get_context()->do_log())
10710 {
10711 t.stop();
10712 std::cerr << "in apply_filters_and_compute_diff_stats:"
10713 << "changed leaf artefacts counted!:" << t << "\n";
10714
10715 std::cerr << "in apply_filters_and_compute_diff_stats:"
10716 << "count unreachable types ...\n";
10717 t.start();
10718 }
10719
10720 // Walk the unreachable types to count them
10721 {
10722 size_t num_added_unreachable_types = 0,
10723 num_changed_unreachable_types = 0,
10724 num_deleted_unreachable_types = 0,
10725 num_added_unreachable_types_filtered = 0,
10726 num_changed_unreachable_types_filtered = 0,
10727 num_deleted_unreachable_types_filtered = 0;
10728
10729 count_unreachable_types(num_added_unreachable_types,
10730 num_deleted_unreachable_types,
10731 num_changed_unreachable_types,
10732 num_added_unreachable_types_filtered,
10733 num_deleted_unreachable_types_filtered,
10734 num_changed_unreachable_types_filtered);
10735
10736 if (get_context()->do_log())
10737 {
10738 t.stop();
10739 std::cerr << "in apply_filters_and_compute_diff_stats:"
10740 << "unreachable types counted!:" << t << "\n";
10741 }
10742
10743 stat.num_added_unreachable_types(num_added_unreachable_types);
10744 stat.num_removed_unreachable_types(num_deleted_unreachable_types);
10745 stat.num_changed_unreachable_types(num_changed_unreachable_types);
10747 (num_added_unreachable_types_filtered);
10749 (num_deleted_unreachable_types_filtered);
10751 (num_changed_unreachable_types_filtered);
10752 }
10753}
10754
10755/// Emit the summary of the functions & variables that got
10756/// removed/changed/added.
10757///
10758/// TODO: This should be handled by the reporters, just like what is
10759/// done for reporter_base::diff_to_be_reported.
10760///
10761/// @param out the output stream to emit the stats to.
10762///
10763/// @param indent the indentation string to use in the summary.
10764void
10766 ostream& out,
10767 const string& indent)
10768{
10769 /// Report added/removed/changed functions.
10770 size_t net_num_leaf_changes =
10772 s.net_num_func_added() +
10775 s.net_num_vars_added() +
10782
10783 if (!sonames_equal_)
10784 out << indent << "ELF SONAME changed\n";
10785
10786 if (!architectures_equal_)
10787 out << indent << "ELF architecture changed\n";
10788
10789 diff_context_sptr ctxt = get_context();
10790
10791 if (ctxt->show_leaf_changes_only())
10792 {
10793 out << "Leaf changes summary: ";
10794 out << net_num_leaf_changes << " artifact";
10795 if (net_num_leaf_changes > 1)
10796 out << "s";
10797 out << " changed";
10798
10799 if (size_t num_filtered = s.num_leaf_changes_filtered_out())
10800 out << " (" << num_filtered << " filtered out)";
10801 out << "\n";
10802
10803 out << indent << "Changed leaf types summary: "
10806 out << " (" << s.num_leaf_type_changes_filtered_out()
10807 << " filtered out)";
10808 out << " leaf type";
10809 if (s.num_leaf_type_changes() > 1)
10810 out << "s";
10811 out << " changed\n";
10812
10813 // function changes summary
10814 out << indent << "Removed/Changed/Added functions summary: ";
10815 out << s.net_num_func_removed() << " Removed";
10817 out << " ("
10819 << " filtered out)";
10820 out << ", ";
10821
10822 out << s.net_num_leaf_func_changes() << " Changed";
10824 out << " ("
10826 << " filtered out)";
10827 out << ", ";
10828
10829 out << s.net_num_func_added()<< " Added ";
10830 if (s.net_num_func_added() <= 1)
10831 out << "function";
10832 else
10833 out << "functions";
10835 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10836 out << "\n";
10837
10838 // variables changes summary
10839 out << indent << "Removed/Changed/Added variables summary: ";
10840 out << s.net_num_vars_removed() << " Removed";
10842 out << " (" << s.num_removed_vars_filtered_out()
10843 << " filtered out)";
10844 out << ", ";
10845
10846 out << s.net_num_leaf_var_changes() << " Changed";
10848 out << " ("
10850 << " filtered out)";
10851 out << ", ";
10852
10853 out << s.net_num_vars_added() << " Added ";
10854 if (s.net_num_vars_added() <= 1)
10855 out << "variable";
10856 else
10857 out << "variables";
10859 out << " (" << s.num_added_vars_filtered_out()
10860 << " filtered out)";
10861 out << "\n";
10862 }
10863 else // if (ctxt->show_leaf_changes_only())
10864 {
10865 size_t total_nb_function_changes = s.num_func_removed()
10866 + s.num_func_changed() + s.num_func_added();
10867
10868 // function changes summary
10869 out << indent << "Functions changes summary: ";
10870 out << s.net_num_func_removed() << " Removed";
10872 out << " ("
10874 << " filtered out)";
10875 out << ", ";
10876
10877 out << s.net_num_func_changed() << " Changed";
10879 out << " (" << s.num_changed_func_filtered_out() << " filtered out)";
10880 out << ", ";
10881
10882 out << s.net_num_func_added() << " Added";
10884 out << " (" << s.num_added_func_filtered_out() << " filtered out)";
10885 if (total_nb_function_changes <= 1)
10886 out << " function";
10887 else
10888 out << " functions";
10889 out << "\n";
10890
10891 // variables changes summary
10892 size_t total_nb_variable_changes = s.num_vars_removed()
10893 + s.num_vars_changed() + s.num_vars_added();
10894
10895 out << indent << "Variables changes summary: ";
10896 out << s.net_num_vars_removed() << " Removed";
10898 out << " (" << s.num_removed_vars_filtered_out()
10899 << " filtered out)";
10900 out << ", ";
10901
10902 out << s.num_vars_changed() - s.num_changed_vars_filtered_out() << " Changed";
10904 out << " (" << s.num_changed_vars_filtered_out() << " filtered out)";
10905 out << ", ";
10906
10907 out << s.net_num_vars_added() << " Added";
10909 out << " (" << s.num_added_vars_filtered_out()
10910 << " filtered out)";
10911 if (total_nb_variable_changes <= 1)
10912 out << " variable";
10913 else
10914 out << " variables";
10915 out << "\n";
10916 }
10917
10918 // Show statistics about types not reachable from global
10919 // functions/variables.
10920 if (ctxt->show_unreachable_types())
10921 {
10922 size_t total_nb_unreachable_type_changes =
10926
10927 // Show summary of unreachable types
10928 out << indent << "Unreachable types summary: "
10930 << " removed";
10933 << " filtered out)";
10934 out << ", ";
10935
10937 << " changed";
10940 << " filtered out)";
10941 out << ", ";
10942
10944 << " added";
10947 << " filtered out)";
10948 if (total_nb_unreachable_type_changes <= 1)
10949 out << " type";
10950 else
10951 out << " types";
10952 out << "\n";
10953 }
10954
10955 if (ctxt->show_symbols_unreferenced_by_debug_info()
10956 && (s.num_func_syms_removed()
10957 || s.num_func_syms_added()
10959 || s.num_var_syms_added()))
10960 {
10961 // function symbols changes summary.
10962
10963 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10964 && s.num_func_syms_removed() == 0
10965 && s.num_func_syms_added() != 0)
10966 // If the only unreferenced function symbol change is function
10967 // syms that got added, but we were forbidden to show function
10968 // syms being added, do nothing.
10969 ;
10970 else
10971 {
10972 out << indent
10973 << "Function symbols changes summary: "
10974 << s.net_num_removed_func_syms() << " Removed";
10976 out << " (" << s.num_removed_func_syms_filtered_out()
10977 << " filtered out)";
10978 out << ", ";
10979 out << s.net_num_added_func_syms() << " Added";
10981 out << " (" << s.num_added_func_syms_filtered_out()
10982 << " filtered out)";
10983 out << " function symbol";
10985 out << "s";
10986 out << " not referenced by debug info\n";
10987 }
10988
10989 // variable symbol changes summary.
10990
10991 if (!ctxt->show_added_symbols_unreferenced_by_debug_info()
10992 && s.num_var_syms_removed() == 0
10993 && s.num_var_syms_added() != 0)
10994 // If the only unreferenced variable symbol change is variable
10995 // syms that got added, but we were forbidden to show variable
10996 // syms being added, do nothing.
10997 ;
10998 else
10999 {
11000 out << indent
11001 << "Variable symbols changes summary: "
11002 << s.net_num_removed_var_syms() << " Removed";
11004 out << " (" << s.num_removed_var_syms_filtered_out()
11005 << " filtered out)";
11006 out << ", ";
11007 out << s.net_num_added_var_syms() << " Added";
11009 out << " (" << s.num_added_var_syms_filtered_out()
11010 << " filtered out)";
11011 out << " variable symbol";
11012 if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
11013 out << "s";
11014 out << " not referenced by debug info\n";
11015 }
11016 }
11017}
11018
11019/// Walk the changed functions and variables diff nodes to categorize
11020/// redundant nodes.
11021void
11023{
11025
11026 diff_context_sptr ctxt = get_context();
11027
11028 ctxt->forget_visited_diffs();
11029 for (function_decl_diff_sptrs_type::const_iterator i =
11030 changed_fns_.begin();
11031 i!= changed_fns_.end();
11032 ++i)
11033 {
11034 diff = *i;
11036 }
11037
11038 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11039 i!= sorted_changed_vars_.end();
11040 ++i)
11041 {
11042 diff_sptr diff = *i;
11044 }
11045
11046 for (diff_sptrs_type::const_iterator i =
11049 ++i)
11050 {
11051 diff_sptr diff = *i;
11053 }
11054}
11055
11056/// Walk the changed functions and variables diff nodes and clear the
11057/// redundancy categorization they might carry.
11058void
11060{
11062 for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
11063 i!= changed_fns_.end();
11064 ++i)
11065 {
11066 diff = *i;
11068 }
11069
11070 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11071 i!= sorted_changed_vars_.end();
11072 ++i)
11073 {
11074 diff = *i;
11076 }
11077}
11078
11079/// If the user asked to dump the diff tree node (for changed
11080/// variables and functions) on the error output stream, then just do
11081/// that.
11082///
11083/// This function is used for debugging purposes.
11084void
11086{
11087 diff_context_sptr ctxt = get_context();
11088
11089 if (!ctxt->dump_diff_tree()
11090 || ctxt->error_output_stream() == 0)
11091 return;
11092
11093 if (!changed_fns_.empty())
11094 {
11095 *ctxt->error_output_stream() << "changed functions diff tree: \n\n";
11096 for (function_decl_diff_sptrs_type::const_iterator i =
11097 changed_fns_.begin();
11098 i != changed_fns_.end();
11099 ++i)
11100 {
11101 diff_sptr d = *i;
11102 print_diff_tree(d, *ctxt->error_output_stream());
11103 }
11104 }
11105
11106 if (!sorted_changed_vars_.empty())
11107 {
11108 *ctxt->error_output_stream() << "\nchanged variables diff tree: \n\n";
11109 for (var_diff_sptrs_type::const_iterator i =
11110 sorted_changed_vars_.begin();
11111 i != sorted_changed_vars_.end();
11112 ++i)
11113 {
11114 diff_sptr d = *i;
11115 print_diff_tree(d, *ctxt->error_output_stream());
11116 }
11117 }
11118
11119 if (!changed_unreachable_types_sorted().empty())
11120 {
11121 *ctxt->error_output_stream() << "\nchanged unreachable "
11122 "types diff tree: \n\n";
11123 for (vector<diff_sptr>::const_iterator i =
11126 ++i)
11127 {
11128 diff_sptr d = *i;
11129 print_diff_tree(d, *ctxt->error_output_stream());
11130 }
11131 }
11132}
11133
11134/// Populate the vector of children node of the @ref corpus_diff type.
11135///
11136/// The children node can then later be retrieved using
11137/// corpus_diff::children_node().
11138void
11140{
11141 for (function_decl_diff_sptrs_type::const_iterator i =
11142 changed_functions_sorted().begin();
11143 i != changed_functions_sorted().end();
11144 ++i)
11145 if (diff_sptr d = *i)
11147}
11148
11149/// Constructor for @ref corpus_diff.
11150///
11151/// @param first the first corpus of the diff.
11152///
11153/// @param second the second corpus of the diff.
11154///
11155/// @param ctxt the diff context to use. Note that this context
11156/// object must stay alive at least during the life time of the
11157/// current instance of @ref corpus_diff. Otherwise memory corruption
11158/// issues occur.
11160 corpus_sptr second,
11161 diff_context_sptr ctxt)
11162 : priv_(new priv(first, second, ctxt))
11163{}
11164
11165corpus_diff::~corpus_diff() = default;
11166
11167/// Finish building the current instance of @ref corpus_diff.
11168void
11170{
11171 if (priv_->finished_)
11172 return;
11174 priv_->finished_ = true;
11175}
11176
11177/// Test if logging was requested.
11178///
11179/// @return true iff logging was requested.
11180bool
11182{return context()->do_log();}
11183
11184/// Request logging, or not.
11185///
11186/// @param f true iff logging is requested.
11187void
11189{context()->do_log(f);}
11190
11191/// @return the first corpus of the diff.
11192corpus_sptr
11194{return priv_->first_;}
11195
11196/// @return the second corpus of the diff.
11197corpus_sptr
11199{return priv_->second_;}
11200
11201/// @return the children nodes of the current instance of corpus_diff.
11202const vector<diff*>&
11204{return priv_->children_;}
11205
11206/// Append a new child node to the vector of children nodes for the
11207/// current instance of @ref corpus_diff node.
11208///
11209/// Note that the vector of children nodes for the current instance of
11210/// @ref corpus_diff node must remain sorted, using
11211/// diff_less_than_functor.
11212///
11213/// @param d the new child node. Note that the life time of the
11214/// object held by @p d will thus equal the life time of the current
11215/// instance of @ref corpus_diff.
11216void
11218{
11219 ABG_ASSERT(d);
11220
11221 diff_less_than_functor is_less_than;
11222 bool inserted = false;
11223 for (vector<diff*>::iterator i = priv_->children_.begin();
11224 i != priv_->children_.end();
11225 ++i)
11226 // Look for the point where to insert the diff child node.
11227 if (!is_less_than(d.get(), *i))
11228 {
11229 context()->keep_diff_alive(d);
11230 priv_->children_.insert(i, d.get());
11231 // As we have just inserted 'd' into the vector, the iterator
11232 // 'i' is invalidated. We must *NOT* use it anymore.
11233 inserted = true;
11234 break;
11235 }
11236
11237 if (!inserted)
11238 {
11239 context()->keep_diff_alive(d);
11240 // We didn't insert anything to the vector, presumably b/c it was
11241 // empty or had one element that was "less than" 'd'. We can thus
11242 // just append 'd' to the end of the vector.
11243 priv_->children_.push_back(d.get());
11244 }
11245}
11246
11247/// @return the bare edit script of the functions changed as recorded
11248/// by the diff.
11251{return priv_->fns_edit_script_;}
11252
11253/// @return the bare edit script of the variables changed as recorded
11254/// by the diff.
11257{return priv_->vars_edit_script_;}
11258
11259/// Test if the soname of the underlying corpus has changed.
11260///
11261/// @return true iff the soname has changed.
11262bool
11264{return !priv_->sonames_equal_;}
11265
11266/// Test if the architecture of the underlying corpus has changed.
11267///
11268/// @return true iff the architecture has changed.
11269bool
11271{return !priv_->architectures_equal_;}
11272
11273/// Getter for the deleted functions of the diff.
11274///
11275/// @return the the deleted functions of the diff.
11278{return priv_->deleted_fns_;}
11279
11280/// Getter for the added functions of the diff.
11281///
11282/// @return the added functions of the diff.
11285{return priv_->added_fns_;}
11286
11287/// Getter for the functions which signature didn't change, but which
11288/// do have some indirect changes in their parms.
11289///
11290/// @return a non-sorted map of functions which signature didn't
11291/// change, but which do have some indirect changes in their parms.
11292/// The key of the map is a unique identifier for the function; it's
11293/// usually made of the name and version of the underlying ELF symbol
11294/// of the function for corpora that were built from ELF files.
11297{return priv_->changed_fns_map_;}
11298
11299/// Getter for a sorted vector of functions which signature didn't
11300/// change, but which do have some indirect changes in their parms.
11301///
11302/// @return a sorted vector of functions which signature didn't
11303/// change, but which do have some indirect changes in their parms.
11306{return priv_->changed_fns_;}
11307
11308/// Getter for the variables that got deleted from the first subject
11309/// of the diff.
11310///
11311/// @return the map of deleted variable.
11312const string_var_ptr_map&
11314{return priv_->deleted_vars_;}
11315
11316/// Getter for the added variables of the diff.
11317///
11318/// @return the map of added variable.
11319const string_var_ptr_map&
11321{return priv_->added_vars_;}
11322
11323/// Getter for the non-sorted map of variables which signature didn't
11324/// change but which do have some indirect changes in some sub-types.
11325///
11326/// @return the non-sorted map of changed variables.
11329{return priv_->changed_vars_map_;}
11330
11331/// Getter for the sorted vector of variables which signature didn't
11332/// change but which do have some indirect changes in some sub-types.
11333///
11334/// @return a sorted vector of changed variables.
11337{return priv_->sorted_changed_vars_;}
11338
11339/// Getter for function symbols not referenced by any debug info and
11340/// that got deleted.
11341///
11342/// @return a map of elf function symbols not referenced by any debug
11343/// info and that got deleted.
11346{return priv_->deleted_unrefed_fn_syms_;}
11347
11348/// Getter for function symbols not referenced by any debug info and
11349/// that got added.
11350///
11351/// @return a map of elf function symbols not referenced by any debug
11352/// info and that got added.
11355{return priv_->added_unrefed_fn_syms_;}
11356
11357/// Getter for variable symbols not referenced by any debug info and
11358/// that got deleted.
11359///
11360/// @return a map of elf variable symbols not referenced by any debug
11361/// info and that got deleted.
11364{return priv_->deleted_unrefed_var_syms_;}
11365
11366/// Getter for variable symbols not referenced by any debug info and
11367/// that got added.
11368///
11369/// @return a map of elf variable symbols not referenced by any debug
11370/// info and that got added.
11373{return priv_->added_unrefed_var_syms_;}
11374
11375/// Getter for a map of deleted types that are not reachable from
11376/// global functions/variables.
11377///
11378/// @return a map that associates pretty representation of deleted
11379/// unreachable types and said types.
11382{return priv_->deleted_unreachable_types_;}
11383
11384/// Getter of a sorted vector of deleted types that are not reachable
11385/// from global functions/variables.
11386///
11387/// @return a sorted vector of deleted types that are not reachable
11388/// from global functions/variables. The types are lexicographically
11389/// sorted by considering their pretty representation.
11390const vector<type_base_sptr>&
11392{
11393 if (priv_->deleted_unreachable_types_sorted_.empty())
11394 if (!priv_->deleted_unreachable_types_.empty())
11395 sort_string_type_base_sptr_map(priv_->deleted_unreachable_types_,
11396 priv_->deleted_unreachable_types_sorted_);
11397
11398 return priv_->deleted_unreachable_types_sorted_;
11399}
11400
11401/// Getter for a map of added types that are not reachable from global
11402/// functions/variables.
11403///
11404/// @return a map that associates pretty representation of added
11405/// unreachable types and said types.
11408{return priv_->added_unreachable_types_;}
11409
11410/// Getter of a sorted vector of added types that are not reachable
11411/// from global functions/variables.
11412///
11413/// @return a sorted vector of added types that are not reachable from
11414/// global functions/variables. The types are lexicographically
11415/// sorted by considering their pretty representation.
11416const vector<type_base_sptr>&
11418{
11419 if (priv_->added_unreachable_types_sorted_.empty())
11420 if (!priv_->added_unreachable_types_.empty())
11421 sort_string_type_base_sptr_map(priv_->added_unreachable_types_,
11422 priv_->added_unreachable_types_sorted_);
11423
11424 return priv_->added_unreachable_types_sorted_;
11425}
11426
11427/// Getter for a map of changed types that are not reachable from
11428/// global functions/variables.
11429///
11430/// @return a map that associates pretty representation of changed
11431/// unreachable types and said types.
11434{return priv_->changed_unreachable_types_;}
11435
11436/// Getter of a sorted vector of changed types that are not reachable
11437/// from global functions/variables.
11438///
11439/// @return a sorted vector of changed types that are not reachable
11440/// from global functions/variables. The diffs are lexicographically
11441/// sorted by considering their pretty representation.
11442const vector<diff_sptr>&
11444{return priv_->changed_unreachable_types_sorted();}
11445
11446/// Getter of the diff context of this diff
11447///
11448/// @return the diff context for this diff.
11451{return priv_->get_context();}
11452
11453/// @return the pretty representation for the current instance of @ref
11454/// corpus_diff
11455const string&
11457{
11458 if (priv_->pretty_representation_.empty())
11459 {
11460 std::ostringstream o;
11461 o << "corpus_diff["
11462 << first_corpus()->get_path()
11463 << ", "
11464 << second_corpus()->get_path()
11465 << "]";
11466 priv_->pretty_representation_ = o.str();
11467 }
11468 return priv_->pretty_representation_;
11469}
11470/// Return true iff the current @ref corpus_diff node carries a
11471/// change.
11472///
11473/// @return true iff the current diff node carries a change.
11474bool
11476{
11477 return (soname_changed()
11479 || !(priv_->deleted_fns_.empty()
11480 && priv_->added_fns_.empty()
11481 && priv_->changed_fns_map_.empty()
11482 && priv_->deleted_vars_.empty()
11483 && priv_->added_vars_.empty()
11484 && priv_->changed_vars_map_.empty()
11485 && priv_->added_unrefed_fn_syms_.empty()
11486 && priv_->deleted_unrefed_fn_syms_.empty()
11487 && priv_->added_unrefed_var_syms_.empty()
11488 && priv_->deleted_unrefed_var_syms_.empty()
11489 && priv_->deleted_unreachable_types_.empty()
11490 && priv_->added_unreachable_types_.empty()
11491 && priv_->changed_unreachable_types_.empty()));
11492}
11493
11494/// Test if the current instance of @ref corpus_diff carries changes
11495/// that we are sure are incompatible. By incompatible change we mean
11496/// a change that "breaks" the ABI of the corpus we are looking at.
11497///
11498/// In concrete terms, this function considers the following changes
11499/// as being ABI incompatible for sure:
11500///
11501/// - a soname change
11502/// - if exported functions or variables got removed
11503///
11504/// Note that subtype changes *can* represent changes that break ABI
11505/// too. But they also can be changes that are OK, ABI-wise.
11506///
11507/// It's up to the user to provide suppression specifications to say
11508/// explicitely which subtype change is OK. The remaining sub-type
11509/// changes are then considered to be ABI incompatible. But to test
11510/// if such ABI incompatible subtype changes are present you need to
11511/// use the function @ref corpus_diff::has_net_subtype_changes()
11512///
11513/// @return true iff the current instance of @ref corpus_diff carries
11514/// changes that we are sure are ABI incompatible.
11515bool
11517{
11518 const diff_stats& stats = const_cast<corpus_diff*>(this)->
11520
11523 || stats.net_num_func_removed() != 0
11525 // If all reports about functions with sub-type changes
11526 // have been suppressed, then even those about functions
11527 // that are virtual don't matter anymore because the
11528 // user willingly requested to shut them down
11529 && stats.net_num_func_changed() != 0)
11530 || stats.net_num_vars_removed() != 0
11531 || stats.net_num_removed_func_syms() != 0
11532 || stats.net_num_removed_var_syms() != 0
11533 || stats.net_num_removed_unreachable_types() != 0);
11534
11535 // If stats.net_num_changed_unreachable_types() != 0 then walk the
11536 // corpus_diff::priv::changed_unreachable_types_, and see if there
11537 // is one that is harmful by bitwise and-ing their category with
11538 // abigail::comparison::get_default_harmful_categories_bitmap().
11541 {
11542 // The changed unreachable types can carry harmful changes.
11543 // Let's figure if they actually do.
11544
11545 diff_context_sptr ctxt = context();
11546 for (auto &entry : priv_->changed_unreachable_types())
11547 {
11548 diff_sptr dif = entry.second;
11549
11550 // Let's see if any of the categories of this diff node
11551 // belong to the "harmful" ones.
11552 if (dif->get_category() & get_default_harmful_categories_bitmap())
11553 {
11555 break;
11556 }
11557 }
11558 }
11559
11561}
11562
11563/// Test if the current instance of @ref corpus_diff carries subtype
11564/// changes whose reports are not suppressed by any suppression
11565/// specification. In effect, these are deemed incompatible ABI
11566/// changes.
11567///
11568/// @return true iff the the current instance of @ref corpus_diff
11569/// carries subtype changes that are deemed incompatible ABI changes.
11570bool
11572{
11573 const diff_stats& stats = const_cast<corpus_diff*>(this)->
11575
11576 return (stats.net_num_func_changed() != 0
11577 || stats.net_num_vars_changed() != 0
11578 || stats.net_num_removed_unreachable_types() != 0
11579 || stats.net_num_changed_unreachable_types() != 0);
11580}
11581
11582/// Test if the current instance of @ref corpus_diff carries changes
11583/// whose reports are not suppressed by any suppression specification.
11584/// In effect, these are deemed incompatible ABI changes.
11585///
11586/// @return true iff the the current instance of @ref corpus_diff
11587/// carries subtype changes that are deemed incompatible ABI changes.
11588bool
11590{return context()->get_reporter()->diff_has_net_changes(this);}
11591
11592/// Apply the different filters that are registered to be applied to
11593/// the diff tree; that includes the categorization filters. Also,
11594/// apply the suppression interpretation filters.
11595///
11596/// After the filters are applied, this function calculates some
11597/// statistics about the changes carried by the current instance of
11598/// @ref corpus_diff. These statistics are represented by an instance
11599/// of @ref corpus_diff::diff_stats.
11600///
11601/// This member function is called by the reporting function
11602/// corpus_diff::report().
11603///
11604/// Note that for a given instance of corpus_diff, this function
11605/// applies the filters and suppressions only the first time it is
11606/// invoked. Subsequent invocations just return the instance of
11607/// corpus_diff::diff_stats that was cached after the first
11608/// invocation.
11609///
11610/// @return a reference to the statistics about the changes carried by
11611/// the current instance of @ref corpus_diff.
11614{
11615 if (priv_->diff_stats_)
11616 return *priv_->diff_stats_;
11617
11619 if (do_log())
11620 {
11621 std::cerr << "Applying suppressions ...\n";
11622 t.start();
11623 }
11624
11625 apply_suppressions(this);
11626
11627 if (do_log())
11628 {
11629 t.stop();
11630 std::cerr << "suppressions applied!:" << t << "\n";
11631 }
11632
11633 priv_->diff_stats_.reset(new diff_stats(context()));
11634
11635 if (do_log())
11636 {
11637 std::cerr << "Marking leaf nodes ...\n";
11638 t.start();
11639 }
11640
11642
11643 if (do_log())
11644 {
11645 t.stop();
11646 std::cerr << "leaf nodes marked!:" << t << "\n";
11647 std::cerr << "Applying filters and computing diff stats ...\n";
11648 t.start();
11649 }
11650
11651 priv_->apply_filters_and_compute_diff_stats(*priv_->diff_stats_);
11652
11653 if (do_log())
11654 {
11655 t.stop();
11656 std::cerr << "Filters applied and diff stats computed!: " << t << "\n";
11657 }
11658
11659 return *priv_->diff_stats_;
11660}
11661
11662/// A visitor that marks leaf diff nodes by storing them in the
11663/// instance of @ref diff_maps returned by
11664/// corpus_diff::get_leaf_diffs() invoked on the current instance of
11665/// corpus_diff.
11666struct leaf_diff_node_marker_visitor : public diff_node_visitor
11667{
11668 /// This is called when the visitor visits a diff node.
11669 ///
11670 /// It basically tests if the diff node being visited is a leaf diff
11671 /// node - that is, it contains local changes. If it does, then the
11672 /// node is added to the set of maps that hold leaf diffs in the
11673 /// current corpus_diff.
11674 ///
11675 /// Note that only leaf nodes that are reachable from public
11676 /// interfaces (global functions or variables) are collected by this
11677 /// visitor.
11678 ///
11679 /// @param d the diff node being visited.
11680 virtual void
11681 visit_begin(diff *d)
11682 {
11683 if (d->has_local_changes()
11684 // A leaf basic (or class/union) type name change makes no
11685 // sense when showing just leaf changes. It only makes sense
11686 // when it can explain the details about a non-leaf change.
11687 // In other words, it doesn't make sense to say that an "int"
11688 // became "unsigned int". But it does make sense to say that
11689 // a typedef changed because its underlying type was 'int' and
11690 // is now an "unsigned int".
11692 // Similarly, a *local* change describing a type that changed
11693 // its nature doesn't make sense.
11694 && !is_distinct_diff(d)
11695 // Similarly, a pointer (or reference or array), a typedef or
11696 // qualified type change in itself doesn't make sense. It
11697 // would rather make sense to show that pointer change as part
11698 // of the variable change whose pointer type changed, for
11699 // instance.
11700 && !is_pointer_diff(d)
11701 && !is_reference_diff(d)
11703 && !is_typedef_diff(d)
11704 && !is_array_diff(d)
11705 // Similarly a parameter change in itself doesn't make sense.
11706 // It should have already been reported as part of the change
11707 // of the function it belongs to.
11708 && !is_fn_parm_diff(d)
11709 // An anonymous class or union diff doesn't make sense on its
11710 // own. It must have been described already by the diff of
11711 // the enclosing struct or union if 'd' is from an anonymous
11712 // data member, or from a typedef change if 'd' is from a
11713 // typedef change which underlying type is an anonymous
11714 // struct/union.
11716 // Don't show decl-only-ness changes either.
11718 // Sometime, we can encounter artifacts of bogus DWARF that
11719 // yield a diff node for a decl-only class (and empty class
11720 // with the is_declaration flag set) that carries a non-zero
11721 // size! And of course at some point that non-zero size
11722 // changes. We need to be able to detect that.
11724 {
11725 diff_context_sptr ctxt = d->context();
11726 const corpus_diff *corpus_diff_node = ctxt->get_corpus_diff().get();
11727 ABG_ASSERT(corpus_diff_node);
11728
11729 if (diff *iface_diff = get_current_topmost_iface_diff())
11730 {
11731 type_or_decl_base_sptr iface = iface_diff->first_subject();
11732 // So, this diff node that is reachable from a global
11733 // function or variable carries a leaf change. Let's add
11734 // it to the set of of leaf diffs of corpus_diff_node.
11735 const_cast<corpus_diff*>(corpus_diff_node)->
11736 get_leaf_diffs().insert_diff_node(d, iface);
11737 }
11738 }
11739 }
11740}; // end struct leaf_diff_node_marker_visitor
11741
11742/// Walks the diff nodes associated to the current corpus diff and
11743/// mark those that carry local changes. They are said to be leaf
11744/// diff nodes.
11745///
11746/// The marked nodes are available from the
11747/// corpus_diff::get_leaf_diffs() function.
11748void
11750{
11751 if (!has_changes())
11752 return;
11753
11754 if (!context()->show_leaf_changes_only())
11755 return;
11756
11757 leaf_diff_node_marker_visitor v;
11758 context()->forget_visited_diffs();
11759 bool s = context()->visiting_a_node_twice_is_forbidden();
11760 context()->forbid_visiting_a_node_twice(true);
11761 if (context()->show_impacted_interfaces())
11762 context()->forbid_visiting_a_node_twice_per_interface(true);
11763 traverse(v);
11764 context()->forbid_visiting_a_node_twice(s);
11765 context()->forbid_visiting_a_node_twice_per_interface(false);
11766}
11767
11768/// Get the set of maps that contain leaf nodes. A leaf node being a
11769/// node with a local change.
11770///
11771/// @return the set of maps that contain leaf nodes. A leaf node
11772/// being a node with a local change.
11773diff_maps&
11775{return priv_->leaf_diffs_;}
11776
11777/// Get the set of maps that contain leaf nodes. A leaf node being a
11778/// node with a local change.
11779///
11780/// @return the set of maps that contain leaf nodes. A leaf node
11781/// being a node with a local change.
11782const diff_maps&
11784{return priv_->leaf_diffs_;}
11785
11786/// Report the diff in a serialized form.
11787///
11788/// @param out the stream to serialize the diff to.
11789///
11790/// @param indent the prefix to use for the indentation of this
11791/// serialization.
11792void
11793corpus_diff::report(ostream& out, const string& indent) const
11794{
11795 context()->get_reporter()->report(*this, out, indent);
11796}
11797
11798/// Traverse the diff sub-tree under the current instance corpus_diff.
11799///
11800/// @param v the visitor to invoke on each diff node of the sub-tree.
11801///
11802/// @return true if the traversing has to keep going on, false otherwise.
11803bool
11805{
11807
11808 v.visit_begin(this);
11809
11810 if (!v.visit(this, true))
11811 {
11812 v.visit_end(this);
11813 return false;
11814 }
11815
11816 for (function_decl_diff_sptrs_type::const_iterator i =
11817 changed_functions_sorted().begin();
11818 i != changed_functions_sorted().end();
11819 ++i)
11820 {
11821 if (diff_sptr d = *i)
11822 {
11823 const diff_context_sptr &ctxt = context();
11824 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11825 ctxt->forget_visited_diffs();
11826
11828
11829 if (!d->traverse(v))
11830 {
11831 v.visit_end(this);
11833 return false;
11834 }
11835 }
11836 }
11837
11838 for (var_diff_sptrs_type::const_iterator i =
11839 changed_variables_sorted().begin();
11840 i != changed_variables_sorted().end();
11841 ++i)
11842 {
11843 if (diff_sptr d = *i)
11844 {
11845 const diff_context_sptr &ctxt = context();
11846 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11847 ctxt->forget_visited_diffs();
11848
11850
11851 if (!d->traverse(v))
11852 {
11853 v.visit_end(this);
11855 return false;
11856 }
11857 }
11858 }
11859
11861
11862 // Traverse the changed unreachable type diffs. These diffs are on
11863 // types that are not reachable from global functions or variables.
11864 for (vector<diff_sptr>::const_iterator i =
11867 ++i)
11868 {
11869 if (diff_sptr d = *i)
11870 {
11871 const diff_context_sptr &ctxt = context();
11872 if (ctxt->visiting_a_node_twice_is_forbidden_per_interface())
11873 ctxt->forget_visited_diffs();
11874
11875 if (!d->traverse(v))
11876 {
11877 v.visit_end(this);
11878 return false;
11879 }
11880 }
11881 }
11882
11883 v.visit_end(this);
11884 return true;
11885}
11886
11887/// Compute the diff between two instances of @ref corpus.
11888///
11889/// Note that the two corpora must have been created in the same @ref
11890/// environment, otherwise, this function aborts.
11891///
11892/// @param f the first @ref corpus to consider for the diff.
11893///
11894/// @param s the second @ref corpus to consider for the diff.
11895///
11896/// @param ctxt the diff context to use.
11897///
11898/// @return the resulting diff between the two @ref corpus.
11900compute_diff(const corpus_sptr f,
11901 const corpus_sptr s,
11902 diff_context_sptr ctxt)
11903{
11904 typedef corpus::functions::const_iterator fns_it_type;
11905 typedef corpus::variables::const_iterator vars_it_type;
11906 typedef elf_symbols::const_iterator symbols_it_type;
11907 typedef diff_utils::deep_ptr_eq_functor eq_type;
11908 typedef vector<type_base_wptr>::const_iterator type_base_wptr_it_type;
11909
11910 ABG_ASSERT(f && s);
11911
11912 if (!ctxt)
11913 ctxt.reset(new diff_context);
11914
11915 corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
11916
11917 ctxt->set_corpus_diff(r);
11918
11919 if(ctxt->show_soname_change())
11920 r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
11921 else
11922 r->priv_->sonames_equal_ = true;
11923
11924 r->priv_->architectures_equal_ =
11925 f->get_architecture_name() == s->get_architecture_name();
11926
11927 // Compute the diff of publicly defined and exported functions
11928 diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
11929 f->get_functions().end(),
11930 s->get_functions().begin(),
11931 s->get_functions().end(),
11932 r->priv_->fns_edit_script_);
11933
11934 // Compute the diff of publicly defined and exported variables.
11935 diff_utils::compute_diff<vars_it_type, eq_type>
11936 (f->get_variables().begin(), f->get_variables().end(),
11937 s->get_variables().begin(), s->get_variables().end(),
11938 r->priv_->vars_edit_script_);
11939
11940 // Compute the diff of function elf symbols not referenced by debug
11941 // info.
11942 diff_utils::compute_diff<symbols_it_type, eq_type>
11943 (f->get_unreferenced_function_symbols().begin(),
11944 f->get_unreferenced_function_symbols().end(),
11945 s->get_unreferenced_function_symbols().begin(),
11946 s->get_unreferenced_function_symbols().end(),
11947 r->priv_->unrefed_fn_syms_edit_script_);
11948
11949 // Compute the diff of variable elf symbols not referenced by debug
11950 // info.
11951 diff_utils::compute_diff<symbols_it_type, eq_type>
11952 (f->get_unreferenced_variable_symbols().begin(),
11953 f->get_unreferenced_variable_symbols().end(),
11954 s->get_unreferenced_variable_symbols().begin(),
11955 s->get_unreferenced_variable_symbols().end(),
11956 r->priv_->unrefed_var_syms_edit_script_);
11957
11958 if (ctxt->show_unreachable_types())
11959 // Compute the diff of types not reachable from public functions
11960 // or global variables that are exported.
11961 diff_utils::compute_diff<type_base_wptr_it_type, eq_type>
11962 (f->get_types_not_reachable_from_public_interfaces().begin(),
11963 f->get_types_not_reachable_from_public_interfaces().end(),
11964 s->get_types_not_reachable_from_public_interfaces().begin(),
11965 s->get_types_not_reachable_from_public_interfaces().end(),
11966 r->priv_->unreachable_types_edit_script_);
11967
11968 r->priv_->ensure_lookup_tables_populated();
11969
11970 return r;
11971}
11972
11973// </corpus stuff>
11974
11975/// Compute the diff between two instances of @ref corpus_group.
11976///
11977/// Note that the two corpus_diff must have been created in the same
11978/// @ref environment, otherwise, this function aborts.
11979///
11980/// @param f the first @ref corpus_group to consider for the diff.
11981///
11982/// @param s the second @ref corpus_group to consider for the diff.
11983///
11984/// @param ctxt the diff context to use.
11985///
11986/// @return the resulting diff between the two @ref corpus_group.
11988compute_diff(const corpus_group_sptr& f,
11989 const corpus_group_sptr& s,
11990 diff_context_sptr ctxt)
11991{
11992
11993 corpus_sptr c1 = f;
11994 corpus_sptr c2 = s;
11995
11996 return compute_diff(c1, c2, ctxt);
11997}
11998
11999// <corpus_group stuff>
12000
12001// </corpus_group stuff>
12002// <diff_node_visitor stuff>
12003
12004/// The private data of the @diff_node_visitor type.
12005struct diff_node_visitor::priv
12006{
12007 diff* topmost_interface_diff;
12008 visiting_kind kind;
12009
12010 priv()
12011 : topmost_interface_diff(),
12012 kind()
12013 {}
12014
12015 priv(visiting_kind k)
12016 : topmost_interface_diff(),
12017 kind(k)
12018 {}
12019}; // end struct diff_node_visitor
12020
12021/// Default constructor of the @ref diff_node_visitor type.
12023 : priv_(new priv)
12024{}
12025
12026diff_node_visitor::~diff_node_visitor() = default;
12027
12028/// Constructor of the @ref diff_node_visitor type.
12029///
12030/// @param k how the visiting has to be performed.
12032 : priv_(new priv(k))
12033{}
12034
12035/// Getter for the visiting policy of the traversing code while
12036/// invoking this visitor.
12037///
12038/// @return the visiting policy used by the traversing code when
12039/// invoking this visitor.
12042{return priv_->kind;}
12043
12044/// Setter for the visiting policy of the traversing code while
12045/// invoking this visitor.
12046///
12047/// @param v a bit map representing the new visiting policy used by
12048/// the traversing code when invoking this visitor.
12049void
12051{priv_->kind = v;}
12052
12053/// Setter for the visiting policy of the traversing code while
12054/// invoking this visitor. This one makes a logical or between the
12055/// current policy and the bitmap given in argument and assigns the
12056/// current policy to the result.
12057///
12058/// @param v a bitmap representing the visiting policy to or with
12059/// the current policy.
12060void
12062{priv_->kind = priv_->kind | v;}
12063
12064/// Setter of the diff current topmost interface which is impacted by
12065/// the current diff node being visited.
12066///
12067/// @param d the current topmost interface diff impacted.
12068void
12070{priv_->topmost_interface_diff = d;}
12071
12072/// Getter of the diff current topmost interface which is impacted by
12073/// the current diff node being visited.
12074///
12075/// @return the current topmost interface diff impacted.
12076diff*
12078{return priv_->topmost_interface_diff;}
12079
12080/// This is called by the traversing code on a @ref diff node just
12081/// before visiting it. That is, before visiting it and its children
12082/// node.
12083///
12084/// @param d the diff node to visit.
12085void
12087{}
12088
12089/// This is called by the traversing code on a @ref diff node just
12090/// after visiting it. That is after visiting it and its children
12091/// nodes.
12092///
12093/// @param d the diff node that got visited.
12094void
12096{}
12097
12098/// This is called by the traversing code on a @ref corpus_diff node
12099/// just before visiting it. That is, before visiting it and its
12100/// children node.
12101///
12102/// @param p the corpus_diff node to visit.
12103///
12104void
12106{}
12107
12108/// This is called by the traversing code on a @ref corpus_diff node
12109/// just after visiting it. That is after visiting it and its children
12110/// nodes.
12111///
12112/// @param d the diff node that got visited.
12113void
12115{}
12116
12117/// Default visitor implementation
12118///
12119/// @return true
12120bool
12122{return true;}
12123
12124/// Default visitor implementation.
12125///
12126/// @return true
12127bool
12129{
12130 diff* d = dif;
12131 visit(d, pre);
12132
12133 return true;
12134}
12135
12136/// Default visitor implementation.
12137///
12138/// @return true
12139bool
12141{
12142 diff* d = dif;
12143 visit(d, pre);
12144
12145 return true;
12146}
12147
12148/// Default visitor implementation.
12149///
12150/// @return true
12151bool
12153{
12154 diff* d = dif;
12155 visit(d, pre);
12156
12157 return true;
12158}
12159
12160/// Default visitor implementation.
12161///
12162/// @return true
12163bool
12165{
12166 diff* d = dif;
12167 visit(d, pre);
12168
12169 return true;
12170}
12171
12172/// Default visitor implementation.
12173///
12174/// @return true
12175bool
12177{
12178 diff* d = dif;
12179 visit(d, pre);
12180
12181 return true;
12182}
12183
12184/// Default visitor implementation.
12185///
12186/// @return true
12187bool
12189{
12190 diff* d = dif;
12191 visit(d, pre);
12192
12193 return true;
12194}
12195
12196/// Default visitor implementation.
12197///
12198/// @return true
12199bool
12201{
12202 diff* d = dif;
12203 visit(d, pre);
12204
12205 return true;
12206}
12207
12208/// Default visitor implementation.
12209///
12210/// @return true
12211bool
12213{
12214 diff* d = dif;
12215 visit(d, pre);
12216
12217 return true;
12218}
12219
12220/// Default visitor implementation.
12221///
12222/// @return true
12223bool
12225{
12226 diff* d = dif;
12227 visit(d, pre);
12228
12229 return true;
12230}
12231
12232/// Default visitor implementation.
12233///
12234/// @return true
12235bool
12237{
12238 diff* d = dif;
12239 visit(d, pre);
12240
12241 return true;
12242}
12243
12244/// Default visitor implementation.
12245///
12246/// @return true
12247bool
12249{
12250 diff* d = dif;
12251 visit(d, pre);
12252
12253 return true;
12254}
12255
12256/// Default visitor implementation.
12257///
12258/// @return true
12259bool
12261{
12262 diff* d = dif;
12263 visit(d, pre);
12264
12265 return true;
12266}
12267
12268/// Default visitor implementation.
12269///
12270/// @return true
12271bool
12273{
12274 diff* d = dif;
12275 visit(d, pre);
12276
12277 return true;
12278}
12279
12280/// Default visitor implementation.
12281///
12282/// @return true
12283bool
12285{return true;}
12286
12287// </diff_node_visitor stuff>
12288
12289// <redundant diff node marking>
12290
12291// </redundant diff node marking>
12292
12293// <diff tree category propagation>
12294
12295/// A visitor to propagate the category of a node up to its parent
12296/// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY or the
12297/// SUPPRESSED_CATEGORY because those are propagated using other
12298/// specific visitors.
12299struct category_propagation_visitor : public diff_node_visitor
12300{
12301 virtual void
12302 visit_end(diff* d)
12303 {
12304 // Has this diff node 'd' been already visited ?
12305 bool already_visited = d->context()->diff_has_been_visited(d);
12306
12307 // The canonical diff node of the class of equivalence of the diff
12308 // node 'd'.
12309 diff* canonical = d->get_canonical_diff();
12310
12311 // If this class of equivalence of diff node is being visited for
12312 // the first time, then update its canonical node's category too.
12313 bool update_canonical = !already_visited && canonical;
12314
12315 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12316 i != d->children_nodes().end();
12317 ++i)
12318 {
12319 // If we are visiting the class of equivalence of 'd' for the
12320 // first time, then let's look at the children of 'd' and
12321 // propagate their categories to 'd'.
12322 //
12323 // If the class of equivalence of 'd' has already been
12324 // visited, then let's look at the canonical diff nodes of the
12325 // children of 'd' and propagate their categories to 'd'.
12326 diff* diff = already_visited
12327 ? (*i)->get_canonical_diff()
12328 : *i;
12329
12331
12333 // Do not propagate redundant and suppressed categories. Those
12334 // are propagated in a specific pass elsewhere.
12335 c &= ~(REDUNDANT_CATEGORY
12341 // Also, if a (class) type has got a harmful name change, do not
12342 // propagate harmless name changes coming from its sub-types
12343 // (i.e, data members) to the class itself.
12346
12347 d->add_to_category(c);
12348 if (!already_visited && canonical)
12349 if (update_canonical)
12350 canonical->add_to_category(c);
12351 }
12352 }
12353};// end struct category_propagation_visitor
12354
12355/// Visit all the nodes of a given sub-tree. For each node that has a
12356/// particular category set, propagate that category set up to its
12357/// parent nodes.
12358///
12359/// @param diff_tree the diff sub-tree to walk for categorization
12360/// purpose;
12361void
12363{
12364 category_propagation_visitor v;
12365 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12366 diff_tree->context()->forbid_visiting_a_node_twice(true);
12367 diff_tree->context()->forget_visited_diffs();
12368 diff_tree->traverse(v);
12369 diff_tree->context()->forbid_visiting_a_node_twice(s);
12370}
12371
12372/// Visit all the nodes of a given sub-tree. For each node that has a
12373/// particular category set, propagate that category set up to its
12374/// parent nodes.
12375///
12376/// @param diff_tree the diff sub-tree to walk for categorization
12377/// purpose;
12378void
12380{propagate_categories(diff_tree.get());}
12381
12382/// Visit all the nodes of a given corpus tree. For each node that
12383/// has a particular category set, propagate that category set up to
12384/// its parent nodes.
12385///
12386/// @param diff_tree the corpus_diff tree to walk for categorization
12387/// purpose;
12388void
12390{
12391 category_propagation_visitor v;
12392 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12393 diff_tree->context()->forbid_visiting_a_node_twice(false);
12394 diff_tree->traverse(v);
12395 diff_tree->context()->forbid_visiting_a_node_twice(s);
12396}
12397
12398/// Visit all the nodes of a given corpus tree. For each node that
12399/// has a particular category set, propagate that category set up to
12400/// its parent nodes.
12401///
12402/// @param diff_tree the corpus_diff tree to walk for categorization
12403/// purpose;
12404void
12406{propagate_categories(diff_tree.get());}
12407
12408/// A tree node visitor that knows how to categorizes a given diff
12409/// node in the SUPPRESSED_CATEGORY category and how to propagate that
12410/// categorization.
12411struct suppression_categorization_visitor : public diff_node_visitor
12412{
12413
12414 /// Before visiting the children of the diff node, check if the node
12415 /// is suppressed by a suppression specification. If it is, mark
12416 /// the node as belonging to the SUPPRESSED_CATEGORY category.
12417 ///
12418 /// @param p the diff node to visit.
12419 virtual void
12420 visit_begin(diff* d)
12421 {
12422 bool is_private_type = false;
12423 if (d->is_suppressed(is_private_type))
12424 {
12425 diff_category c = is_private_type
12429
12430 // If a node was suppressed, all the other nodes of its class
12431 // of equivalence are suppressed too.
12432 diff *canonical_diff = d->get_canonical_diff();
12433 if (canonical_diff != d)
12434 canonical_diff->add_to_category(c);
12435 }
12437 {
12438 // This diff node is specifically allowed by a
12439 // negated_suppression, then mark it as being in the
12440 // HAS_ALLOWED_CHANGE_CATEGORY.
12443 diff *canonical_diff = d->get_canonical_diff();
12444 canonical_diff->add_to_category(c);
12445
12446 // Note that some complementary code later down below does
12447 // categorize the descendants and parents nodes of this node
12448 // as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
12449 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
12450 }
12451
12452 // If a parent node has been allowed by a negated suppression
12453 // specification, then categorize the current node as
12454 // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
12455 if (d->parent_node())
12456 {
12461 else
12462 {
12463 c = d->parent_node()->get_category();
12467 }
12468 }
12469
12470 }
12471
12472 /// After visiting the children nodes of a given diff node,
12473 /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
12474 /// diff node, if need be.
12475 ///
12476 /// That is, if all children nodes carry a suppressed change the
12477 /// current node should be marked as suppressed as well.
12478 ///
12479 /// In practice, this might be too strong of a condition. If the
12480 /// current node carries a local change (i.e, a change not carried
12481 /// by any of its children node) and if that change is not
12482 /// suppressed, then the current node should *NOT* be suppressed.
12483 ///
12484 /// But right now, the IR doesn't let us know about local vs
12485 /// children-carried changes. So we cannot be that precise yet.
12486 virtual void
12487 visit_end(diff* d)
12488 {
12489 bool has_non_suppressed_child = false;
12490 bool has_non_empty_child = false;
12491 bool has_suppressed_child = false;
12492 bool has_non_private_child = false;
12493 bool has_private_child = false;
12494 bool has_descendant_with_allowed_change = false;
12495
12496 if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
12497 // (or the PRIVATE_TYPE_CATEGORY for the same matter)
12498 // category from its children is a node which:
12499 //
12500 // 1/ hasn't been suppressed already
12501 //
12502 // 2/ and has no local change (unless it's a pointer,
12503 // reference or qualified diff node).
12504 //
12505 // Note that qualified type and typedef diff nodes are a bit
12506 // special. The local changes of the underlying type are
12507 // considered local for the qualified/typedef type, just like
12508 // for pointer/reference types. But then the qualified or
12509 // typedef type itself can have local changes of its own, and
12510 // those changes are of the kind LOCAL_NON_TYPE_CHANGE_KIND.
12511 // So a qualified type which have local changes that are
12512 // *NOT* of LOCAL_NON_TYPE_CHANGE_KIND (or that has no local
12513 // changes at all) and which is in the PRIVATE_TYPE_CATEGORY
12514 // or SUPPRESSED_CATEGORY can see these categories be
12515 // propagated.
12516 //
12517 // Note that all pointer/reference diff node changes are
12518 // potentially considered local, i.e, local changes of the
12519 // pointed-to-type are considered local to the pointer itself.
12520 //
12521 // Similarly, changes local to the type of function parameters,
12522 // variables (and data members) and classes (that are not of
12523 // LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
12524 // suppressed can propagate their SUPPRESSED_CATEGORY-ness to
12525 // those kinds of diff node.
12526 !(d->get_category() & SUPPRESSED_CATEGORY)
12527 && (!d->has_local_changes()
12528 || is_pointer_diff(d)
12529 || is_reference_diff(d)
12531 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12532 || (is_typedef_diff(d)
12533 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12535 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12536 || (is_fn_parm_diff(d)
12537 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12539 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12540 || (is_var_diff(d)
12541 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
12542 || (is_class_diff(d)
12543 && (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
12544 {
12545 // Note that we handle private diff nodes differently from
12546 // generally suppressed diff nodes. E.g, it's not because a
12547 // type is private (and suppressed because of that; i.e, in
12548 // the category PRIVATE_TYPE_CATEGORY) that a typedef to that
12549 // type should also be private and so suppressed. Private
12550 // diff nodes thus have different propagation rules than
12551 // generally suppressed rules.
12552 for (vector<diff*>::const_iterator i = d->children_nodes().begin();
12553 i != d->children_nodes().end();
12554 ++i)
12555 {
12556 diff* child = *i;
12557 if (child->has_changes())
12558 {
12559 has_non_empty_child = true;
12560 if (child->get_class_of_equiv_category() & SUPPRESSED_CATEGORY)
12561 has_suppressed_child = true;
12562 else if (child->get_class_of_equiv_category()
12564 // Propagation of the PRIVATE_TYPE_CATEGORY is going
12565 // to be handled later below.
12566 ;
12567 else
12568 has_non_suppressed_child = true;
12569
12570 if (child->get_class_of_equiv_category()
12572 has_private_child = true;
12573 else if (child->get_class_of_equiv_category()
12575 // Propagation of the SUPPRESSED_CATEGORY has been
12576 // handled above already.
12577 ;
12578 else
12579 has_non_private_child = true;
12580 }
12581 }
12582
12583 if (has_non_empty_child
12584 && has_suppressed_child
12585 && !has_non_suppressed_child)
12586 {
12588 // If a node was suppressed, all the other nodes of its class
12589 // of equivalence are suppressed too.
12590 diff *canonical_diff = d->get_canonical_diff();
12591 if (canonical_diff != d)
12592 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12593 }
12594
12595 // Note that the private-ness of a an underlying type won't be
12596 // propagated to its parent typedef, by virtue of the big "if"
12597 // clause at the beginning of this function. So we don't have
12598 // to handle that case here. So the idiom of defining
12599 // typedefs of private (opaque) types will be respected;
12600 // meaning that changes to opaque underlying type will be
12601 // flagged as private and the typedef will be flagged private
12602 // as well, unless the typedef itself has local non-type
12603 // changes. In the later case, changes to the typedef will be
12604 // emitted because the typedef won't inherit the privateness
12605 // of its underlying type. So in practise, the typedef
12606 // remains public for the purpose of change reporting.
12607 if (has_non_empty_child
12608 && has_private_child
12609 && !has_non_private_child)
12610 {
12611 d->add_to_category(PRIVATE_TYPE_CATEGORY);
12612 // If a node was suppressed, all the other nodes of its class
12613 // of equivalence are suppressed too.
12614 diff *canonical_diff = d->get_canonical_diff();
12615 if (canonical_diff != d)
12616 canonical_diff->add_to_category(PRIVATE_TYPE_CATEGORY);
12617 }
12618
12619 // If the underlying type of a typedef is private and carries
12620 // changes (that are implicitely suppressed because it's
12621 // private) then the typedef must be suppressed too, so that
12622 // those changes to the underlying type are not seen.
12623 if (is_typedef_diff(d)
12624 && !d->has_local_changes()
12625 && has_private_child
12626 && has_non_empty_child)
12627 {
12628 d->add_to_category(SUPPRESSED_CATEGORY|PRIVATE_TYPE_CATEGORY);
12629 // If a node was suppressed, all the other nodes of its class
12630 // of equivalence are suppressed too.
12631 diff *canonical_diff = d->get_canonical_diff();
12632 if (canonical_diff != d)
12633 canonical_diff->add_to_category
12635 }
12636
12637 if (const function_decl_diff *fn_diff = is_function_decl_diff(d))
12638 if (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND))
12639 {
12640 // d is a function diff that carries a local *type*
12641 // change (that means it's a change to the function
12642 // type). Let's see if the child function type diff
12643 // node is suppressed. That would mean that we are
12644 // instructed to show details of a diff that is deemed
12645 // suppressed; this means the suppression conflicts with
12646 // a local type change. In that case, let's follow what
12647 // the user asked and suppress the function altogether,
12648 if (function_type_diff_sptr fn_type_diff = fn_diff->type_diff())
12649 if (fn_type_diff->is_suppressed())
12650 {
12651 d->add_to_category(SUPPRESSED_CATEGORY);
12652 // If a node was suppressed, all the other nodes
12653 // of its class of equivalence are suppressed too.
12654 diff *canonical_diff = d->get_canonical_diff();
12655 if (canonical_diff != d)
12656 canonical_diff->add_to_category(SUPPRESSED_CATEGORY);
12657 }
12658 }
12659 }
12660
12661 // If any descendant node was selected by a negated suppression
12662 // specification then categorize the current one as
12663 // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
12664 for (auto child_node : d->children_nodes())
12665 {
12666 diff *canonical_diff = child_node->get_canonical_diff();
12667 diff_category c = canonical_diff->get_category();
12670 has_descendant_with_allowed_change = true;
12671 }
12672 if (has_descendant_with_allowed_change)
12673 {
12675 d->add_to_category(c);
12676 d->get_canonical_diff()->add_to_category(c);
12677 }
12678 }
12679}; //end struct suppression_categorization_visitor
12680
12681/// Walk a given diff-sub tree and appply the suppressions carried by
12682/// the context. If the suppression applies to a given node than
12683/// categorize the node into the SUPPRESSED_CATEGORY category and
12684/// propagate that categorization.
12685///
12686/// @param diff_tree the diff-sub tree to apply the suppressions to.
12687void
12689{
12690 if (diff_tree && !diff_tree->context()->suppressions().empty())
12691 {
12692 // Apply suppressions to functions and variables that have
12693 // changed sub-types.
12694 suppression_categorization_visitor v;
12695 diff_tree->context()->forget_visited_diffs();
12696 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12697 diff_tree->context()->forbid_visiting_a_node_twice(true);
12698 diff_tree->traverse(v);
12699 diff_tree->context()->forbid_visiting_a_node_twice(s);
12700 }
12701}
12702
12703/// Walk a given diff-sub tree and appply the suppressions carried by
12704/// the context. If the suppression applies to a given node than
12705/// categorize the node into the SUPPRESSED_CATEGORY category and
12706/// propagate that categorization.
12707///
12708/// @param diff_tree the diff-sub tree to apply the suppressions to.
12709void
12711{apply_suppressions(diff_tree.get());}
12712
12713/// Walk a @ref corpus_diff tree and appply the suppressions carried
12714/// by the context. If the suppression applies to a given node then
12715/// categorize the node into the SUPPRESSED_CATEGORY category and
12716/// propagate that categorization.
12717///
12718/// @param diff_tree the diff tree to apply the suppressions to.
12719void
12721{
12722 if (diff_tree && !diff_tree->context()->suppressions().empty())
12723 {
12724 // First, visit the children trees of changed constructs:
12725 // changed functions, variables, as well as sub-types of these,
12726 // and apply suppression specifications to these ...
12727 suppression_categorization_visitor v;
12728 diff_tree->context()->forget_visited_diffs();
12729 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12730 diff_tree->context()->forbid_visiting_a_node_twice(true);
12731 const_cast<corpus_diff*>(diff_tree)->traverse(v);
12732 diff_tree->context()->forbid_visiting_a_node_twice(s);
12733
12734 // ... then also visit the set of added and removed functions,
12735 // variables, symbols, and types not reachable from global
12736 // functions and variables.
12737 diff_tree->priv_->
12738 apply_supprs_to_added_removed_fns_vars_unreachable_types();
12739 }
12740}
12741
12742/// Walk a diff tree and appply the suppressions carried by the
12743/// context. If the suppression applies to a given node than
12744/// categorize the node into the SUPPRESSED_CATEGORY category and
12745/// propagate that categorization.
12746///
12747/// @param diff_tree the diff tree to apply the suppressions to.
12748void
12750{apply_suppressions(diff_tree.get());}
12751
12752// </diff tree category propagation>
12753
12754// <diff tree printing stuff>
12755
12756/// A visitor to print (to an output stream) a pretty representation
12757/// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
12758struct diff_node_printer : public diff_node_visitor
12759{
12760 ostream& out_;
12761 unsigned level_;
12762
12763 /// Emit a certain number of spaces to the output stream associated
12764 /// to this diff_node_printer.
12765 ///
12766 /// @param level half of the numver of spaces to emit.
12767 void
12768 do_indent(unsigned level)
12769 {
12770 for (unsigned i = 0; i < level; ++i)
12771 out_ << " ";
12772 }
12773
12774 diff_node_printer(ostream& out)
12775 : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
12776 out_(out),
12777 level_(0)
12778 {}
12779
12780 virtual void
12781 visit_begin(diff*)
12782 {
12783 ++level_;
12784 }
12785
12786 virtual void
12787 visit_end(diff*)
12788 {
12789 --level_;
12790 }
12791
12792 virtual void
12793 visit_begin(corpus_diff*)
12794 {
12795 ++level_;
12796 }
12797
12798 virtual void
12799 visit_end(corpus_diff*)
12800 {
12801 --level_;
12802 }
12803
12804 virtual bool
12805 visit(diff* d, bool pre)
12806 {
12807 if (!pre)
12808 // We are post-visiting the diff node D. Which means, we have
12809 // printed a pretty representation for it already. So do
12810 // nothing now.
12811 return true;
12812
12813 do_indent(level_);
12814 out_ << d->get_pretty_representation();
12815 out_ << "\n";
12816 do_indent(level_);
12817 out_ << "{\n";
12818 do_indent(level_ + 1);
12819 out_ << "category: "<< d->get_category() << "\n";
12820 do_indent(level_ + 1);
12821 out_ << "@: " << std::hex << d << std::dec << "\n";
12822 do_indent(level_ + 1);
12823 out_ << "@-canonical: " << std::hex
12824 << d->get_canonical_diff()
12825 << std::dec << "\n";
12826 do_indent(level_);
12827 out_ << "}\n";
12828
12829 return true;
12830 }
12831
12832 virtual bool
12833 visit(corpus_diff* d, bool pre)
12834 {
12835 if (!pre)
12836 // We are post-visiting the diff node D. Which means, we have
12837 // printed a pretty representation for it already. So do
12838 // nothing now.
12839 return true;
12840
12841 // indent
12842 for (unsigned i = 0; i < level_; ++i)
12843 out_ << ' ';
12844 out_ << d->get_pretty_representation();
12845 out_ << '\n';
12846 return true;
12847 }
12848}; // end struct diff_printer_visitor
12849
12850// </ diff tree printing stuff>
12851
12852/// Emit a textual representation of a @ref diff sub-tree to an
12853/// output stream.
12854///
12855/// @param diff_tree the sub-tree to emit the textual representation
12856/// for.
12857///
12858/// @param out the output stream to emit the textual representation
12859/// for @p diff_tree to.
12860void
12861print_diff_tree(diff* diff_tree, ostream& out)
12862{
12863 diff_node_printer p(out);
12864 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12865 diff_tree->context()->forbid_visiting_a_node_twice(false);
12866 diff_tree->traverse(p);
12867 diff_tree->context()->forbid_visiting_a_node_twice(s);
12868}
12869
12870/// Emit a textual representation of a @ref corpus_diff tree to an
12871/// output stream.
12872///
12873/// @param diff_tree the @ref corpus_diff tree to emit the textual
12874/// representation for.
12875///
12876/// @param out the output stream to emit the textual representation
12877/// for @p diff_tree to.
12878void
12879print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
12880{
12881 diff_node_printer p(out);
12882 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
12883 diff_tree->context()->forbid_visiting_a_node_twice(false);
12884 diff_tree->traverse(p);
12885 diff_tree->context()->forbid_visiting_a_node_twice(s);
12886}
12887
12888/// Emit a textual representation of a @ref diff sub-tree to an
12889/// output stream.
12890///
12891/// @param diff_tree the sub-tree to emit the textual representation
12892/// for.
12893///
12894/// @param out the output stream to emit the textual representation
12895/// for @p diff_tree to.
12896void
12898 std::ostream& o)
12899{print_diff_tree(diff_tree.get(), o);}
12900
12901/// Emit a textual representation of a @ref corpus_diff tree to an
12902/// output stream.
12903///
12904/// @param diff_tree the @ref corpus_diff tree to emit the textual
12905/// representation for.
12906///
12907/// @param out the output stream to emit the textual representation
12908/// for @p diff_tree to.
12909void
12911 std::ostream& o)
12912{print_diff_tree(diff_tree.get(), o);}
12913
12914// <redundancy_marking_visitor>
12915
12916/// A tree visitor to categorize nodes with respect to the
12917/// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
12918/// present on several spots of the tree) and mark such nodes
12919/// appropriatly. This visitor also takes care of propagating the
12920/// REDUNDANT_CATEGORY of a given node to its parent nodes as
12921/// appropriate.
12922struct redundancy_marking_visitor : public diff_node_visitor
12923{
12924 bool skip_children_nodes_;
12925
12926 redundancy_marking_visitor()
12927 : skip_children_nodes_()
12928 {}
12929
12930 virtual void
12931 visit_begin(diff* d)
12932 {
12933 if (d->to_be_reported())
12934 {
12935 // A diff node that carries a change and that has been already
12936 // traversed elsewhere is considered redundant. So let's mark
12937 // it as such and let's not traverse it; that is, let's not
12938 // visit its children.
12939 if ((d->context()->diff_has_been_visited(d)
12940 || d->get_canonical_diff()->is_traversing())
12941 && d->has_changes())
12942 {
12943 // But if two diff nodes are redundant sibbling that carry
12944 // changes of base types, do not mark them as being
12945 // redundant. This is to avoid marking nodes as redundant
12946 // in this case:
12947 //
12948 // int foo(int a, int b);
12949 // compared with:
12950 // float foo(float a, float b); (in C).
12951 //
12952 // In this case, we want to report all the occurences of
12953 // the int->float change because logically, they are at
12954 // the same level in the diff tree.
12955
12956 bool redundant_with_sibling_node = false;
12957 const diff* p = d->parent_node();
12958
12959 // If this is a child node of a fn_parm_diff, look through
12960 // the fn_parm_diff node to get the function diff node.
12961 if (p && dynamic_cast<const fn_parm_diff*>(p))
12962 p = p->parent_node();
12963
12964 if (p)
12965 for (vector<diff*>::const_iterator s =
12966 p->children_nodes().begin();
12967 s != p->children_nodes().end();
12968 ++s)
12969 {
12970 if (*s == d)
12971 continue;
12972 diff* sib = *s;
12973 // If this is a fn_parm_diff, look through the
12974 // fn_parm_diff node to get at the real type node.
12975 if (fn_parm_diff* f = dynamic_cast<fn_parm_diff*>(*s))
12976 sib = f->type_diff().get();
12977 if (sib == d)
12978 continue;
12979 if (sib->get_canonical_diff() == d->get_canonical_diff()
12980 // Sibbling diff nodes that carry base type
12981 // changes ar to be marked as redundant.
12982 && (is_base_diff(sib) || is_distinct_diff(sib)))
12983 {
12984 redundant_with_sibling_node = true;
12985 break;
12986 }
12987 }
12988 if (!redundant_with_sibling_node
12989 // Changes to basic types should never be considered
12990 // redundant. For instance, if a member of integer
12991 // type is changed into a char type in both a struct A
12992 // and a struct B, we want to see both changes.
12994 // The same goes for distinct type changes
12996 // Functions with similar *local* changes are never marked
12997 // redundant because otherwise one could miss important
12998 // similar local changes that are applied to different
12999 // functions.
13001 // Changes involving variadic parameters of functions
13002 // should never be marked redundant because we want to see
13003 // them all.
13006 // If the canonical diff itself has been filtered out,
13007 // then this one is not marked redundant, unless the
13008 // canonical diff was already redundant.
13009 && (!d->get_canonical_diff()->is_filtered_out()
13010 || (d->get_canonical_diff()->get_category()
13012 // If the *same* diff node (not one that is merely
13013 // equivalent to this one) has already been visited
13014 // the do not mark it as beind redundant. It's only
13015 // the other nodes that are equivalent to this one
13016 // that must be marked redundant.
13017 && d->context()->diff_has_been_visited(d) != d
13018 // If the diff node is a function parameter and is not
13019 // a reference/pointer (to a non basic or a non
13020 // distinct type diff) then do not mark it as
13021 // redundant.
13022 //
13023 // Children nodes of base class diff nodes are never
13024 // redundant either, we want to see them all.
13028 {
13030 // As we said in preamble, as this node is marked as
13031 // being redundant, let's not visit its children.
13032 // This is not an optimization; it's needed for
13033 // correctness. In the case of a diff node involving
13034 // a class type that refers to himself, visiting the
13035 // children nodes might cause them to be wrongly
13036 // marked as redundant.
13039 skip_children_nodes_ = true;
13040 }
13041 }
13042 }
13043 else
13044 {
13045 // If the node is not to be reported, do not look at it children.
13047 skip_children_nodes_ = true;
13048 }
13049 }
13050
13051 virtual void
13052 visit_begin(corpus_diff*)
13053 {
13054 }
13055
13056 virtual void
13057 visit_end(diff* d)
13058 {
13059 if (skip_children_nodes_)
13060 // When visiting this node, we decided to skip its children
13061 // node. Now that we are done visiting the node, lets stop
13062 // avoiding the children nodes visiting for the other tree
13063 // nodes.
13064 {
13066 skip_children_nodes_ = false;
13067 }
13068 else
13069 {
13070 // Propagate the redundancy categorization of the children nodes
13071 // to this node. But if this node has local changes, then it
13072 // doesn't inherit redundancy from its children nodes.
13073 if (!(d->get_category() & REDUNDANT_CATEGORY)
13074 && (!d->has_local_changes_to_be_reported()
13075 // By default, pointer, reference and qualified types
13076 // consider that a local changes to their underlying
13077 // type is always a local change for themselves.
13078 //
13079 // This is as if those types don't have local changes
13080 // in the same sense as other types. So we always
13081 // propagate redundancy to them, regardless of if they
13082 // have local changes or not.
13083 //
13084 // We also propagate redundancy to typedef types if
13085 // these /only/ carry changes to their underlying
13086 // type.
13087 //
13088 // Note that changes to the underlying type of a
13089 // typedef is considered local of
13090 // LOCAL_TYPE_CHANGE_KIND kind. The other changes to the
13091 // typedef itself are considered local of
13092 // LOCAL_NON_TYPE_CHANGE_KIND kind.
13093 || is_pointer_diff(d)
13095 // A typedef with local non-type changes should not
13096 // see redundancy propagation from its underlying
13097 // type, otherwise, the non-type change might be
13098 // "suppressed" away.
13099 || (is_typedef_diff(d)
13100 && (!(d->has_local_changes()
13102 // A (member) variable with non-type local changes
13103 // should not see redundacy propagation from its type.
13104 // If redundant local-type changes are carried by its
13105 // type however, then that redundancy is propagated to
13106 // the variable. This is key to keep the redundancy
13107 // consistency in the system; otherwise, a type change
13108 // would be rightfully considered redundant at some
13109 // places but not at others.
13110 || (is_var_diff(d)
13111 && (!(d->has_local_changes()
13113 // A function parameter with non-type local changes
13114 // should not see redundancy propagation either. But
13115 // a function parameter with local type changes can
13116 // definitely be redundant.
13117 || (is_fn_parm_diff(d)
13118 && (!(d->has_local_changes()
13120 ))
13121 {
13122 bool has_non_redundant_child = false;
13123 bool has_non_empty_child = false;
13124 for (vector<diff*>::const_iterator i =
13125 d->children_nodes().begin();
13126 i != d->children_nodes().end();
13127 ++i)
13128 {
13129 if ((*i)->has_changes())
13130 {
13131 has_non_empty_child = true;
13132 // Let's see if the current child node '*i' is
13133 // "non-redundant".
13134 //
13135 // A non-redundant node would be a node that
13136 // carries a change to be reported and has not
13137 // been marked as being redundant.
13138 if ((*i)->to_be_reported()
13139 && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
13140 has_non_redundant_child = true;
13141 }
13142 if (has_non_redundant_child)
13143 break;
13144 }
13145
13146 // A diff node for which at least a child node carries a
13147 // change, and for which all the children are redundant is
13148 // deemed redundant too, unless it has local changes.
13149 if (has_non_empty_child
13150 && !has_non_redundant_child)
13151 d->add_to_category(REDUNDANT_CATEGORY);
13152 }
13153 }
13154 }
13155
13156 virtual void
13157 visit_end(corpus_diff*)
13158 {
13159 }
13160
13161 virtual bool
13162 visit(diff*, bool)
13163 {return true;}
13164
13165 virtual bool
13166 visit(corpus_diff*, bool)
13167 {
13168 return true;
13169 }
13170};// end struct redundancy_marking_visitor
13171
13172/// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13173/// category out of the nodes.
13174struct redundancy_clearing_visitor : public diff_node_visitor
13175{
13176 bool
13177 visit(corpus_diff*, bool)
13178 {return true;}
13179
13180 bool
13181 visit(diff* d, bool)
13182 {
13183 // clear the REDUNDANT_CATEGORY out of the current node.
13184 diff_category c = d->get_category();
13185 c &= ~REDUNDANT_CATEGORY;
13186 d->set_category(c);
13187 return true;
13188 }
13189}; // end struct redundancy_clearing_visitor
13190
13191/// Walk a given @ref diff sub-tree to categorize each of the nodes
13192/// with respect to the REDUNDANT_CATEGORY.
13193///
13194/// @param diff_tree the @ref diff sub-tree to walk.
13195void
13197{
13198 if (diff_tree->context()->show_redundant_changes())
13199 return;
13200 redundancy_marking_visitor v;
13201 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13202 diff_tree->context()->forbid_visiting_a_node_twice(false);
13203 diff_tree->traverse(v);
13204 diff_tree->context()->forbid_visiting_a_node_twice(s);
13205}
13206
13207/// Walk a given @ref diff sub-tree to categorize each of the nodes
13208/// with respect to the REDUNDANT_CATEGORY.
13209///
13210/// @param diff_tree the @ref diff sub-tree to walk.
13211void
13213{categorize_redundancy(diff_tree.get());}
13214
13215/// Walk a given @ref corpus_diff tree to categorize each of the nodes
13216/// with respect to the REDUNDANT_CATEGORY.
13217///
13218/// @param diff_tree the @ref corpus_diff tree to walk.
13219void
13221{
13222 redundancy_marking_visitor v;
13223 diff_tree->context()->forget_visited_diffs();
13224 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13225 diff_tree->context()->forbid_visiting_a_node_twice(false);
13226 diff_tree->traverse(v);
13227 diff_tree->context()->forbid_visiting_a_node_twice(s);
13228}
13229
13230/// Walk a given @ref corpus_diff tree to categorize each of the nodes
13231/// with respect to the REDUNDANT_CATEGORY.
13232///
13233/// @param diff_tree the @ref corpus_diff tree to walk.
13234void
13236{categorize_redundancy(diff_tree.get());}
13237
13238// </redundancy_marking_visitor>
13239
13240/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13241/// out of the category of the nodes.
13242///
13243/// @param diff_tree the @ref diff sub-tree to walk.
13244void
13246{
13247 redundancy_clearing_visitor v;
13248 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13249 diff_tree->context()->forbid_visiting_a_node_twice(false);
13250 diff_tree->traverse(v);
13251 diff_tree->context()->forbid_visiting_a_node_twice(s);
13252 diff_tree->context()->forget_visited_diffs();
13253}
13254
13255/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13256/// out of the category of the nodes.
13257///
13258/// @param diff_tree the @ref diff sub-tree to walk.
13259void
13261{clear_redundancy_categorization(diff_tree.get());}
13262
13263/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13264/// out of the category of the nodes.
13265///
13266/// @param diff_tree the @ref corpus_diff tree to walk.
13267void
13269{
13270 redundancy_clearing_visitor v;
13271 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13272 diff_tree->context()->forbid_visiting_a_node_twice(false);
13273 diff_tree->traverse(v);
13274 diff_tree->context()->forbid_visiting_a_node_twice(s);
13275 diff_tree->context()->forget_visited_diffs();
13276}
13277
13278/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13279/// out of the category of the nodes.
13280///
13281/// @param diff_tree the @ref corpus_diff tree to walk.
13282void
13284{clear_redundancy_categorization(diff_tree.get());}
13285
13286/// Apply the @ref diff tree filters that have been associated to the
13287/// context of the a given @ref corpus_diff tree. As a result, the
13288/// nodes of the @diff tree are going to be categorized into one of
13289/// several of the categories of @ref diff_category.
13290///
13291/// @param diff_tree the @ref corpus_diff instance which @ref diff are
13292/// to be categorized.
13293void
13295{
13296 diff_tree->context()->maybe_apply_filters(diff_tree);
13297 propagate_categories(diff_tree);
13298}
13299
13300/// Test if a diff node represents the difference between a variadic
13301/// parameter type and something else.
13302///
13303/// @param d the diff node to consider.
13304///
13305/// @return true iff @p d is a diff node that represents the
13306/// difference between a variadic parameter type and something else.
13307bool
13309{
13310 if (!d)
13311 return false;
13312
13313 type_base_sptr t = is_type(d->first_subject());
13314 if (t && t->get_environment().is_variadic_parameter_type(t))
13315 return true;
13316
13317 t = is_type(d->second_subject());
13318 if (t && t->get_environment().is_variadic_parameter_type(t))
13319 return true;
13320
13321 return false;
13322}
13323
13324/// Test if a diff node represents the difference between a variadic
13325/// parameter type and something else.
13326///
13327/// @param d the diff node to consider.
13328///
13329/// @return true iff @p d is a diff node that represents the
13330/// difference between a variadic parameter type and something else.
13331bool
13333{return is_diff_of_variadic_parameter_type(d.get());}
13334
13335/// Test if a diff node represents the difference between a variadic
13336/// parameter and something else.
13337///
13338/// @param d the diff node to consider.
13339///
13340/// @return true iff @p d is a diff node that represents the
13341/// difference between a variadic parameter and something else.
13342bool
13344{
13346 dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
13347 return (diff && is_diff_of_variadic_parameter_type(diff->type_diff()));
13348}
13349
13350/// Test if a diff node represents the difference between a variadic
13351/// parameter and something else.
13352///
13353/// @param d the diff node to consider.
13354///
13355/// @return true iff @p d is a diff node that represents the
13356/// difference between a variadic parameter and something else.
13357bool
13359{return is_diff_of_variadic_parameter(d.get());}
13360
13361/// Test if a diff node represents a diff between two basic types.
13362///
13363/// @param d the diff node to consider.
13364///
13365/// @return true iff @p d is a diff between two basic types.
13366const type_decl_diff*
13368{return dynamic_cast<const type_decl_diff*>(d);}
13369
13370/// Test if a diff node represents a diff between two basic types, or
13371/// between pointers, references or qualified type to basic types.
13372///
13373/// @param diff the diff node to consider.
13374///
13375/// @param allow_indirect_type if true, then this function looks into
13376/// pointer, reference or qualified diff types to see if they "point
13377/// to" basic types.
13378///
13379/// @return true iff @p d is a diff between two basic types.
13380const type_decl_diff*
13381is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
13382{
13383 if (allow_indirect_type)
13386}
13387
13388/// If a diff node is about changes between two typedef types, get the
13389/// diff node about changes between the underlying types.
13390///
13391/// Note that this function walks the tree of underlying diff nodes
13392/// returns the first diff node about types that are not typedefs.
13393///
13394/// @param dif the dif node to consider.
13395///
13396/// @return the underlying diff node of @p dif, or just return @p dif
13397/// if it's not a typedef diff node.
13398const diff*
13400{
13401 const typedef_diff *d = 0;
13402 while ((d = is_typedef_diff(dif)))
13403 dif = d->underlying_type_diff().get();
13404 return dif;
13405}
13406
13407/// If a diff node is about changes between two pointer types, get the
13408/// diff node about changes between the underlying (pointed-to) types.
13409///
13410/// Note that this function walks the tree of underlying diff nodes
13411/// returns the first diff node about types that are not pointers.
13412///
13413/// @param dif the dif node to consider.
13414///
13415/// @return the underlying diff node of @p dif, or just return @p dif
13416/// if it's not a pointer diff node.
13417const diff*
13419{
13420 const pointer_diff *d = 0;
13421 while ((d = is_pointer_diff(dif)))
13422 dif = d->underlying_type_diff().get();
13423 return dif;
13424}
13425
13426/// If a diff node is about changes between two reference types, get
13427/// the diff node about changes between the underlying (pointed-to)
13428/// types.
13429///
13430/// Note that this function walks the tree of underlying diff nodes
13431/// returns the first diff node about types that are not references.
13432///
13433/// @param dif the dif node to consider.
13434///
13435/// @return the underlying diff node of @p dif, or just return @p dif
13436/// if it's not a reference diff node.
13437const diff*
13439{
13440 const reference_diff *d = 0;
13441 while ((d = is_reference_diff(dif)))
13442 dif = d->underlying_type_diff().get();
13443 return dif;
13444}
13445
13446/// If a diff node is about changes between two qualified types, get
13447/// the diff node about changes between the underlying (non-qualified)
13448/// types.
13449///
13450/// Note that this function walks the tree of underlying diff nodes
13451/// returns the first diff node about types that are not qualified.
13452///
13453/// @param dif the dif node to consider.
13454///
13455/// @return the underlying diff node of @p dif, or just return @p dif
13456/// if it's not a qualified diff node.
13457const diff*
13459{
13460 const qualified_type_diff *d = 0;
13461 while ((d = is_qualified_type_diff(dif)))
13462 dif = d->underlying_type_diff().get();
13463 return dif;
13464}
13465
13466/// If a diff node is about changes between two function parameters
13467/// get the diff node about changes between the types of the parameters.
13468///
13469/// @param dif the dif node to consider.
13470///
13471/// @return the diff of the types of the parameters.
13472const diff*
13474{
13475 const fn_parm_diff *d = 0;
13476 while ((d = is_fn_parm_diff(dif)))
13477 dif = d->type_diff().get();
13478 return dif;
13479}
13480
13481/// If a diff node is about changes between two pointer, reference or
13482/// qualified types, get the diff node about changes between the
13483/// underlying types.
13484///
13485/// Note that this function walks the tree of underlying diff nodes
13486/// returns the first diff node about types that are not pointer,
13487/// reference or qualified.
13488///
13489/// @param dif the dif node to consider.
13490///
13491/// @return the underlying diff node of @p dif, or just return @p dif
13492/// if it's not a pointer, reference or qualified diff node.
13493const diff*
13495{
13496 while (true)
13497 {
13498 if (const pointer_diff *d = is_pointer_diff(dif))
13499 dif = peel_pointer_diff(d);
13500 else if (const reference_diff *d = is_reference_diff(dif))
13501 dif = peel_reference_diff(d);
13502 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13503 dif = peel_qualified_diff(d);
13504 else
13505 break;
13506 }
13507 return dif;
13508}
13509
13510/// If a diff node is about changes between two typedefs or qualified
13511/// types, get the diff node about changes between the underlying
13512/// types.
13513///
13514/// Note that this function walks the tree of underlying diff nodes
13515/// returns the first diff node about types that are not typedef or
13516/// qualified types.
13517///
13518/// @param dif the dif node to consider.
13519///
13520/// @return the underlying diff node of @p dif, or just return @p dif
13521/// if it's not typedef or qualified diff node.
13522const diff*
13524{
13525 while (true)
13526 {
13527 if (const typedef_diff *d = is_typedef_diff(dif))
13528 dif = peel_typedef_diff(d);
13529 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13530 dif = peel_qualified_diff(d);
13531 else
13532 break;
13533 }
13534 return dif;
13535}
13536
13537/// If a diff node is about changes between two typedefs or qualified
13538/// types, get the diff node about changes between the underlying
13539/// types.
13540///
13541/// Note that this function walks the tree of underlying diff nodes
13542/// returns the first diff node about types that are neither typedef,
13543/// qualified type nor parameters.
13544///
13545/// @param dif the dif node to consider.
13546///
13547/// @return the diff node about changes between the underlying types.
13548const diff*
13550{
13551 while (true)
13552 {
13553 if (const typedef_diff *d = is_typedef_diff(dif))
13554 dif = peel_typedef_diff(d);
13555 else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
13556 dif = peel_qualified_diff(d);
13557 else if (const fn_parm_diff *d = is_fn_parm_diff(dif))
13558 dif = peel_fn_parm_diff(d);
13559 else
13560 break;
13561 }
13562 return dif;
13563}
13564
13565/// Test if a diff node represents a diff between two class or union
13566/// types.
13567///
13568/// @param d the diff node to consider.
13569///
13570/// @return iff @p is a diff between two class or union types then
13571/// return the instance of @ref class_or_union_diff that @p derives
13572/// from. Otherwise, return nil.
13575{return dynamic_cast<const class_or_union_diff*>(d);}
13576
13577/// Test if a given diff node carries *only* a local type change.
13578///
13579/// @param d the diff node to consider.
13580///
13581/// @return true iff @p has a change and that change is a local type
13582/// change.
13583static bool
13584has_local_type_change_only(const diff *d)
13585{
13586 if (enum change_kind k = d->has_local_changes())
13587 if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
13588 && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
13589 return true;
13590
13591 return false;
13592}
13593
13594/// Test if a diff node is a decl diff that only carries a basic type
13595/// change on its type diff sub-node.
13596///
13597///Note that that pointers/references/qualified types diffs to basic
13598/// type diffs are considered as having basic type change only.
13599///
13600/// @param d the diff node to consider.
13601///
13602/// @return true iff @p d is a decl diff that only carries a basic
13603/// type change on its type diff sub-node.
13604bool
13606{
13608
13609 if (is_diff_of_basic_type(d, true) && d->has_changes())
13610 return true;
13611 else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
13612 return (has_local_type_change_only(v)
13613 && is_diff_of_basic_type(v->type_diff().get(), true));
13614 else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
13615 return (has_local_type_change_only(p)
13616 && is_diff_of_basic_type(p->type_diff().get(), true));
13617 else if (const function_decl_diff* f =
13618 dynamic_cast<const function_decl_diff*>(d))
13619 return (has_local_type_change_only(f)
13620 && f->type_diff()
13621 && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
13622 true));
13623 return false;
13624}
13625}// end namespace comparison
13626} // 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:1695
#define ABG_ASSERT_NOT_REACHED
A macro that expands to aborting the program when executed.
The abstraction of a diff between two arrays.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of array_diff.
const diff_sptr & element_type_diff() const
Getter for the diff between the two types of array elements.
array_diff(const array_type_def_sptr first, const array_type_def_sptr second, diff_sptr element_type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for array_diff.
const array_type_def_sptr second_array() const
Getter for the second array of the diff.
const array_type_def_sptr first_array() const
Getter for the first array of the diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
An abstraction of a diff between two instances of class_decl::base_spec.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of base_diff.
void set_underlying_class_diff(class_diff_sptr d)
Setter for the diff object for the diff of the underlyng base classes.
class_decl::base_spec_sptr second_base() const
Getter for the second base spec of the diff object.
base_diff(class_decl::base_spec_sptr first, class_decl::base_spec_sptr second, class_diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
const class_diff_sptr get_underlying_class_diff() const
Getter for the diff object for the diff of the underlying base classes.
class_decl::base_spec_sptr first_base() const
Getter for the first base spec of the diff object.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Generates a report for the current instance of base_diff.
This type abstracts changes for a class_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_diff.
class_decl_sptr first_class_decl() const
const base_diff_sptrs_type & changed_bases()
Getter for the changed base classes of the diff.
const vector< class_decl::base_spec_sptr > & moved_bases() const
Getter for the vector of bases that "moved". That is, the vector of base types which position changed...
const string_base_sptr_map & inserted_bases() const
Getter for the inserted base classes of the diff.
const string_base_sptr_map & deleted_bases() const
Getter for the deleted base classes of the diff.
virtual enum change_kind has_local_changes() const
const edit_script & base_changes() const
virtual const string & get_pretty_representation() const
class_diff(class_decl_sptr first_scope, class_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor of class_diff.
friend class_diff_sptr compute_diff(const class_decl_sptr first, const class_decl_sptr second, diff_context_sptr ctxt)
Compute the set of changes between two instances of class_decl.
class_decl_sptr second_class_decl() const
Getter of the second class involved in the diff.
virtual void report(ostream &, const string &indent="") const
Produce a basic report about the changes between two class_decl.
This is the base class of class_diff and union_diff.
virtual bool has_changes() const
Test if the current diff node carries a change.
const edit_script & member_fn_tmpls_changes() const
size_t count_filtered_subtype_changed_data_members(bool local_only=false) const
Count the number of /filtered/ data members with a sub-type change.
const class_or_union_diff::priv_ptr & get_priv() const
Getter of the private data of the class_or_union_diff type.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of class_or_un...
const edit_script & member_class_tmpls_changes() const
void allocate_priv_data()
Allocate the memory for the priv_ pimpl data member of the class_or_union_diff class.
class_or_union_diff(class_or_union_sptr first_scope, class_or_union_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the class_or_union_diff class.
const unsigned_var_diff_sptr_map & changed_data_members() const
Getter of the map of data members that got replaced by another data member. The key of the map is the...
const edit_script & member_types_changes() const
const string_member_function_sptr_map & deleted_member_fns() const
class_or_union_sptr first_class_or_union() const
const var_diff_sptrs_type & sorted_subtype_changed_data_members() const
Getter of the sorted vector of data members with a (sub-)type change.
bool lookup_tables_empty(void) const
Tests if the lookup tables are empty.
const string_decl_base_sptr_map & data_members_replaced_by_adms() const
Get the map of data members that got replaced by anonymous data members.
void clear_lookup_tables(void)
Clear the lookup tables useful for reporting.
const string_decl_base_sptr_map & deleted_data_members() const
Getter for the data members that got deleted.
virtual ~class_or_union_diff()
Destructor of class_or_union_diff.
const string_decl_base_sptr_map & inserted_data_members() const
Getter for the data members that got inserted.
void ensure_lookup_tables_populated(void) const
If the lookup tables are not yet built, walk the differences and fill them.
const string_member_function_sptr_map & inserted_member_fns() const
const function_decl_diff_sptrs_type & changed_member_fns() const
Getter for the virtual members functions that have had a change in a sub-type, without having a chang...
const edit_script & data_members_changes() const
const changed_var_sptrs_type & ordered_data_members_replaced_by_adms() const
Get an ordered vector of of data members that got replaced by anonymous data members.
virtual enum change_kind has_local_changes() const
size_t count_filtered_changed_data_members(bool local_only=false) const
Count the number of /filtered/ data members that got replaced by another data member.
const edit_script & member_fns_changes() const
class_or_union_sptr second_class_or_union() const
const var_diff_sptrs_type & sorted_changed_data_members() const
Getter of the sorted vector of data members that got replaced by another data member.
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current class_or_union_diff node in a textual format.
This is a document class that aims to capture statistics about the changes carried by a corpus_diff t...
size_t num_changed_unreachable_types_filtered_out() const
Getter of the number of changed types that are unreachable from public interfaces and that have been ...
size_t num_func_removed() const
Getter for the number of functions removed.
size_t num_removed_unreachable_types_filtered_out() const
Getter of the number of removed types that are not reachable from public interfaces and that have bee...
size_t num_vars_changed() const
Getter for the number of variables that have a change in one of their sub-types.
size_t net_num_leaf_var_changes() const
Getter for the net number of leaf variable change diff nodes.
size_t num_vars_added() const
Getter for the number of variables added.
size_t num_removed_unreachable_types() const
Getter of the number of removed types that are unreachable from the public interface of the ABI corpu...
size_t num_changed_vars_filtered_out() const
Getter for the number of variables that have a change in one of their sub-types, and that have been f...
size_t num_changed_func_filtered_out() const
Getter for the number of functions that have a change in one of their sub-types, and that have been f...
size_t num_removed_vars_filtered_out() const
Getter for the number removed variables that have been filtered out.
size_t net_num_func_changed() const
Getter for the number of functions that have a change in their sub-types, minus the number of these f...
size_t net_num_vars_removed() const
Getter for the net number of removed variables.
size_t net_num_added_unreachable_types() const
Getter of the number of added types that are unreachable from public interfaces and that are *NOT* fi...
size_t num_removed_var_syms_filtered_out() const
Getter for the number of removed variable symbols, not referenced by any debug info,...
size_t net_num_added_func_syms() const
Getter of the net number of added function symbols that are not referenced by any debug info.
size_t num_added_var_syms_filtered_out() const
Getter for the number of added variable symbols, not referenced by any debug info,...
size_t num_added_unreachable_types() const
Getter of the number of added types that are unreachable from the public interface of the ABI corpus.
size_t net_num_removed_func_syms() const
Getter of the net number of removed function symbols that are not referenced by any debug info.
size_t num_var_syms_added() const
Getter for the number of variable symbols (not referenced by any debug info) that got added.
size_t num_leaf_var_changes() const
Getter for the number of leaf variable change diff nodes.
size_t net_num_removed_var_syms() const
Getter of the net number of removed variable symbols that are not referenced by any debug info.
size_t net_num_func_removed() const
Getter for the net number of function removed.
size_t net_num_func_added() const
Getter for the net number of added functions.
size_t net_num_removed_unreachable_types() const
Getter of the number of removed types that are not reachable from public interfaces and that have *NO...
size_t net_num_leaf_changes() const
Getter of the net number of leaf change diff nodes.
size_t num_removed_func_syms_filtered_out() const
Getter for the number of removed function symbols, not referenced by debug info, that have been filte...
size_t num_added_unreachable_types_filtered_out() const
Getter of the number of added types that are unreachable from public interfaces and that are filtered...
size_t num_added_func_filtered_out() const
Getter for the number of added function that have been filtered out.
size_t num_func_syms_added() const
Getter for the number of function symbols (not referenced by any debug info) that got added.
size_t net_num_leaf_type_changes() const
Getter for the net number of leaf type change diff nodes.
size_t num_func_added() const
Getter for the number of functions added.
size_t net_num_added_var_syms() const
Getter of the net number of added variable symbols that are not referenced by any debug info.
size_t num_leaf_type_changes() const
Getter for the number of leaf type change diff nodes.
size_t num_leaf_var_changes_filtered_out() const
Getter for the number of leaf variable changes diff nodes that have been filtered out.
size_t num_added_vars_filtered_out() const
Getter for the number of added variables that have been filtered out.
size_t num_func_with_virtual_offset_changes() const
Getter for the number of functions that carry virtual member offset changes.
size_t num_func_changed() const
Getter for the number of functions that have a change in one of their sub-types.
size_t num_removed_func_filtered_out() const
Getter for the number of removed functions that have been filtered out.
size_t net_num_vars_added() const
Getter for the net number of added variables.
size_t num_leaf_changes() const
Getter of the number of leaf type change diff nodes.
size_t num_leaf_func_changes_filtered_out() const
Getter for the number of leaf function change diff nodes that were filtered out.
size_t num_added_func_syms_filtered_out() const
Getter for the number of added function symbols, not referenced by any debug info,...
size_t num_leaf_type_changes_filtered_out() const
Getter for the number of filtered out leaf type change diff nodes.
size_t num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from the public interface of the ABI corpu...
size_t net_num_leaf_func_changes() const
Getter for the net number of leaf function change diff nodes.
size_t num_leaf_func_changes() const
Getter for the number of leaf function change diff nodes.
size_t net_num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from public interfaces and that have *NOT*...
size_t num_func_syms_removed() const
Getter for the number of function symbols (not referenced by any debug info) that got removed.
size_t num_leaf_changes_filtered_out() const
Getter of the number of leaf type change diff nodes that have been filtered out.
size_t num_vars_removed() const
Getter for the number of variables removed.
size_t num_var_syms_removed() const
Getter for the number of variable symbols (not referenced by any debug info) that got removed.
size_t net_num_vars_changed() const
Getter for the number of variables that have a change in their sub-types, minus the number of these v...
An abstraction of a diff between between two abi corpus.
bool has_incompatible_changes() const
Test if the current instance of corpus_diff carries changes that we are sure are incompatible....
bool has_changes() const
Return true iff the current corpus_diff node carries a change.
void finish_diff_type()
Finish building the current instance of corpus_diff.
virtual void chain_into_hierarchy()
Populate the vector of children node of the corpus_diff type.
const string_var_ptr_map & deleted_variables() const
Getter for the variables that got deleted from the first subject of the diff.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Getter of a sorted vector of changed types that are not reachable from global functions/variables.
bool soname_changed() const
Test if the soname of the underlying corpus has changed.
friend corpus_diff_sptr compute_diff(const corpus_sptr f, const corpus_sptr s, diff_context_sptr ctxt)
Compute the diff between two instances of corpus.
const vector< type_base_sptr > & deleted_unreachable_types_sorted() const
Getter of a sorted vector of deleted types that are not reachable from global functions/variables.
edit_script & function_changes() const
edit_script & variable_changes() const
const vector< diff * > & children_nodes() const
const string_diff_sptr_map & changed_unreachable_types() const
Getter for a map of changed types that are not reachable from global functions/variables.
const var_diff_sptrs_type & changed_variables_sorted()
Getter for the sorted vector of variables which signature didn't change but which do have some indire...
const string_elf_symbol_map & deleted_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got deleted.
const string_elf_symbol_map & deleted_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got deleted.
corpus_diff(corpus_sptr first, corpus_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for corpus_diff.
bool do_log() const
Test if logging was requested.
const string_elf_symbol_map & added_unrefed_function_symbols() const
Getter for function symbols not referenced by any debug info and that got added.
bool has_net_subtype_changes() const
Test if the current instance of corpus_diff carries subtype changes whose reports are not suppressed ...
const string_var_ptr_map & added_variables() const
Getter for the added variables of the diff.
diff_maps & get_leaf_diffs()
Get the set of maps that contain leaf nodes. A leaf node being a node with a local change.
const diff_context_sptr context() const
Getter of the diff context of this diff.
bool has_net_changes() const
Test if the current instance of corpus_diff carries changes whose reports are not suppressed by any s...
virtual bool traverse(diff_node_visitor &v)
Traverse the diff sub-tree under the current instance corpus_diff.
const diff_stats & apply_filters_and_suppressions_before_reporting()
Apply the different filters that are registered to be applied to the diff tree; that includes the cat...
const string_var_diff_sptr_map & changed_variables()
Getter for the non-sorted map of variables which signature didn't change but which do have some indir...
const string_function_ptr_map & added_functions()
Getter for the added functions of the diff.
void mark_leaf_diff_nodes()
Walks the diff nodes associated to the current corpus diff and mark those that carry local changes....
const string_type_base_sptr_map & deleted_unreachable_types() const
Getter for a map of deleted types that are not reachable from global functions/variables.
const vector< type_base_sptr > & added_unreachable_types_sorted() const
Getter of a sorted vector of added types that are not reachable from global functions/variables.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
const string_elf_symbol_map & added_unrefed_variable_symbols() const
Getter for variable symbols not referenced by any debug info and that got added.
const function_decl_diff_sptrs_type & changed_functions_sorted()
Getter for a sorted vector of functions which signature didn't change, but which do have some indirec...
const string & get_pretty_representation() const
const string_function_ptr_map & deleted_functions() const
Getter for the deleted functions of the diff.
void append_child_node(diff_sptr)
Append a new child node to the vector of children nodes for the current instance of corpus_diff node.
friend void apply_suppressions(const corpus_diff *diff_tree)
Walk a corpus_diff tree and appply the suppressions carried by the context. If the suppression applie...
const string_type_base_sptr_map & added_unreachable_types() const
Getter for a map of added types that are not reachable from global functions/variables.
const string_function_decl_diff_sptr_map & changed_functions()
Getter for the functions which signature didn't change, but which do have some indirect changes in th...
bool architecture_changed() const
Test if the architecture of the underlying corpus has changed.
The base class of diff between decls.
decl_diff_base(decl_base_sptr first_subject, decl_base_sptr second_subject, diff_context_sptr ctxt)
Constructor of decl_diff_base.
The default, initial, reporter of the libabigail comparison engine.
Definition: abg-reporter.h:159
The context of the diff. This type holds various bits of information that is going to be used through...
void add_suppressions(const suppr::suppressions_type &supprs)
Add new suppression specifications that specify which diff node reports should be dropped on the floo...
diff_category get_allowed_category() const
Getter for the bitmap that represents the set of categories that the user wants to see reported.
void forget_visited_diffs()
Unmark all the diff nodes that were marked as being traversed.
corpus_sptr get_first_corpus() const
Getter for the first corpus of the corpus diff of the current context.
bool show_architecture_change() const
Getter for the property that says if the comparison module should show the architecture changes in it...
bool show_offsets_sizes_in_bits() const
Get the flag that indicates if diff reports using this context should show sizes and offsets in bits,...
void forbid_visiting_a_node_twice(bool f)
This sets a flag that, if it's true, then during the traversing of a diff nodes tree each node is vis...
void initialize_canonical_diff(const diff_sptr diff)
Set the canonical diff node property of a given diff node appropriately.
bool show_redundant_changes() const
A getter for the flag that says if we should report about functions or variables diff nodes that have...
void forbid_visiting_a_node_twice_per_interface(bool)
This function sets a flag os that if forbid_visiting_a_node_twice() returns true, then each time the ...
void keep_diff_alive(diff_sptr &)
Add a diff node to the set of diff nodes that are kept alive for the life time of the current instanc...
diff * diff_has_been_visited(const diff *) const
Test if a diff node has been traversed.
bool visiting_a_node_twice_is_forbidden_per_interface() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
void set_corpus_diff(const corpus_diff_sptr &)
Set the corpus diff relevant to this context.
bool show_leaf_changes_only() const
Get the flag that indicates if the diff using this context should show only leaf changes or not.
bool perform_change_categorization() const
Test if it's requested to perform diff node categorization.
bool show_impacted_interfaces() const
Getter of the flag that indicates if the leaf reporter should display a summary of the interfaces imp...
bool show_soname_change() const
Getter for the property that says if the comparison module should show the soname changes in its repo...
reporter_base_sptr get_reporter() const
Getter of the reporter to be used in this context.
void add_diff_filter(filtering::filter_base_sptr)
Setter for the diff filters to apply to a given diff sub-tree.
bool do_log() const
Test if logging was requested.
const suppr::suppressions_type & direct_suppressions() const
Getter of the direct suppression specification (those that are not negated) comprised in the general ...
void maybe_apply_filters(diff_sptr diff)
Apply the diff filters to a given diff sub-tree.
const suppr::suppressions_type & suppressions() const
Getter for the vector of suppressions that specify which diff node reports should be dropped on the f...
bool show_relative_offset_changes(void)
Get the flag saying if offset changes should be reported in a relative way. That is,...
bool visiting_a_node_twice_is_forbidden() const
Return a flag that, if true, then during the traversing of a diff nodes tree each node is visited at ...
void do_dump_diff_tree(const diff_sptr) const
Emit a textual representation of a diff tree to the error output stream of the current context,...
const suppr::suppressions_type & negated_suppressions() const
Getter of the negated suppression specifications that are comprised in the general vector of suppress...
void add_suppression(const suppr::suppression_sptr suppr)
Add a new suppression specification that specifies which diff node reports should be dropped on the f...
bool show_hex_values() const
Get the flag that indicates if the diff reports using this context should show sizes and offsets in a...
void switch_categories_off(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
bool show_stats_only() const
Test if the comparison module should only show the diff stats.
const filtering::filters & diff_filters() const
Getter for the diff tree nodes filters to apply to diff sub-trees.
bool show_unreachable_types()
Getter for the flag that indicates if changes on types unreachable from global functions and variable...
const corpus_diff_sptr & get_corpus_diff() const
Get the corpus diff for the current context.
void mark_diff_as_visited(const diff *)
Mark a diff node as traversed by a traversing algorithm.
diff_sptr get_canonical_diff_for(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second) const
Getter for the canonical diff node for the diff represented by their two subjects.
void switch_categories_on(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
ostream * default_output_stream()
Getter for the default output stream used by code of the comparison engine. By default the default ou...
bool dump_diff_tree() const
Test if the comparison engine should dump the diff tree for the changed functions and variables it ha...
bool show_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info are to be compared and...
bool show_added_symbols_unreferenced_by_debug_info() const
Getter for the flag that indicates if symbols not referenced by any debug info and that got added are...
corpus_sptr get_second_corpus() const
Getter for the second corpus of the corpus diff of the current context.
void set_allowed_category(diff_category c)
Setter for the bitmap that represents the set of categories that the user wants to see reported.
void set_reporter(reporter_base_sptr &)
Setter of the reporter to be used in this context.
ostream * error_output_stream() const
Getter for the errror output stream used by code of the comparison engine. By default the error outpu...
This type contains maps. Each map associates a type name to a diff of that type. Not all kinds of dif...
const string_diff_ptr_map & get_function_decl_diff_map() const
Getter of the map that contains function decl diffs.
const string_diff_ptr_map & get_var_decl_diff_map() const
Getter of the map that contains var decl diffs.
const string_diff_ptr_map & get_enum_diff_map() const
Getter of the map that contains enum type diffs.
bool insert_diff_node(const diff *d, const type_or_decl_base_sptr &impacted_iface)
Insert a new diff node into the current instance of diff_maps.
diff_maps()
Default constructor of the diff_maps type.
const string_diff_ptr_map & get_union_diff_map() const
Getter of the map that contains union type diffs.
artifact_sptr_set_type * lookup_impacted_interfaces(const diff *d) const
Lookup the interfaces that are impacted by a given leaf diff node.
const string_diff_ptr_map & get_function_type_diff_map() const
Getter of the map that contains function type diffs.
const string_diff_ptr_map & get_typedef_diff_map() const
Getter of the map that contains typedef type diffs.
const string_diff_ptr_map & get_distinct_diff_map() const
Getter of the map that contains distinct diffs.
const string_diff_ptr_map & get_subrange_diff_map() const
Getter of the map that contains subrange type diffs.
const string_diff_ptr_map & get_reference_diff_map() const
Getter of the map that contains reference type diffs.
const string_diff_ptr_map & get_array_diff_map() const
Getter of the map that contains array type diffs.
const string_diff_ptr_map & get_type_decl_diff_map() const
Getter of the map that contains basic type diffs.
const string_diff_ptr_map & get_fn_parm_diff_map() const
Getter of the map that contains function parameter diffs.
const string_diff_ptr_map & get_class_diff_map() const
Getter of the map that contains class type diffs.
The base class for the node visitors. These are the types used to visit each node traversed by the di...
void or_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor....
virtual bool visit(diff *, bool)
Default visitor implementation.
virtual bool visit(distinct_diff *, bool)
Default visitor implementation.
virtual void visit_end(corpus_diff *)
This is called by the traversing code on a corpus_diff node just after visiting it....
void set_current_topmost_iface_diff(diff *)
Setter of the diff current topmost interface which is impacted by the current diff node being visited...
virtual void visit_begin(diff *)
This is called by the traversing code on a diff node just before visiting it. That is,...
visiting_kind get_visiting_kind() const
Getter for the visiting policy of the traversing code while invoking this visitor.
virtual void visit_end(diff *)
This is called by the traversing code on a diff node just after visiting it. That is after visiting i...
diff_node_visitor()
Default constructor of the diff_node_visitor type.
void set_visiting_kind(visiting_kind v)
Setter for the visiting policy of the traversing code while invoking this visitor.
diff * get_current_topmost_iface_diff() const
Getter of the diff current topmost interface which is impacted by the current diff node being visited...
virtual bool traverse(diff_node_visitor &v)
The default traverse function.
The abstraction of a change between two ABI artifacts, a.k.a an artifact change.
void begin_traversing()
Flag a given diff node as being traversed.
void set_category(diff_category c)
Set the category of the current diff node. This category includes the categories inherited from the c...
virtual void finish_diff_type()
Finish the insertion of a diff tree node into the diff graph.
virtual void chain_into_hierarchy()
This constructs the relation between this diff node and its detail diff nodes, in the generic view of...
diff_category remove_from_category(diff_category c)
Remove the current diff tree node from an a existing sef of categories. The categories include those ...
type_or_decl_base_sptr second_subject() const
Getter of the second subject of the diff.
bool is_traversing() const
Tell if a given node is being traversed or not.
type_or_decl_base_sptr first_subject() const
Getter of the first subject of the diff.
bool is_suppressed() const
Test if the current diff node has been suppressed by a user-provided suppression specification.
bool is_filtered_out_without_looking_at_allowed_changes() const
Test if this diff tree node is to be filtered out for reporting purposes, but without considering the...
diff * get_canonical_diff() const
Getter for the canonical diff of the current instance of diff.
bool has_parent_allowed_by_specific_negated_suppression() const
Test if the current diff node has a parent node which is specifically allowed by a negated suppressio...
bool has_local_changes_to_be_reported() const
Test if this diff tree node should be reported when considering the categories that were *NOT* inheri...
const vector< diff * > & children_nodes() const
Getter for the children nodes of the current diff node.
diff_category get_category() const
Getter for the category of the current diff tree node.
bool is_allowed_by_specific_negated_suppression() const
Test if this diff node is allowed (prevented from being suppressed) by at least one negated suppressi...
diff_category remove_from_local_category(diff_category c)
Remove the current diff tree node from the categories resulting from the local changes.
void add_to_local_and_inherited_categories(diff_category c)
Adds the current diff tree node to the categories resulting from the local and inherited changes of t...
bool do_log() const
Test if logging was requested.
diff_category get_local_category() const
Getter for the local category of the current diff tree node.
diff_category add_to_category(diff_category c)
Adds the current diff tree node to an additional set of categories. Note that the categories include ...
const diff_context_sptr context() const
Getter of the context of the current diff.
virtual enum change_kind has_local_changes() const =0
Pure interface to know if the current instance of @diff carries a local change. A local change is a c...
virtual bool traverse(diff_node_visitor &v)
The generic traversing code that walks a given diff sub-tree.
bool currently_reporting() const
Tests if we are currently in the middle of emitting a report for this diff.
virtual bool has_changes() const =0
Pure interface to get the length of the changes encapsulated by this diff. A length of zero means tha...
bool has_descendant_allowed_by_specific_negated_suppression() const
Test if the current diff node has a descendant node which is specifically allowed by a negated suppre...
bool to_be_reported() const
Test if this diff tree node should be reported.
const diff * parent_node() const
Getter for the parent node of the current diff node.
diff_category get_class_of_equiv_category() const
Getter of the category of the class of equivalence of the current diff tree node.
void set_canonical_diff(diff *)
Setter for the canonical diff of the current instance of diff.
bool is_filtered_out_wrt_non_inherited_categories() const
Test if this diff tree node is to be filtered out for reporting purposes, but by considering only the...
diff_category add_to_local_category(diff_category c)
Adds the current diff tree node to the categories resulting from the local changes of the current dif...
void set_local_category(diff_category c)
Set the local category of the current diff node.
virtual const string & get_pretty_representation() const
Get a pretty representation of the current diff node.
void append_child_node(diff_sptr)
Add a new child node to the vector of children nodes for the current diff node.
bool is_filtered_out() const
Test if this diff tree node is to be filtered out for reporting purposes.
void end_traversing()
Flag a given diff node as not being traversed anymore.
bool reported_once() const
Tests if a report has already been emitted for the current diff.
An abstraction of a diff between entities that are of a different kind (disctinct).
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of @distinct_d...
const diff_sptr compatible_child_diff() const
Getter for the child diff of this distinct_diff instance.
distinct_diff(type_or_decl_base_sptr first, type_or_decl_base_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for distinct_diff.
static bool entities_are_of_distinct_kinds(type_or_decl_base_sptr first, type_or_decl_base_sptr second)
Test if the two arguments are of different kind, or that are both NULL.
virtual void report(ostream &out, const string &indent="") const
Emit a report about the current diff instance.
const type_or_decl_base_sptr first() const
Getter for the first subject of the diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const type_or_decl_base_sptr second() const
Getter for the second subject of the diff.
Abstraction of a diff between two enums.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of enum_diff.
enum_diff(const enum_type_decl_sptr, const enum_type_decl_sptr, const diff_sptr, diff_context_sptr ctxt=diff_context_sptr())
Constructor for enum_diff.
diff_sptr underlying_type_diff() const
const string_changed_enumerator_map & changed_enumerators() const
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const enum_type_decl_sptr first_enum() const
const string_enumerator_map & deleted_enumerators() const
const enum_type_decl_sptr second_enum() const
const string_enumerator_map & inserted_enumerators() const
virtual void report(ostream &, const string &indent="") const
Report the differences between the two enums.
A filter that walks the diff nodes tree and tags relevant diff nodes into categories considered to re...
Abstraction of a diff between two function parameters.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children nodes of the diff base type sub-object of this instance of fn_parm_di...
const function_decl::parameter_sptr first_parameter() const
Getter for the first subject of this diff node.
virtual enum change_kind has_local_changes() const
Check if the current diff node carries a local change.
virtual const string & get_pretty_representation() const
Build and return a textual representation of the current instance of fn_parm_diff.
const function_decl::parameter_sptr second_parameter() const
Getter for the second subject of this diff node.
diff_sptr type_diff() const
Getter for the diff representing the changes on the type of the function parameter involved in the cu...
virtual void report(ostream &, const string &indent="") const
Emit a textual report about the current fn_parm_diff instance.
Abstraction of a diff between two function_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_de...
const function_decl_sptr second_function_decl() const
function_decl_diff(const function_decl_sptr first, const function_decl_sptr second, diff_context_sptr ctxt)
Constructor for function_decl_diff.
virtual enum change_kind has_local_changes() const
const function_decl_sptr first_function_decl() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Serialize a report of the changes encapsulated in the current instance of function_decl_diff over to ...
Abstraction of a diff between two function types.
virtual bool has_changes() const
Test if the current diff node carries changes.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of function_ty...
const string_fn_parm_diff_sptr_map & subtype_changed_parms() const
Getter for the map of function parameter changes of the current diff.
const diff_sptr return_type_diff() const
Getter for the diff of the return types of the two function types of the current diff.
const string_parm_map & removed_parms() const
Getter for the map of parameters that got removed.
const string_parm_map & added_parms() const
Getter for the map of parameters that got added.
friend function_type_diff_sptr compute_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of function_type.
const vector< function_decl::parameter_sptr > & sorted_added_parms() const
Getter for the sorted vector of added parameters .
const function_type_sptr first_function_type() const
Getter for the first subject of the diff.
const function_type_sptr second_function_type() const
Getter for the second subject of the diff.
function_type_diff(const function_type_sptr first, const function_type_sptr second, diff_context_sptr ctxt)
Consutrctor of the function_type type.
virtual enum change_kind has_local_changes() const
Test if the current diff node carries local changes.
virtual const string & get_pretty_representation() const
Build and return a copy of a pretty representation of the current instance of function_type_diff.
const vector< function_decl::parameter_sptr > & sorted_deleted_parms() const
Getter for the sorted vector of deleted parameters.
virtual void report(ostream &, const string &indent="") const
Build and emit a textual report about the current function_type_diff instance.
A reporter that only reports leaf changes.
Definition: abg-reporter.h:281
The abstraction of a diff between two pointers.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const pointer_type_def_sptr first_pointer() const
Getter for the first subject of a pointer diff.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of pointer_dif...
const pointer_type_def_sptr second_pointer() const
Getter for the second subject of a pointer diff.
diff_sptr underlying_type_diff() const
Getter for the diff between the pointed-to types of the pointers of this diff.
pointer_diff(pointer_type_def_sptr first, pointer_type_def_sptr second, diff_sptr underlying_type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for a pointer_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
The abstraction of a diff between two ptr_to_mbr_type.
virtual bool has_changes() const
Test whether the current diff node carries any change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of ptr_to_mbr_...
virtual ~ptr_to_mbr_diff()
Destructor of ptr_to_mbr_diff.
ptr_to_mbr_type_sptr first_ptr_to_mbr_type() const
Getter of the first pointer-to-member subject of the current diff node.
const diff_sptr containing_type_diff() const
Getter of the diff node carrying changes to the containing type of first subject of the current diff ...
const diff_sptr member_type_diff() const
Getter of the diff node carrying changes to the member type of first subject of the current diff node...
ptr_to_mbr_type_sptr second_ptr_to_mbr_type() const
Getter of the second pointer-to-member subject of the current diff node.
virtual enum change_kind has_local_changes() const
Test whether the current diff node carries any local change.
virtual const string & get_pretty_representation() const
Get the pretty representation of the current ptr_to_mbr_diff node.
virtual void report(ostream &, const string &indent="") const
Pure interface to report the diff in a serialized form that is legible for the user.
Abstraction of a diff between two qualified types.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of qualified_t...
diff_sptr leaf_underlying_type_diff() const
Getter for the diff between the most underlying non-qualified types of two qualified types.
diff_sptr underlying_type_diff() const
Getter for the diff between the underlying types of the two qualified types.
qualified_type_diff(qualified_type_def_sptr first, qualified_type_def_sptr second, diff_sptr underling, diff_context_sptr ctxt=diff_context_sptr())
Constructor for qualified_type_diff.
const qualified_type_def_sptr second_qualified_type() const
Getter for the second qualified type of the diff.
virtual enum change_kind has_local_changes() const
const qualified_type_def_sptr first_qualified_type() const
Getter for the first qualified type of the diff.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
The abstraction of a diff between two references.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of reference_d...
reference_type_def_sptr first_reference() const
Getter for the first reference of the diff.
reference_type_def_sptr second_reference() const
Getter for the second reference of the diff.
reference_diff(const reference_type_def_sptr first, const reference_type_def_sptr second, diff_sptr underlying, diff_context_sptr ctxt=diff_context_sptr())
Constructor for reference_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const diff_sptr & underlying_type_diff() const
Getter for the diff between the two referred-to types.
virtual void report(ostream &, const string &indent="") const
Report the diff in a serialized form.
An abstractions of the changes between two scopes.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of scope_diff.
const diff_sptrs_type & changed_types() const
const scope_decl_sptr second_scope() const
Getter for the second scope of the diff.
const scope_decl_sptr first_scope() const
Getter for the first scope of the diff.
const decl_base_sptr deleted_member_at(unsigned index) const
Accessor that eases the manipulation of the edit script associated to this instance....
const diff_sptrs_type & changed_decls() const
scope_diff(scope_decl_sptr first_scope, scope_decl_sptr second_scope, diff_context_sptr ctxt=diff_context_sptr())
Constructor for scope_diff.
friend scope_diff_sptr compute_diff(const scope_decl_sptr first, const scope_decl_sptr second, scope_diff_sptr d, diff_context_sptr ctxt)
Compute the diff between two scopes.
const decl_base_sptr inserted_member_at(unsigned i)
Accessor that eases the manipulation of the edit script associated to this instance....
virtual void report(ostream &out, const string &indent="") const
Report the changes of one scope against another.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
const edit_script & member_changes() const
Accessor of the edit script of the members of a scope.
The abstraction of the diff between two subrange types.
virtual bool has_changes() const
Test if the current subrange_diff node carries any change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of subrange_di...
const array_type_def::subrange_sptr second_subrange() const
Getter of the second subrange of the current instance subrange_diff.
subrange_diff(const array_type_def::subrange_sptr &first, const array_type_def::subrange_sptr &second, const diff_sptr &underlying_type_diff, const diff_context_sptr ctxt=diff_context_sptr())
Constructor of the subrange_diff diff node type.
const array_type_def::subrange_sptr first_subrange() const
Getter of the first subrange of the current instance subrange_diff.
const diff_sptr underlying_type_diff() const
Getter of the diff node of the underlying types of the current subrange_diff diff node.
virtual enum change_kind has_local_changes() const
Test if the current subrange_diff node carries any local change.
virtual const string & get_pretty_representation() const
Getter the pretty representation of the subrange_diff diff node.
virtual void report(ostream &, const string &indent="") const
Report about the changes carried by this node.
An abstraction of a diff between two translation units.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const translation_unit_sptr second_translation_unit() const
Getter for the second translation unit of this diff.
translation_unit_diff(translation_unit_sptr first, translation_unit_sptr second, diff_context_sptr ctxt=diff_context_sptr())
Constructor for translation_unit_diff.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
virtual enum change_kind has_local_changes() const
const translation_unit_sptr first_translation_unit() const
Getter for the first translation unit of this diff.
Abstraction of a diff between two basic type declarations.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
const type_decl_sptr first_type_decl() const
Getter for the first subject of the type_decl_diff.
const type_decl_sptr second_type_decl() const
Getter for the second subject of the type_decl_diff.
virtual void report(ostream &out, const string &indent="") const
Ouputs a report of the differences between of the two type_decl involved in the type_decl_diff.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
The base class of diff between types.
Abstraction of a diff between two typedef_decl.
virtual bool has_changes() const
Return true iff the current diff node carries a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of typedef_dif...
const typedef_decl_sptr second_typedef_decl() const
Getter for the second typedef_decl involved in the diff.
const typedef_decl_sptr first_typedef_decl() const
Getter for the firt typedef_decl involved in the diff.
const diff_sptr underlying_type_diff() const
Getter for the diff between the two underlying types of the typedefs.
virtual enum change_kind has_local_changes() const
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Reports the difference between the two subjects of the diff in a serialized form.
union_diff(union_decl_sptr first_union, union_decl_sptr second_union, diff_context_sptr ctxt=diff_context_sptr())
Constructor for the union_diff type.
union_decl_sptr first_union_decl() const
union_decl_sptr second_union_decl() const
virtual ~union_diff()
Destructor of the union_diff node.
virtual const string & get_pretty_representation() const
virtual void report(ostream &, const string &indent="") const
Report the changes carried by the current union_diff node in a textual format.
Abstracts a diff between two instances of var_decl.
virtual bool has_changes() const
Return true iff the diff node has a change.
virtual void chain_into_hierarchy()
Populate the vector of children node of the diff base type sub-object of this instance of var_diff.
var_diff(var_decl_sptr first, var_decl_sptr second, diff_sptr type_diff, diff_context_sptr ctxt=diff_context_sptr())
Constructor for var_diff.
var_decl_sptr first_var() const
Getter for the first var_decl of the diff.
virtual void report(ostream &out, const string &indent="") const
Report the diff in a serialized form.
virtual enum change_kind has_local_changes() const
friend var_diff_sptr compute_diff(const var_decl_sptr first, const var_decl_sptr second, diff_context_sptr ctxt)
Compute the diff between two instances of var_decl.
virtual const string & get_pretty_representation() const
diff_sptr type_diff() const
Getter for the diff of the types of the instances of var_decl.
var_decl_sptr second_var() const
Getter for the second var_decl of the diff.
The abstraction of an edit script for transforming a sequence A into a sequence B.
shared_ptr< subrange_type > subrange_sptr
Convenience typedef for a shared pointer on a function_decl::subrange.
Definition: abg-ir.h:2537
shared_ptr< base_spec > base_spec_sptr
Convenience typedef.
Definition: abg-ir.h:4246
vector< base_spec_sptr > base_specs
Convenience typedef.
Definition: abg-ir.h:4247
vector< method_decl_sptr > member_functions
Convenience typedef.
Definition: abg-ir.h:4057
bool get_is_anonymous() const
Test if the current declaration is anonymous.
Definition: abg-ir.cc:4901
The abstraction of the version of an ELF symbol.
Definition: abg-ir.h:1194
Abstraction of an elf symbol.
Definition: abg-ir.h:923
const string & get_id_string() const
Get a string that is representative of a given elf_symbol.
Definition: abg-ir.cc:2521
std::vector< enumerator > enumerators
Convenience typedef for a list of enumerator.
Definition: abg-ir.h:2766
Abstraction for a function declaration.
Definition: abg-ir.h:3111
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3135
const function_type_sptr get_type() const
Return the type of the current instance of function_decl.
Definition: abg-ir.cc:22136
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:22473
An abstraction helper for type declarations.
Definition: abg-ir.h:1973
The base class of both types and declarations.
Definition: abg-ir.h:1368
Abstracts a variable declaration.
Definition: abg-ir.h:3008
interned_string get_id() const
Return an ID that tries to uniquely identify the variable inside a program or a library.
Definition: abg-ir.cc:20908
change_kind
The kind of change the current function suppression should apply to.
@ ADDED_FUNCTION_CHANGE_KIND
The function was added to the second subject of the diff.
@ DELETED_FUNCTION_CHANGE_KIND
The function was deleted from the second subject of the diff.
change_kind
The kind of change the current variable suppression should apply to.
@ ADDED_VARIABLE_CHANGE_KIND
The variable was added to the second second subject of the diff.
@ DELETED_VARIABLE_CHANGE_KIND
The variable was deleted from the second subject of the diff.
A type used to time various part of the libabigail system.
bool stop()
Stop the timer.
bool start()
Start the timer.
std::vector< filter_base_sptr > filters
Convenience typedef for a vector of filter_base_sptr.
bool is_decl_only_class_with_size_change(const class_or_union &first, const class_or_union &second)
Test if two classes that are decl-only (have the decl-only flag and carry no data members) but are di...
shared_ptr< filter_base > filter_base_sptr
Convenience typedef for a shared pointer to filter_base.
bool has_harmful_name_change(const decl_base_sptr &f, const decl_base_sptr &s)
Test if two decls represents a harmful name change.
bool has_decl_only_def_change(const decl_base_sptr &first, const decl_base_sptr &second)
Test if two decl_base_sptr are different just by the fact that one is decl-only and the other one is ...
bool has_basic_or_class_type_name_change(const diff *d)
Test if a diff node carries a basic or class type name change.
void apply_filter(filter_base &filter, corpus_diff_sptr d)
Walk the diff sub-trees of a a corpus_diff and apply a filter to the nodes visted....
bool is_mostly_distinct_diff(const diff *d)
Test if a diff node carries a distinct type change or a pointer/reference/typedef to distinct type ch...
shared_ptr< diff > diff_sptr
Convenience typedef for a shared_ptr for the diff class.
Definition: abg-fwd.h:79
visiting_kind operator~(visiting_kind l)
The overloaded 'bit inversion' operator for visiting_kind.
const decl_diff_base * is_decl_diff(const diff *diff)
Test if a diff node is about differences between declarations.
const diff * peel_qualified_diff(const diff *dif)
If a diff node is about changes between two qualified types, get the diff node about changes between ...
const diff * peel_pointer_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two pointer, reference or qualified types,...
void categorize_redundancy(diff *diff_tree)
Walk a given diff sub-tree to categorize each of the nodes with respect to the REDUNDANT_CATEGORY.
vector< diff * > diff_ptrs_type
Convenience typedef for a vector of diff*.
void sort_string_diff_ptr_map(const string_diff_ptr_map &map, diff_ptrs_type &sorted)
Sort a map ofg string -> diff* into a vector of diff_ptr. The diff_ptr are sorted lexicographically w...
diff_category
An enum for the different categories that a diff tree node falls into, regarding the kind of changes ...
@ ACCESS_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries access related changes,...
@ HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless data member change....
@ SUPPRESSED_CATEGORY
This means that a diff node was marked as suppressed by a user-provided suppression specification.
@ VIRTUAL_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an incompatible change to a vtable.
@ REDUNDANT_CATEGORY
A diff node in this category is redundant. That means it's present as a child of a other nodes in the...
@ SIZE_OR_OFFSET_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries a change that modifies the...
@ NON_VIRT_MEM_FUN_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a non-virtual member fu...
@ HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
A diff node in this category has a descendant node that is in the HAS_ALLOWED_CHANGE_CATEGORY categor...
@ HARMLESS_ENUM_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition of enumerator to an enum type.
@ FN_PARM_ADD_REMOVE_CHANGE_CATEGORY
A diff node in this category is a function (or function type) with at least one parameter added or re...
@ VOID_PTR_TO_PTR_CHANGE_CATEGORY
A diff node in this category carries a change from void pointer to non-void pointer.
@ PRIVATE_TYPE_CATEGORY
This means that a diff node was warked as being for a private type. That is, the diff node is meant t...
@ COMPATIBLE_TYPE_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries a change involving two com...
@ TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a type that was declaration-only and that is now ...
@ STATIC_DATA_MEMBER_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a static data member.
@ HARMLESS_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...
@ HARMLESS_UNION_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless union change.
@ HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
A diff node in this category has a parent node that is in the HAS_ALLOWED_CHANGE_CATEGORY category....
@ BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY
A diff node in this category carries a change in the size of the array type of a global variable,...
@ VAR_TYPE_CV_CHANGE_CATEGORY
A diff node in this category is for a variable which type holds a cv-qualifier change.
@ HAS_ALLOWED_CHANGE_CATEGORY
A diff node in this category carries a change that must be reported, even if the diff node is also in...
@ FN_PARM_TYPE_CV_CHANGE_CATEGORY
A diff node in this category has a function parameter type with a cv-qualifiers change.
@ FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
A diff node in this category is a function parameter type which top cv-qualifiers change.
@ FN_RETURN_TYPE_CV_CHANGE_CATEGORY
A diff node in this category is a function return type with a cv-qualifier change.
@ HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an a symbol alias change that is harmless.
shared_ptr< reporter_base > reporter_base_sptr
A convenience typedef for a shared pointer to a reporter_base.
Definition: abg-reporter.h:54
void sort_string_var_diff_sptr_map(const string_var_diff_sptr_map &map, var_diff_sptrs_type &sorted)
Sort of an instance of string_var_diff_sptr_map map.
unordered_map< string, var_diff_sptr > string_var_diff_sptr_map
Convenience typedef for a map whose key is a string and whose value is a changed variable of type var...
const class_or_union_diff * is_diff_of_class_or_union_type(const diff *d)
Test if a diff node represents a diff between two class or union types.
const pointer_diff * is_pointer_diff(const diff *diff)
Test if a diff node is about differences between two pointers.
vector< var_diff_sptr > var_diff_sptrs_type
Convenience typedef for a vector of var_diff_sptr.
unordered_map< string, class_decl::base_spec_sptr > string_base_sptr_map
Convenience typedef for a map of string and class_decl::basse_spec_sptr.
void sort_string_function_ptr_map(const string_function_ptr_map &map, vector< const function_decl * > &sorted)
Sort an instance of string_function_ptr_map map and stuff a resulting sorted vector of pointers to fu...
diff_sptr try_to_diff(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
</distinct_diff>
bool has_basic_type_change_only(const diff *d)
Test if a diff node is a decl diff that only carries a basic type change on its type diff sub-node.
void propagate_categories(diff *diff_tree)
Visit all the nodes of a given sub-tree. For each node that has a particular category set,...
const subrange_diff * is_subrange_diff(const diff *diff)
Test if a diff node is a subrange_diff node.
unordered_map< unsigned, fn_parm_diff_sptr > unsigned_fn_parm_diff_sptr_map
Convenience typedef for a map which key is an integer and which value is a changed parameter.
void sort_string_base_sptr_map(const string_base_sptr_map &m, class_decl::base_specs &sorted)
Lexicographically sort base specifications found in instances of string_base_sptr_map.
diff_category get_default_harmless_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmless.
vector< diff_sptr > diff_sptrs_type
Convenience typedef for a vector of diff_sptr.
distinct_diff_sptr compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
Try to diff entities that are of distinct kinds.
void sort_changed_data_members(changed_var_sptrs_type &input)
Sort (in place) a vector of changed data members.
unordered_map< string, type_base_sptr > string_type_base_sptr_map
Convenience typedef for a map which key is a string and which value is a type_base_sptr.
diff_sptr try_to_diff< class_decl >(const type_or_decl_base_sptr first, const type_or_decl_base_sptr second, diff_context_sptr ctxt)
This is a specialization of try_to_diff() template to diff instances of class_decl.
shared_ptr< type_decl_diff > type_decl_diff_sptr
Convenience typedef for a shared pointer on a type_decl_diff type.
bool is_diff_of_variadic_parameter(const diff *d)
Test if a diff node represents the difference between a variadic parameter and something else.
shared_ptr< diff_context > diff_context_sptr
Convenience typedef for a shared pointer of diff_context.
Definition: abg-fwd.h:71
bool is_diff_of_global_decls(const diff *)
Tests if a given diff node is to represent the changes between two gobal decls.
shared_ptr< subrange_diff > subrange_diff_sptr
A convenience typedef for a shared pointer to subrange_diff type.
bool is_diff_of_variadic_parameter_type(const diff *d)
Test if a diff node represents the difference between a variadic parameter type and something else.
diff_category get_default_harmful_categories_bitmap()
Getter of a bitmap made of the set of change categories that are considered harmful.
unordered_map< string, function_decl::parameter_sptr > string_parm_map
Convenience typedef for a map which value is a function parameter. The key is the name of the functio...
unordered_map< string, enum_type_decl::enumerator > string_enumerator_map
Convenience typedef for a map which value is an enumerator. The key is the name of the enumerator.
shared_ptr< var_diff > var_diff_sptr
Convenience typedef for a shared pointer to a var_diff type.
unordered_map< string, method_decl_sptr > string_member_function_sptr_map
Convenience typedef for a hash map of strings and member functions.
const diff * peel_typedef_diff(const diff *dif)
If a diff node is about changes between two typedef types, get the diff node about changes between th...
shared_ptr< reference_diff > reference_diff_sptr
Convenience typedef for a shared pointer on a reference_diff type.
vector< base_diff_sptr > base_diff_sptrs_type
Convenience typedef for a vector of base_diff_sptr.
shared_ptr< function_decl_diff > function_decl_diff_sptr
Convenience typedef for a shared pointer to a function_decl type.
shared_ptr< ptr_to_mbr_diff > ptr_to_mbr_diff_sptr
Typedef of a shared_ptr to ptr_to_mbr_diff.
void sort_string_elf_symbol_map(const string_elf_symbol_map &map, vector< elf_symbol_sptr > &sorted)
Sort a map of string -> pointer to elf_symbol.
const function_decl_diff * is_function_decl_diff(const diff *diff)
Test if a diff node is about differences between functions.
void sort_string_function_decl_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort the values of a string_function_decl_diff_sptr_map map and store the result in a vector of funct...
shared_ptr< fn_parm_diff > fn_parm_diff_sptr
Convenience typedef for a shared pointer to a fn_parm_diff type.
unordered_map< string, function_decl_diff_sptr > string_function_decl_diff_sptr_map
Convenience typedef for a map which key is a string and which value is a function_decl_diff_sptr.
void clear_redundancy_categorization(diff *diff_tree)
Walk a given diff sub-tree to clear the REDUNDANT_CATEGORY out of the category of the nodes.
unordered_map< string, const var_decl * > string_var_ptr_map
Convenience typedef for a map which key is a string and which value is a point to var_decl.
void sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map, var_diff_sptrs_type &sorted)
Sort the values of a unsigned_var_diff_sptr_map map and store the result into a vector of var_diff_sp...
void sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map &map, vector< fn_parm_diff_sptr > &sorted)
Sort a map of fn_parm_diff by the indexes of the function parameters.
bool is_child_node_of_base_diff(const diff *diff)
Test if a diff node is a child node of a base diff node.
visiting_kind
An enum for the different ways to visit a diff tree node.
@ SKIP_CHILDREN_VISITING_KIND
This says that the traversing code should avoid visiting the children nodes of the current node being...
@ DO_NOT_MARK_VISITED_NODES_AS_VISITED
This says that the traversing code should not mark visited nodes as having been traversed....
visiting_kind operator&(visiting_kind l, visiting_kind r)
The overloaded and operator for visiting_kind.
const diff * peel_fn_parm_diff(const diff *dif)
If a diff node is about changes between two function parameters get the diff node about changes betwe...
const function_type_diff * is_function_type_diff(const diff *diff)
Test if a diff node is a function_type_diff node.
const distinct_diff * is_distinct_diff(const diff *diff)
Test if a diff node is about differences between two diff nodes of different kinds.
unordered_map< string, changed_enumerator > string_changed_enumerator_map
Convenience typedef for a map which value is a changed enumerator. The key is the name of the changed...
visiting_kind operator|(visiting_kind l, visiting_kind r)
The overloaded or operator for visiting_kind.
const array_diff * is_array_diff(const diff *diff)
Test if a diff node is a array_diff node.
const diff * peel_reference_diff(const diff *dif)
If a diff node is about changes between two reference types, get the diff node about changes between ...
unordered_map< string, fn_parm_diff_sptr > string_fn_parm_diff_sptr_map
Convenience typedef for a map which value is a changed function parameter and which key is the name o...
string get_pretty_representation(diff *d)
Get a copy of the pretty representation of a diff node.
void sort_artifacts_set(const artifact_sptr_set_type &set, vector< type_or_decl_base_sptr > &sorted)
Sort the set of ABI artifacts contained in a artifact_sptr_set_type.
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.
const class_or_union_diff * is_anonymous_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff between two anonymous classes or unions.
shared_ptr< base_diff > base_diff_sptr
Convenience typedef for a shared pointer to a base_diff type.
shared_ptr< scope_diff > scope_diff_sptr
Convenience typedef for a shared pointer on a scope_diff.
shared_ptr< class_diff > class_diff_sptr
Convenience typedef for a shared pointer on a class_diff type.
const base_diff * is_base_diff(const diff *diff)
Test if a diff node is about differences between two base class specifiers.
const fn_parm_diff * is_fn_parm_diff(const diff *diff)
Test if a diff node is about differences between two function parameters.
void sort_string_member_function_sptr_map(const string_member_function_sptr_map &map, class_or_union::member_functions &sorted)
Sort a map that's an instance of string_member_function_sptr_map and fill a vector of member function...
const union_diff * is_union_diff(const diff *diff)
Test if a diff node is a union_diff node.
vector< changed_var_sptr > changed_var_sptrs_type
Convenience typedef for a vector of @changed_var_sptr.gg381.
shared_ptr< pointer_diff > pointer_diff_sptr
Convenience typedef for a shared pointer on a pointer_diff type.
const diff * peel_pointer_diff(const diff *dif)
If a diff node is about changes between two pointer types, get the diff node about changes between th...
void apply_suppressions(diff *diff_tree)
Walk a given diff-sub tree and appply the suppressions carried by the context. If the suppression app...
void sort_string_parm_map(const string_parm_map &map, vector< function_decl::parameter_sptr > &sorted)
Sort a map of string -> function parameters.
void sort_string_type_base_sptr_map(string_type_base_sptr_map &map, vector< type_base_sptr > &sorted)
Sort a map of string to type_base_sptr entities.
const enum_diff * is_enum_diff(const diff *diff)
Test if a diff node is a enum_diff node.
unordered_map< string, base_diff_sptr > string_base_diff_sptr_map
Convenience typedef for a map of string and base_diff_sptr.
void sort_data_members(const string_decl_base_sptr_map &data_members, vector< decl_base_sptr > &sorted)
Sort a map of data members by the offset of their initial value.
const class_or_union_diff * is_class_or_union_diff(const diff *d)
Test if a diff node is a class_or_union_diff node.
const corpus_diff * is_corpus_diff(const diff *diff)
Test if a diff node is a corpus_diff node.
const diff * get_typedef_diff_underlying_type_diff(const diff *diff)
Return the leaf underlying diff node of a typedef_diff node.
const typedef_diff * is_typedef_diff(const diff *diff)
Test if a diff node is a typedef_diff node.
unordered_map< unsigned, var_diff_sptr > unsigned_var_diff_sptr_map
Convenience typedef for a map whose key is an unsigned int and whose value is a changed variable of t...
type_base_sptr get_leaf_type(qualified_type_def_sptr t)
Return the first underlying type that is not a qualified type.
const diff * peel_typedef_qualified_type_or_parameter_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
shared_ptr< array_diff > array_diff_sptr
Convenience typedef for a shared pointer on a array_diff type.
bool is_reference_or_ptr_diff_to_non_basic_nor_distinct_types(const diff *diff)
Test if a diff node is a reference or pointer diff node to a change that is neither basic type change...
const class_diff * is_class_diff(const diff *diff)
Test if a diff node is a class_diff node.
void sort_string_var_ptr_map(const string_var_ptr_map &map, vector< const var_decl * > &sorted)
Sort a map of string -> pointer to var_decl.
const type_decl_diff * is_diff_of_basic_type(const diff *d)
Test if a diff node represents a diff between two basic types.
unordered_map< string, diff_sptr > string_diff_sptr_map
Convenience typedef for a map which value is a diff_sptr. The key of the map is the qualified name of...
unordered_map< const diff *, artifact_sptr_set_type, diff_hash, diff_equal > diff_artifact_set_map_type
A convenience typedef for an unordered_map which key is a diff* and which value is a artifact_sptr_se...
const qualified_type_diff * is_qualified_type_diff(const diff *diff)
Test if a diff node is about differences between two qualified types.
diff_sptr compute_diff(const decl_base_sptr first, const decl_base_sptr second, diff_context_sptr ctxt)
Compute the difference between two decls. The decls can represent either type declarations,...
unordered_map< string, diff * > string_diff_ptr_map
Convenience typedef for a map which value is a diff*. The key of the map is the qualified name of the...
void sort_string_base_diff_sptr_map(const string_base_diff_sptr_map &map, base_diff_sptrs_type &sorted)
Sort a map of string -> base_diff_sptr into a sorted vector of base_diff_sptr. The base_diff_sptr are...
void sort_changed_enumerators(const string_changed_enumerator_map &enumerators_map, changed_enumerators_type &sorted)
Sort a map of changed enumerators.
void print_diff_tree(diff *diff_tree, ostream &out)
Emit a textual representation of a diff sub-tree to an output stream.
vector< changed_enumerator > changed_enumerators_type
Convenience typedef for a vector of changed enumerators.
vector< function_decl_diff_sptr > function_decl_diff_sptrs_type
Convenience typedef for a vector of function_decl_diff_sptr.
bool is_child_node_of_function_parm_diff(const diff *diff)
Test if a diff node is a child node of a function parameter diff node.
void sort_string_virtual_member_function_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort an map of string -> virtual member function into a vector of virtual member functions....
shared_ptr< function_type_diff > function_type_diff_sptr
A convenience typedef for a shared pointer to function_type_type_diff.
const function_type_diff * is_function_type_diff_with_local_changes(const diff *diff)
Test if a given diff node carries a function type change with local changes.
const var_diff * is_var_diff(const diff *diff)
Test if a diff node is about differences between variables.
const type_diff_base * is_type_diff(const diff *diff)
Test if a diff node is about differences between types.
unordered_map< string, elf_symbol_sptr > string_elf_symbol_map
Convenience typedef for a map whose key is a string and whose value is an elf_symbol_sptr.
void sort_string_diff_sptr_map(const string_diff_sptr_map &map, diff_sptrs_type &sorted)
Sort a map ofg string -> diff_sptr into a vector of diff_sptr. The diff_sptr are sorted lexicographic...
const reference_diff * is_reference_diff(const diff *diff)
Test if a diff node is about differences between two references.
void sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map &map, var_diff_sptrs_type &sorted)
Sort the values of a string_var_diff_sptr_map and store the result in a vector of var_diff_sptr.
void apply_filters(corpus_diff_sptr diff_tree)
Apply the diff tree filters that have been associated to the context of the a given corpus_diff tree....
shared_ptr< distinct_diff > distinct_diff_sptr
Convenience typedef for a shared pointer to distinct_types_diff.
shared_ptr< corpus_diff > corpus_diff_sptr
A convenience typedef for a shared pointer to corpus_diff.
std::pair< var_decl_sptr, var_decl_sptr > changed_var_sptr
Convenience typedef for a pair of var_decl_sptr representing a var_decl change. The first member of t...
shared_ptr< typedef_diff > typedef_diff_sptr
Convenience typedef for a shared pointer on a typedef_diff type.
const diff * peel_typedef_or_qualified_type_diff(const diff *dif)
If a diff node is about changes between two typedefs or qualified types, get the diff node about chan...
void sort_enumerators(const string_enumerator_map &enumerators_map, enum_type_decl::enumerators &sorted)
Sort a map of enumerators by their value.
unordered_map< string, const function_decl * > string_function_ptr_map
Convenience typedef for a map which key is a string and which value is a pointer to decl_base.
ostream & operator<<(ostream &o, diff_category c)
Serialize an instance of diff_category to an output stream.
shared_ptr< translation_unit_diff > translation_unit_diff_sptr
Convenience typedef for a shared pointer on a translation_unit_diff type.
void compute_diff(RandomAccessOutputIterator a_base, RandomAccessOutputIterator a_begin, RandomAccessOutputIterator a_end, RandomAccessOutputIterator b_base, RandomAccessOutputIterator b_begin, RandomAccessOutputIterator b_end, vector< point > &lcs, edit_script &ses, int &ses_len)
Compute the longest common subsequence of two (sub-regions of) sequences as well as the shortest edit...
shared_ptr< reference_type_def > reference_type_def_sptr
Convenience typedef for a shared pointer on a reference_type_def.
Definition: abg-fwd.h:232
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc:6620
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:5809
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition: abg-fwd.h:266
unordered_set< type_or_decl_base_sptr, type_or_decl_hash, type_or_decl_equal > artifact_sptr_set_type
A convenience typedef for a hash set of type_or_decl_base_sptr.
Definition: abg-ir.h:550
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition: abg-ir.cc:10541
bool is_anonymous_data_member(const decl_base &d)
Test if a decl is an anonymous data member.
Definition: abg-ir.cc:6038
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:11873
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:888
change_kind
A bitfield that gives callers of abigail::ir::equals() some insight about how different two internal ...
Definition: abg-ir.h:1323
@ LOCAL_TYPE_CHANGE_KIND
This means that a given IR artifact has a local type change.
Definition: abg-ir.h:1327
@ ALL_LOCAL_CHANGES_MASK
Testing (anding) against this mask means that a given IR artifact has local differences,...
Definition: abg-ir.h:1338
@ LOCAL_NON_TYPE_CHANGE_KIND
This means that a given IR artifact has a local non-type change. That is a change that is carried by ...
Definition: abg-ir.h:1332
bool is_user_defined_type(const type_base *t)
Test if a type is user-defined.
Definition: abg-ir.cc:5713
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:10823
shared_ptr< array_type_def > array_type_def_sptr
Convenience typedef for a shared pointer on a array_type_def.
Definition: abg-fwd.h:241
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:9332
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:11054
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:5976
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:190
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition: abg-fwd.h:207
shared_ptr< typedef_decl > typedef_decl_sptr
Convenience typedef for a shared pointer on a typedef_decl.
Definition: abg-fwd.h:164
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:10773
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:10384
const global_scope * get_global_scope(const decl_base &decl)
return the global scope as seen by a given declaration.
Definition: abg-ir.cc:8593
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition: abg-fwd.h:253
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:236
shared_ptr< scope_decl > scope_decl_sptr
Convenience typedef for a shared pointer on a scope_decl.
Definition: abg-fwd.h:261
shared_ptr< type_or_decl_base > type_or_decl_base_sptr
A convenience typedef for a shared_ptr to type_or_decl_base.
Definition: abg-fwd.h:121
shared_ptr< translation_unit > translation_unit_sptr
Convenience typedef for a shared pointer on a translation_unit type.
Definition: abg-fwd.h:137
bool equals(const decl_base &l, const decl_base &r, change_kind *k)
Compares two instances of decl_base.
Definition: abg-ir.cc:5360
shared_ptr< pointer_type_def > pointer_type_def_sptr
Convenience typedef for a shared pointer on a pointer_type_def.
Definition: abg-fwd.h:223
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:19804
uint64_t get_absolute_data_member_offset(const var_decl &m)
Get the absolute offset of a data member.
Definition: abg-ir.cc:6439
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition: abg-ir.cc:6534
var_decl * is_var_decl(const type_or_decl_base *tod)
Tests if a declaration is a variable declaration.
Definition: abg-ir.cc:11717
decl_base * is_decl(const type_or_decl_base *d)
Test if an ABI artifact is a declaration.
Definition: abg-ir.cc:10481
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition: abg-fwd.h:172
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:6897
uint64_t get_data_member_offset(const var_decl &m)
Get the offset of a data member.
Definition: abg-ir.cc:6350
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6807
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:11576
bool is_union_type(const type_or_decl_base &t)
Test if a type is a union_decl.
Definition: abg-ir.cc:11103
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition: abg-ir.cc:5847
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition: abg-ir.cc:10174
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:28249
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:9224
shared_ptr< type_decl > type_decl_sptr
Convenience typedef for a shared pointer on a type_decl.
Definition: abg-fwd.h:158
bool is_unique_type(const type_base_sptr &t)
Test if a type is unique in the entire environment.
Definition: abg-ir.cc:27844
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:11546
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:11075
bool is_at_global_scope(const decl_base &decl)
Tests whether a given declaration is at global scope.
Definition: abg-ir.cc:10314
bool is_member_decl(const decl_base_sptr d)
Tests if a declaration is a class member.
Definition: abg-ir.cc:5651
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:1639
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_private_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:1636
bool is_negated_suppression(const suppression_base &s)
Test if a suppression specification is a negated suppression.
Toplevel namespace for libabigail.
A comparison function for instances of base_diff.
A functor to compare instances of class_decl::base_spec.
A functor to compare two changed enumerators, based on their initial value.
size_t count_filtered_bases()
Count the number of bases classes whose changes got filtered out.
class_decl::base_spec_sptr base_has_changed(class_decl::base_spec_sptr) const
Test whether a given base class has changed. A base class has changed if it's in both in deleted *and...
The type of private data of class_or_union_diff.
size_t count_filtered_changed_dm(bool local_only=false)
Get the number of data member changes carried by the current diff node that were filtered out.
size_t count_filtered_subtype_changed_dm(bool local_only=false)
Get the number of data member sub-type changes carried by the current diff node that were filtered ou...
size_t get_deleted_non_static_data_members_number() const
Get the number of non static data members that were deleted.
size_t count_filtered_changed_mem_fns(const diff_context_sptr &)
Get the number of member functions changes carried by the current diff node that were filtered out.
decl_base_sptr subtype_changed_dm(decl_base_sptr) const
Test if the current diff node carries a data member change for a data member which name is the same a...
type_or_decl_base_sptr member_type_has_changed(decl_base_sptr) const
Test if the current diff node carries a member type change for a member type which name is the same a...
decl_base_sptr member_class_tmpl_has_changed(decl_base_sptr) const
Test if the current diff node carries a member class template change for a member class template whic...
size_t count_filtered_inserted_mem_fns(const diff_context_sptr &)
Get the number of member functions insertions carried by the current diff node that were filtered out...
size_t count_filtered_deleted_mem_fns(const diff_context_sptr &)
Get the number of member functions deletions carried by the current diff node that were filtered out.
size_t get_inserted_non_static_data_members_number() const
Get the number of non static data members that were inserted.
The type of the private data of corpus_diff::diff_stats.
bool added_unreachable_type_is_suppressed(const type_base *t) const
Test if an added type that is unreachable from public interface has been suppressed by a suppression ...
void ensure_lookup_tables_populated()
If the lookup tables are not yet built, walk the differences and fill the lookup tables.
const vector< diff_sptr > & changed_unreachable_types_sorted() const
Get the sorted vector of diff nodes representing changed unreachable types.
diff_context_sptr get_context()
Getter of the context associated with this corpus.
void categorize_redundant_changed_sub_nodes()
Walk the changed functions and variables diff nodes to categorize redundant nodes.
const string_diff_sptr_map & changed_unreachable_types() const
Get the map of diff nodes representing changed unreachable types.
bool added_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added variable symbol (that is not referenced by any debug inf...
bool lookup_tables_empty() const
Tests if the lookup tables are empty.
bool deleted_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted function symbol (that is not referenced by any debug i...
void apply_filters_and_compute_diff_stats(corpus_diff::diff_stats &)
Compute the diff stats.
bool added_variable_is_suppressed(const var_decl *var) const
Test if the change reports for a given added variable have been suppressed.
bool deleted_unreachable_type_is_suppressed(const type_base *t) const
Test if a deleted type that is unreachable from public interface has been suppressed by a suppression...
bool deleted_variable_is_suppressed(const var_decl *var) const
Test if the change reports for a give given deleted variable has been deleted.
bool deleted_unrefed_var_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given deleted variable symbol (that is not referenced by any debug i...
void maybe_dump_diff_tree()
If the user asked to dump the diff tree node (for changed variables and functions) on the error outpu...
void count_unreachable_types(size_t &num_added, size_t &num_removed, size_t &num_changed, size_t &num_filtered_added, size_t &num_filtered_removed, size_t &num_filtered_changed)
Count the number of types not reachable from the interface (i.e, not reachable from global functions ...
void clear_redundancy_categorization()
Walk the changed functions and variables diff nodes and clear the redundancy categorization they migh...
void count_leaf_changes(size_t &num_changes, size_t &num_filtered)
Count the number of leaf changes as well as the number of the changes that have been filtered out.
void count_leaf_type_changes(size_t &num_type_changes, size_t &num_type_changes_filtered)
Count the number of leaf *type* changes as well as the number of the leaf type changes that have been...
bool added_unrefed_fn_sym_is_suppressed(const elf_symbol *) const
Test if the change reports for a given added function symbol (that is not referenced by any debug inf...
bool deleted_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a given deleted function have been deleted.
void apply_supprs_to_added_removed_fns_vars_unreachable_types()
Apply suppression specifications for this corpus diff to the set of added/removed functions/variables...
void emit_diff_stats(const diff_stats &stats, ostream &out, const string &indent)
Emit the summary of the functions & variables that got removed/changed/added.
bool added_function_is_suppressed(const function_decl *fn) const
Test if the change reports for a give given added function has been deleted.
void clear_lookup_tables()
Clear the lookup tables useful for reporting an enum_diff.
A comparison functor to compare two data members based on their offset.
A comparison functor to compare two instances of var_diff that represent changed data members based o...
A comparison functor for instances of diff.
A functor to compare two instances of diff_sptr.
The private data structure for distinct_diff.
A functor to compare instances of elf_symbol base on their names.
A functor to compare two enumerators based on their value. This implements the "less than" operator.
A comparison functor to compare two instances of fn_parm_diff based on their indexes.
"Less than" functor to compare instances of function_decl.
A "Less Than" functor to compare instance of function_decl_diff.
Functor that compares two function parameters for the purpose of sorting them.
The internal type for the impl idiom implementation of pointer_diff.
The private data of the ptr_to_mbr_diff type.
The internal type for the impl idiom implementation of subrange_diff.
A functor to compare instances of var_decl base on their qualified names.
The internal type for the impl idiom implementation of var_diff.
Functor to sort instances of var_diff_sptr.
A comparison functor for instances of function_decl_diff that represent changes between two virtual m...
An equality functor to deeply compare pointers.
A comparison functor to compare pointer to instances of type_or_decl_base.
Definition: abg-ir.h:3242
A deleter for shared pointers that ... doesn't delete the object managed by the shared pointer.