libabigail
abg-leaf-reporter.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) 2017-2025 Red Hat, Inc.
5//
6// Author: Dodji Seketeli
7
8
9/// @file
10///
11/// This is the implementation of the
12/// abigail::comparison::default_reporter type.
13
14#include "abg-comparison-priv.h"
15#include "abg-reporter.h"
16#include "abg-reporter-priv.h"
17
18namespace abigail
19{
20namespace comparison
21{
22
23/// Test if a diff node is to be reported by the current instance of
24/// @ref leaf_reporter.
25///
26/// A node is said to be reported by the current instance of @ref
27/// leaf_reporter if the node carries local changes and if the node's
28/// reporting hasn't been suppressed.
29bool
31{return d && d->to_be_reported() && d->has_local_changes();}
32
33/// Test if a given instance of @ref corpus_diff carries changes whose
34/// reports are not suppressed by any suppression specification. In
35/// effect, these are deemed incompatible ABI changes.
36///
37/// @param d the @ref corpus_diff to consider
38///
39/// @return true iff @p d carries subtype changes that are deemed
40/// incompatible ABI changes.
41bool
43{
44 if (!d)
45 return false;
46
47 const corpus_diff::diff_stats& stats = const_cast<corpus_diff*>(d)->
48 apply_filters_and_suppressions_before_reporting();
49
50 // Logic here should match emit_diff_stats.
51 return (d->architecture_changed()
52 || d->soname_changed()
53 || stats.net_num_func_removed()
56 || stats.net_num_func_added()
57 || stats.net_num_vars_removed()
59 || stats.net_num_vars_added()
66 || stats.net_num_added_var_syms());
67}
68
69/// Report the changes carried by the diffs contained in an instance
70/// of @ref string_diff_ptr_map.
71///
72/// @param mapp the set of diffs to report for.
73///
74/// @param out the output stream to report the diffs to.
75///
76/// @param indent the string to use for indentation.
77static void
78report_diffs(const reporter_base& r,
79 const string_diff_ptr_map& mapp,
80 ostream& out,
81 const string& indent)
82{
83 diff_ptrs_type sorted_diffs;
84 sort_string_diff_ptr_map(mapp, sorted_diffs);
85
86 bool started_to_emit = false;
87 for (diff_ptrs_type::const_iterator i = sorted_diffs.begin();
88 i != sorted_diffs.end();
89 ++i)
90 {
91 if (const var_diff *d = is_var_diff(*i))
92 if (is_data_member(d->first_var()))
93 continue;
94
95 if (r.diff_to_be_reported((*i)->get_canonical_diff()))
96 {
97 if (started_to_emit)
98 out << "\n";
99
100 string n = (*i)->first_subject()->get_pretty_representation();
101
102 out << indent << "'" << n;
103
104 report_loc_info((*i)->first_subject(),
105 *(*i)->context(), out);
106
107 out << "' changed:\n";
108
109 (*i)->get_canonical_diff()->report(out, indent + " ");
110 started_to_emit = true;
111 }
112 }
113}
114
115/// Report the type changes carried by an instance of @ref diff_maps.
116///
117/// @param maps the set of diffs to report.
118///
119/// @param out the output stream to report the diffs to.
120///
121/// @param indent the string to use for indentation.
122static void
123report_type_changes_from_diff_maps(const leaf_reporter& reporter,
124 const diff_maps& maps,
125 ostream& out,
126 const string& indent)
127{
128 // basic types
129 report_diffs(reporter, maps.get_type_decl_diff_map(), out, indent);
130
131 // enums
132 report_diffs(reporter, maps.get_enum_diff_map(), out, indent);
133
134 // classes
135 report_diffs(reporter, maps.get_class_diff_map(), out, indent);
136
137 // unions
138 report_diffs(reporter, maps.get_union_diff_map(), out, indent);
139
140 // typedefs
141 report_diffs(reporter, maps.get_typedef_diff_map(), out, indent);
142
143 // subranges
144 report_diffs(reporter, maps.get_subrange_diff_map(), out, indent);
145
146 // arrays
147 report_diffs(reporter, maps.get_array_diff_map(), out, indent);
148
149 // It doesn't make sense to report function type changes, does it?
150 // report_diffs(reporter, maps.get_function_type_diff_map(), out, indent);
151
152 // distinct diffs
153 report_diffs(reporter, maps.get_distinct_diff_map(), out, indent);
154
155 // function parameter diffs
156 report_diffs(reporter, maps.get_fn_parm_diff_map(), out, indent);
157}
158
159/// Report the changes carried by an instance of @ref diff_maps.
160///
161/// @param maps the set of diffs to report.
162///
163/// @param out the output stream to report the diffs to.
164///
165/// @param indent the string to use for indentation.
166void
168 ostream& out,
169 const string& indent) const
170{
171 report_type_changes_from_diff_maps(*this, maps, out, indent);
172
173 // function decls
174 report_diffs(*this, maps.get_function_decl_diff_map(), out, indent);
175
176 // var decl
177 report_diffs(*this, maps.get_var_decl_diff_map(), out, indent);
178}
179
180/// Report the changes carried by a @ref typedef_diff node.
181///
182/// @param out the output stream to report to.
183///
184/// @param indent the white space string to use for indentation.
185void
186leaf_reporter::report(const typedef_diff& d,
187 ostream& out,
188 const string& indent) const
189{
190 if (!diff_to_be_reported(&d))
191 return;
192
193 // all changes carried by a typedef_diff are considered local, so
194 // let's just call the default reporter here.
195 default_reporter::report(d, out, indent);
196
198}
199
200/// Report the changes carried by a @ref qualified_type_diff node.
201///
202/// @param out the output stream to report to.
203///
204/// @param indent the white space string to use for indentation.
205void
206leaf_reporter::report(const qualified_type_diff& d, ostream& out,
207 const string& indent) const
208{
209 if (!diff_to_be_reported(&d))
210 return;
211
213
214 // Note that changes that are local to the underlying type of a
215 // qualified type are considered to be local to the qualified type
216 // itself. So let's go ahead and report the local changes of the
217 // underlying type.
219}
220
221/// Report the changes carried by a @ref pointer_diff node.
222///
223/// Note that this function does nothing because a @ref pointer_diff
224/// node never carries local changes.
225void
226leaf_reporter::report(const pointer_diff &d,
227 ostream& out,
228 const string& indent) const
229{
230 // Changes that modify the representation of a pointed-to type is
231 // considered local to the pointer type.
232 if (!diff_to_be_reported(&d))
233 return;
234
235 out << indent
236 << "pointer type changed from: '"
237 << d.first_pointer()->get_pretty_representation()
238 << "' to: '"
239 << d.second_pointer()->get_pretty_representation()
240 << "'\n";
241}
242
243/// Report the changes carried by a @ref reference_diff node.
244///
245/// @param out the output stream to report to.
246///
247/// @param indent the white space string to use for indentation.
248void
249leaf_reporter::report(const reference_diff& d,
250 ostream& out,
251 const string& indent) const
252{
253 if (!diff_to_be_reported(&d))
254 return;
255
257}
258
259/// Report the changes carried by a @ref ptr_to_mbr_diff node.
260///
261/// @param out the output stream to report to.
262///
263/// @param indent the white space string to use for indentation.
264void
265leaf_reporter::report(const ptr_to_mbr_diff& d, std::ostream& out,
266 const std::string& indent) const
267{
268 if (!diff_to_be_reported(&d))
269 return;
270
272}
273
274/// Report the changes carried by a @ref fn_parm_diff node.
275///
276/// @param out the output stream to report to.
277///
278/// @param indent the white space string to use for indentation.
279void
280leaf_reporter::report(const fn_parm_diff& d,
281 ostream& out,
282 const string& indent) const
283{
284 if (!diff_to_be_reported(&d))
285 return;
286
288
290
291 out << indent
292 << "parameter " << f->get_index();
293
294 report_loc_info(f, *d.context(), out);
295
296 out << " of type '"
297 << f->get_type_pretty_representation()
298 << "' changed:\n";
299 d.type_diff()->report(out, indent + " ");
300}
301
302/// Report the changes carried by a @ref function_type_diff node.
303///
304/// @param out the output stream to report to.
305///
306/// @param indent the white space string to use for indentation.
307void
308leaf_reporter::report(const function_type_diff& d,
309 ostream& out,
310 const string& indent) const
311{
312 if (!diff_to_be_reported(&d))
313 return;
314
316
317 if (diff_to_be_reported(d.priv_->return_type_diff_.get()))
318 {
319 out << indent << "return type changed:\n";
320 d.priv_->return_type_diff_->report(out, indent + " ");
321 }
322
323 // Hmmh, the above was quick. Now report about function parameters;
324 //
325 // Report about the parameter types that have changed sub-types.
326 for (vector<fn_parm_diff_sptr>::const_iterator i =
327 d.priv_->sorted_subtype_changed_parms_.begin();
328 i != d.priv_->sorted_subtype_changed_parms_.end();
329 ++i)
330 {
331 diff_sptr dif = *i;
332 if (diff_to_be_reported(dif.get()))
333 dif->report(out, indent);
334 }
335}
336
337/// Report the changes carried by a @ref scope_diff node.
338///
339/// @param out the output stream to report to.
340///
341/// @param indent the white space string to use for indentation.
342void
343leaf_reporter::report(const scope_diff& d,
344 ostream& out,
345 const string& indent) const
346{
347 if (!d.to_be_reported())
348 return;
349
350 // Report changed types.
351 unsigned num_changed_types = d.changed_types().size();
352 if (num_changed_types)
353 out << indent << "changed types:\n";
354
355 for (diff_sptrs_type::const_iterator dif = d.changed_types().begin();
356 dif != d.changed_types().end();
357 ++dif)
358 {
359 if (!*dif || !diff_to_be_reported((*dif).get()))
360 continue;
361
362 out << indent << " '"
363 << (*dif)->first_subject()->get_pretty_representation()
364 << "' changed:\n";
365 (*dif)->report(out, indent + " ");
366 }
367
368 // Report changed decls
369 unsigned num_changed_decls = d.changed_decls().size();
370 if (num_changed_decls)
371 out << indent << "changed declarations:\n";
372
373 for (diff_sptrs_type::const_iterator dif= d.changed_decls().begin();
374 dif != d.changed_decls().end ();
375 ++dif)
376 {
377 if (!*dif || !diff_to_be_reported((*dif).get()))
378 continue;
379
380 out << indent << " '"
381 << (*dif)->first_subject()->get_pretty_representation()
382 << "' was changed to '"
383 << (*dif)->second_subject()->get_pretty_representation() << "'";
384 report_loc_info((*dif)->second_subject(), *d.context(), out);
385 out << ":\n";
386
387 (*dif)->report(out, indent + " ");
388 }
389
390 // Report removed types/decls
391 for (string_decl_base_sptr_map::const_iterator i =
392 d.priv_->deleted_types_.begin();
393 i != d.priv_->deleted_types_.end();
394 ++i)
395 out << indent
396 << " '"
397 << i->second->get_pretty_representation()
398 << "' was removed\n";
399
400 if (d.priv_->deleted_types_.size())
401 out << "\n";
402
403 for (string_decl_base_sptr_map::const_iterator i =
404 d.priv_->deleted_decls_.begin();
405 i != d.priv_->deleted_decls_.end();
406 ++i)
407 out << indent
408 << " '"
409 << i->second->get_pretty_representation()
410 << "' was removed\n";
411
412 if (d.priv_->deleted_decls_.size())
413 out << "\n";
414
415 // Report added types/decls
416 bool emitted = false;
417 for (string_decl_base_sptr_map::const_iterator i =
418 d.priv_->inserted_types_.begin();
419 i != d.priv_->inserted_types_.end();
420 ++i)
421 {
422 // Do not report about type_decl as these are usually built-in
423 // types.
424 if (dynamic_pointer_cast<type_decl>(i->second))
425 continue;
426 out << indent
427 << " '"
428 << i->second->get_pretty_representation()
429 << "' was added\n";
430 emitted = true;
431 }
432
433 if (emitted)
434 out << "\n";
435
436 emitted = false;
437 for (string_decl_base_sptr_map::const_iterator i =
438 d.priv_->inserted_decls_.begin();
439 i != d.priv_->inserted_decls_.end();
440 ++i)
441 {
442 // Do not report about type_decl as these are usually built-in
443 // types.
444 if (dynamic_pointer_cast<type_decl>(i->second))
445 continue;
446 out << indent
447 << " '"
448 << i->second->get_pretty_representation()
449 << "' was added\n";
450 emitted = true;
451 }
452
453 if (emitted)
454 out << "\n";
455}
456
457/// Report about the change carried by a @ref subrange_diff diff node
458/// in a serialized form.
459///
460/// @param d the diff node to consider.
461///
462/// @param out the output stream to report to.
463///
464/// @param indent the indentation string to use in the report.
465void
466leaf_reporter::report(const subrange_diff& d, std::ostream& out,
467 const std::string& indent) const
468{
469 if (!diff_to_be_reported(&d))
470 return;
471
472 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(d.first_subrange(),
473 d.second_subrange(),
474 "range type");
475
476 represent(d, d.context(), out,indent, /*local_only=*/true);
477
479}
480
481/// Report the changes carried by a @ref array_diff node.
482///
483/// @param out the output stream to report to.
484///
485/// @param indent the white space string to use for indentation.
486void
487leaf_reporter::report(const array_diff& d,
488 ostream& out,
489 const string& indent) const
490{
491 if (!diff_to_be_reported(&d))
492 return;
493
494 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(d.first_array(),
495 d.second_array(),
496 "array type");
497
499 d.second_array(),
500 d.context(),
501 out, indent);
502
504 if (diff_to_be_reported(dif.get()))
505 {
506 string fn = ir::get_pretty_representation(is_type(dif->first_subject()));
507 // report array element type changes
508 out << indent << "array element type '"
509 << fn << "' changed: \n";
510 dif->report(out, indent + " ");
511 }
512
514}
515
516/// Report the changes carried by a @ref class_or_union_diff node.
517///
518/// @param out the output stream to report to.
519///
520/// @param indent the white space string to use for indentation.
521void
522leaf_reporter::report(const class_or_union_diff& d,
523 ostream& out,
524 const string& indent) const
525{
526 if (!diff_to_be_reported(&d))
527 return;
528
529 class_or_union_sptr first = d.first_class_or_union(),
530 second = d.second_class_or_union();
531
532 const diff_context_sptr& ctxt = d.context();
533
534 // Report class decl-only -> definition change.
535 if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
537 {
538 string was =
539 first->get_is_declaration_only()
540 ? " was a declaration-only type"
541 : " was a defined type";
542
543 string is_now =
544 second->get_is_declaration_only()
545 ? " and is now a declaration-only type"
546 : " and is now a defined type";
547
548 out << indent << "type " << first->get_pretty_representation()
549 << was << is_now << "\n";
550 return;
551 }
552
553 // member functions
554 if (d.member_fns_changes())
555 {
556 // report deletions
557 int numdels = d.get_priv()->deleted_member_functions_.size();
558 size_t num_filtered =
559 d.get_priv()->count_filtered_deleted_mem_fns(ctxt);
560 if (numdels)
561 report_mem_header(out, numdels, num_filtered, del_kind,
562 "member function", indent);
563 for (string_member_function_sptr_map::const_iterator i =
564 d.get_priv()->deleted_member_functions_.begin();
565 i != d.get_priv()->deleted_member_functions_.end();
566 ++i)
567 {
568 if (!(ctxt->get_allowed_category()
570 && !get_member_function_is_virtual(i->second))
571 continue;
572
573 method_decl_sptr mem_fun = i->second;
574 out << indent << " ";
575 represent(*ctxt, mem_fun, out);
576 }
577
578 // report insertions;
579 int numins = d.get_priv()->inserted_member_functions_.size();
580 num_filtered = d.get_priv()->count_filtered_inserted_mem_fns(ctxt);
581 if (numins)
582 report_mem_header(out, numins, num_filtered, ins_kind,
583 "member function", indent);
584 for (string_member_function_sptr_map::const_iterator i =
585 d.get_priv()->inserted_member_functions_.begin();
586 i != d.get_priv()->inserted_member_functions_.end();
587 ++i)
588 {
589 if (!(ctxt->get_allowed_category()
591 && !get_member_function_is_virtual(i->second))
592 continue;
593
594 method_decl_sptr mem_fun = i->second;
595 out << indent << " ";
596 represent(*ctxt, mem_fun, out);
597 }
598
599 // report member function with sub-types changes
600 int numchanges = d.get_priv()->sorted_changed_member_functions_.size();
601 if (numchanges)
602 report_mem_header(out, change_kind, "member function", indent);
603 for (function_decl_diff_sptrs_type::const_iterator i =
604 d.get_priv()->sorted_changed_member_functions_.begin();
605 i != d.get_priv()->sorted_changed_member_functions_.end();
606 ++i)
607 {
608 if (!(ctxt->get_allowed_category()
611 ((*i)->first_function_decl()))
613 ((*i)->second_function_decl())))
614 continue;
615
616 diff_sptr diff = *i;
617 if (!diff_to_be_reported(diff.get()))
618 continue;
619
620 string repr =
621 (*i)->first_function_decl()->get_pretty_representation();
622 out << indent << " '" << repr << "' has some changes:\n";
623 diff->report(out, indent + " ");
624 }
625 }
626
627 // data members
628 if (d.data_members_changes())
629 {
630 // report deletions
631 int numdels = d.class_or_union_diff::get_priv()->
632 get_deleted_non_static_data_members_number();
633 if (numdels)
634 {
635 report_mem_header(out, numdels, 0, del_kind,
636 "data member", indent);
637 vector<decl_base_sptr> sorted_dms;
639 (d.class_or_union_diff::get_priv()->deleted_data_members_,
640 sorted_dms);
641 for (vector<decl_base_sptr>::const_iterator i = sorted_dms.begin();
642 i != sorted_dms.end();
643 ++i)
644 {
645 var_decl_sptr data_mem =
646 dynamic_pointer_cast<var_decl>(*i);
647 ABG_ASSERT(data_mem);
648 if (get_member_is_static(data_mem))
649 continue;
650 represent_data_member(data_mem, ctxt, out, indent + " ");
651 }
652 }
653
654 //report insertions
655 int numins =
656 d.class_or_union_diff::get_priv()->inserted_data_members_.size();
657 if (numins)
658 {
659 report_mem_header(out, numins, 0, ins_kind,
660 "data member", indent);
661 vector<decl_base_sptr> sorted_dms;
663 (d.class_or_union_diff::get_priv()->inserted_data_members_,
664 sorted_dms);
665 for (vector<decl_base_sptr>::const_iterator i = sorted_dms.begin();
666 i != sorted_dms.end();
667 ++i)
668 {
669 var_decl_sptr data_mem =
670 dynamic_pointer_cast<var_decl>(*i);
671 ABG_ASSERT(data_mem);
672 represent_data_member(data_mem, ctxt, out, indent + " ");
673 }
674 }
675
676 // report changes
677 size_t net_numchanges = 0;
678
679 for (var_diff_sptrs_type::const_iterator it =
680 d.sorted_changed_data_members().begin();
681 it != d.sorted_changed_data_members().end();
682 ++it)
683 if (diff_to_be_reported((*it).get()))
684 net_numchanges++;
685
686 for (var_diff_sptrs_type::const_iterator it =
687 d.sorted_subtype_changed_data_members().begin();
688 it != d.sorted_subtype_changed_data_members().end();
689 ++it)
690 if (diff_to_be_reported((*it).get()))
691 net_numchanges++;
692
693 if (net_numchanges)
694 {
695 report_mem_header(out, change_kind, "data member", indent);
696
697 for (var_diff_sptrs_type::const_iterator it =
698 d.sorted_changed_data_members().begin();
699 it != d.sorted_changed_data_members().end();
700 ++it)
701 if (diff_to_be_reported((*it).get()))
702 represent(*it, ctxt, out, indent + " ", /*local_only=*/true);
703
704 for (var_diff_sptrs_type::const_iterator it =
705 d.sorted_subtype_changed_data_members().begin();
706 it != d.sorted_subtype_changed_data_members().end();
707 ++it)
708 if (diff_to_be_reported((*it).get()))
709 represent(*it, ctxt, out, indent + " ", /*local_only=*/true);
710 }
711
712 // Report about data members replaced by an anonymous union data
713 // member.
715 }
716}
717
718/// Report the changes carried by a @ref class_diff node.
719///
720/// @param out the output stream to report to.
721///
722/// @param indent the white space string to use for indentation.
723void
724leaf_reporter::report(const class_diff& d,
725 ostream& out,
726 const string& indent) const
727{
728 if (!diff_to_be_reported(&d))
729 return;
730
731 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_subject(),
732 d.second_subject());
733
734 string name = d.first_subject()->get_pretty_representation();
735
736 // Now report the changes about the differents parts of the type.
737 class_decl_sptr first = d.first_class_decl(),
738 second = d.second_class_decl();
739
740 report_name_size_and_alignment_changes(first, second, d.context(),
741 out, indent);
742
743 const diff_context_sptr& ctxt = d.context();
744 maybe_report_diff_for_member(first, second, ctxt, out, indent);
745
746 d.class_or_union_diff::report(out, indent);
747
749
751
752 d.reported_once(true);
753}
754
755/// Report the changes carried by a @ref union_diff node.
756///
757/// @param out the output stream to report to.
758///
759/// @param indent the white space string to use for indentation.
760void
761leaf_reporter::report(const union_diff& d,
762 ostream& out,
763 const string& indent) const
764{
765 if (!diff_to_be_reported(&d))
766 return;
767
768 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_subject(),
769 d.second_subject());
770
771 // Now report the changes about the differents parts of the type.
772 union_decl_sptr first = d.first_union_decl(), second = d.second_union_decl();
773
774 report_name_size_and_alignment_changes(first, second, d.context(),
775 out, indent);
776
777 maybe_report_diff_for_member(first, second,d. context(), out, indent);
778
779 d.class_or_union_diff::report(out, indent);
780
782}
783
784/// Report the changes carried by a @ref distinct_diff node.
785///
786/// @param out the output stream to report to.
787///
788/// @param indent the white space string to use for indentation.
789void
790leaf_reporter::report(const distinct_diff& d,
791 ostream& out,
792 const string& indent) const
793{
794 if (!diff_to_be_reported(&d))
795 return;
796
797 type_or_decl_base_sptr f = d.first(), s = d.second();
798
799 string f_repr = f ? f->get_pretty_representation() : "'void'";
800 string s_repr = s ? s->get_pretty_representation() : "'void'";
801
802 diff_sptr diff = d.compatible_child_diff();
803
804 string compatible = diff ? " to compatible type '": " to '";
805
806 out << indent << "entity changed from '" << f_repr << "'"
807 << compatible << s_repr << "'";
808 report_loc_info(s, *d.context(), out);
809 out << "\n";
810
811 report_size_and_alignment_changes(f, s, d.context(), out, indent);
813}
814
815/// Report the changes carried by a @ref function_decl_diff node.
816///
817/// @param out the output stream to report to.
818///
819/// @param indent the white space string to use for indentation.
820void
821leaf_reporter::report(const function_decl_diff& d,
822 ostream& out,
823 const string& indent) const
824{
825 if (!diff_to_be_reported(&d))
826 return;
827
828 maybe_report_diff_for_member(d.first_function_decl(),
829 d.second_function_decl(),
830 d.context(), out, indent);
831
832 function_decl_sptr ff = d.first_function_decl();
833 function_decl_sptr sf = d.second_function_decl();
834
835 diff_context_sptr ctxt = d.context();
836 corpus_sptr fc = ctxt->get_corpus_diff()->first_corpus();
837 corpus_sptr sc = ctxt->get_corpus_diff()->second_corpus();
838
839 string qn1 = ff->get_qualified_name(), qn2 = sf->get_qualified_name(),
840 linkage_names1, linkage_names2;
841 elf_symbol_sptr s1 = ff->get_symbol(), s2 = sf->get_symbol();
842
843 if (s1)
844 linkage_names1 = s1->get_id_string();
845 if (s2)
846 linkage_names2 = s2->get_id_string();
847
848 // If the symbols for ff and sf have aliases, get all the names of
849 // the aliases;
850 if (fc && s1)
851 linkage_names1 =
852 s1->get_aliases_id_string(fc->get_fun_symbol_map());
853 if (sc && s2)
854 linkage_names2 =
855 s2->get_aliases_id_string(sc->get_fun_symbol_map());
856
857 /// If the set of linkage names of the function have changed, report
858 /// it.
859 if (linkage_names1 != linkage_names2)
860 {
861 if (linkage_names1.empty())
862 {
863 out << indent << ff->get_pretty_representation()
864 << " didn't have any linkage name, and it now has: '"
865 << linkage_names2 << "'\n";
866 }
867 else if (linkage_names2.empty())
868 {
869 out << indent << ff->get_pretty_representation()
870 << " did have linkage names '" << linkage_names1
871 << "'\n"
872 << indent << "but it doesn't have any linkage name anymore\n";
873 }
874 else
875 out << indent << "linkage names of "
876 << ff->get_pretty_representation()
877 << "\n" << indent << "changed from '"
878 << linkage_names1 << "' to '" << linkage_names2 << "'\n";
879 }
880
881 if (qn1 != qn2
882 && diff_to_be_reported(d.type_diff().get()))
883 {
884 // So the function has sub-type changes that are to be
885 // reported. Let's see if the function name changed too; if it
886 // did, then we'd report that change right before reporting the
887 // sub-type changes.
888 string frep1 = d.first_function_decl()->get_pretty_representation(),
889 frep2 = d.second_function_decl()->get_pretty_representation();
890 out << indent << "'" << frep1 << " {" << linkage_names1<< "}"
891 << "' now becomes '"
892 << frep2 << " {" << linkage_names2 << "}" << "'\n";
893 }
894
895 maybe_report_diff_for_symbol(ff->get_symbol(),
896 sf->get_symbol(),
897 ctxt, out, indent);
898
899 // Now report about inline-ness changes
900 if (ff->is_declared_inline() != sf->is_declared_inline())
901 {
902 out << indent;
903 if (ff->is_declared_inline())
904 out << sf->get_pretty_representation()
905 << " is not declared inline anymore\n";
906 else
907 out << sf->get_pretty_representation()
908 << " is now declared inline\n";
909 }
910
911 // Report about vtable offset changes.
913 {
914 bool ff_is_virtual = get_member_function_is_virtual(ff),
915 sf_is_virtual = get_member_function_is_virtual(sf);
916 if (ff_is_virtual != sf_is_virtual)
917 {
918 out << indent;
919 if (ff_is_virtual)
920 out << ff->get_pretty_representation()
921 << " is no more declared virtual\n";
922 else
923 out << ff->get_pretty_representation()
924 << " is now declared virtual\n";
925 }
926
927 size_t ff_vtable_offset = get_member_function_vtable_offset(ff),
928 sf_vtable_offset = get_member_function_vtable_offset(sf);
929 if (ff_is_virtual && sf_is_virtual
930 && (ff_vtable_offset != sf_vtable_offset))
931 {
932 out << indent
933 << "the vtable offset of " << ff->get_pretty_representation()
934 << " changed from " << ff_vtable_offset
935 << " to " << sf_vtable_offset << "\n";
936 }
937
938 // the classes of the two member functions.
939 class_decl_sptr fc =
940 is_class_type(is_method_type(ff->get_type())->get_class_type());
941 class_decl_sptr sc =
942 is_class_type(is_method_type(sf->get_type())->get_class_type());
943
944 // Detect if the virtual member function changes above
945 // introduced a vtable change or not.
946 bool vtable_added = false, vtable_removed = false;
947 if (!fc->get_is_declaration_only() && !sc->get_is_declaration_only())
948 {
949 vtable_added = !fc->has_vtable() && sc->has_vtable();
950 vtable_removed = fc->has_vtable() && !sc->has_vtable();
951 }
952 bool vtable_changed = ((ff_is_virtual != sf_is_virtual)
953 || (ff_vtable_offset != sf_vtable_offset));
954 bool incompatible_change = (ff_vtable_offset != sf_vtable_offset);
955
956 if (vtable_added)
957 out << indent
958 << " note that a vtable was added to "
959 << fc->get_pretty_representation()
960 << "\n";
961 else if (vtable_removed)
962 out << indent
963 << " note that the vtable was removed from "
964 << fc->get_pretty_representation()
965 << "\n";
966 else if (vtable_changed)
967 {
968 out << indent;
969 if (incompatible_change)
970 out << " note that this is an ABI incompatible "
971 "change to the vtable of ";
972 else
973 out << " note that this induces a change to the vtable of ";
974 out << fc->get_pretty_representation()
975 << "\n";
976 }
977
978 }
979
980 // Report about function type differences.
981 if (diff_to_be_reported(d.type_diff().get()))
982 d.type_diff()->report(out, indent);
983}
984
985/// Report the changes carried by a @ref var_diff node.
986///
987/// @param out the output stream to report to.
988///
989/// @param indent the white space string to use for indentation.
990void
991leaf_reporter::report(const var_diff& d,
992 ostream& out,
993 const string& indent) const
994{
995 if (!diff_to_be_reported(&d))
996 return;
997
998 decl_base_sptr first = d.first_var(), second = d.second_var();
999 string n = first->get_pretty_representation();
1000
1002 d.context(),
1003 out, indent);
1004
1005 maybe_report_diff_for_symbol(d.first_var()->get_symbol(),
1006 d.second_var()->get_symbol(),
1007 d.context(), out, indent);
1008
1009 maybe_report_diff_for_member(first, second, d.context(), out, indent);
1010
1011 if (diff_sptr dif = d.type_diff())
1012 {
1013 if (diff_to_be_reported(dif.get()))
1014 {
1015 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(dif, "type");
1016 out << indent << "type of variable changed:\n";
1017 dif->report(out, indent + " ");
1018 }
1019 }
1020}
1021
1022/// Report the changes carried by a @ref translation_unit_diff node.
1023///
1024/// @param out the output stream to report to.
1025///
1026/// @param indent the white space string to use for indentation.
1027void
1028leaf_reporter::report(const translation_unit_diff& d,
1029 ostream& out,
1030 const string& indent) const
1031{
1032 if (!d.to_be_reported())
1033 return;
1034
1035 static_cast<const scope_diff&>(d).report(out, indent);
1036}
1037
1038/// Emit a report about changes carried by a @ref var_diff node.
1039///
1040/// @param ctxt the diff context to use.
1041///
1042/// @param var_diff the @êef var_diff node to consider.
1043///
1044/// @param out the output stream to emit the report to.
1045///
1046/// @param indent the indentation string to use for the report.
1047static void
1048emit_changed_var_report(const diff_context_sptr& ctxt,
1049 const var_diff_sptr& var_diff,
1050 ostream& out, const string indent)
1051{
1052 diff_sptr diff = var_diff;
1053 if (!diff
1054 || !diff->to_be_reported()
1055 || !diff->has_local_changes())
1056 return;
1057
1058 string n1 = diff->first_subject()->get_pretty_representation();
1059 string n2 = diff->second_subject()->get_pretty_representation();
1060
1061 out << indent << " [C] '" << n1 << "' was changed";
1062 if (n1 != n2)
1063 out << " to '" << n2 << "'";
1064 report_loc_info(diff->second_subject(), *ctxt, out);
1065 out << ":\n";
1066 diff->report(out, indent + " ");
1067 // Extra spacing.
1068 out << "\n";
1069}
1070
1071/// Report the changes carried by a @ref corpus_diff node.
1072///
1073/// @param out the output stream to report to.
1074///
1075/// @param indent the white space string to use for indentation.
1076void
1077leaf_reporter::report(const corpus_diff& d,
1078 ostream& out,
1079 const string& indent) const
1080{
1081 if (!d.has_changes())
1082 return;
1083
1084 const corpus_diff::diff_stats &s =
1085 const_cast<corpus_diff&>(d).
1086 apply_filters_and_suppressions_before_reporting();
1087
1088 const diff_context_sptr& ctxt = d.context();
1089
1090 d.priv_->emit_diff_stats(s, out, indent);
1091 if (ctxt->show_stats_only())
1092 return;
1093 out << "\n";
1094
1095 if (ctxt->show_soname_change()
1096 && !d.priv_->sonames_equal_)
1097 out << indent << "SONAME changed from '"
1098 << d.first_corpus()->get_soname() << "' to '"
1099 << d.second_corpus()->get_soname() << "'\n\n";
1100
1101 if (ctxt->show_architecture_change()
1102 && !d.priv_->architectures_equal_)
1103 out << indent << "architecture changed from '"
1104 << d.first_corpus()->get_architecture_name() << "' to '"
1105 << d.second_corpus()->get_architecture_name() << "'\n\n";
1106
1107 /// Report removed/added/changed functions.
1108 if (ctxt->show_deleted_fns())
1109 {
1110 if (s.net_num_func_removed() == 1)
1111 out << indent << "1 Removed function:\n\n";
1112 else if (s.net_num_func_removed() > 1)
1113 out << indent << s.net_num_func_removed() << " Removed functions:\n\n";
1114
1115 bool emitted = false;
1116 corpus::functions sorted_deleted_fns;
1117 sort_string_function_ptr_map(d.priv_->deleted_fns_, sorted_deleted_fns);
1118 for (auto f : sorted_deleted_fns)
1119 {
1120 if (d.priv_->deleted_function_is_suppressed(f))
1121 continue;
1122
1123 out << indent
1124 << " ";
1125 out << "[D] ";
1126 out << "'" << f->get_pretty_representation() << "'";
1127 if (ctxt->show_linkage_names())
1128 {
1129 out << " {";
1130 show_linkage_name_and_aliases(out, "", *f->get_symbol(),
1131 d.first_corpus()->get_fun_symbol_map());
1132 out << "}";
1133 }
1134 out << "\n";
1136 {
1137 class_decl_sptr c =
1138 is_class_type(is_method_type(f->get_type())->get_class_type());
1139 out << indent
1140 << " "
1141 << "note that this removes an entry from the vtable of "
1142 << c->get_pretty_representation()
1143 << "\n";
1144 }
1145 emitted = true;
1146 }
1147 if (emitted)
1148 out << "\n";
1149 }
1150
1151 if (ctxt->show_added_fns())
1152 {
1153 if (s.net_num_func_added() == 1)
1154 out << indent << "1 Added function:\n\n";
1155 else if (s.net_num_func_added() > 1)
1156 out << indent << s.net_num_func_added()
1157 << " Added functions:\n\n";
1158 bool emitted = false;
1159 corpus::functions sorted_added_fns;
1160 sort_string_function_ptr_map(d.priv_->added_fns_, sorted_added_fns);
1161 for (auto f : sorted_added_fns)
1162 {
1163 if (d.priv_->added_function_is_suppressed(f))
1164 continue;
1165
1166 out
1167 << indent
1168 << " ";
1169 out << "[A] ";
1170 out << "'"
1171 << f->get_pretty_representation()
1172 << "'";
1173 if (ctxt->show_linkage_names())
1174 {
1175 out << " {";
1177 (out, "", *f->get_symbol(),
1178 d.second_corpus()->get_fun_symbol_map());
1179 out << "}";
1180 }
1181 out << "\n";
1183 {
1184 class_decl_sptr c =
1185 is_class_type(is_method_type(f->get_type())->get_class_type());
1186 out << indent
1187 << " "
1188 << "note that this adds a new entry to the vtable of "
1189 << c->get_pretty_representation()
1190 << "\n";
1191 }
1192 emitted = true;
1193 }
1194 if (emitted)
1195 out << "\n";
1196 }
1197
1198 if (ctxt->show_changed_fns())
1199 {
1200 // Show changed functions.
1201 size_t num_changed = s.net_num_leaf_func_changes();
1202 if (num_changed == 1)
1203 out << indent << "1 function with some sub-type change:\n\n";
1204 else if (num_changed > 1)
1205 out << indent << num_changed
1206 << " functions with some sub-type change:\n\n";
1207
1208 vector<function_decl_diff_sptr> sorted_changed_fns;
1209 sort_string_function_decl_diff_sptr_map(d.priv_->changed_fns_map_,
1210 sorted_changed_fns);
1211 for (vector<function_decl_diff_sptr>::const_iterator i =
1212 sorted_changed_fns.begin();
1213 i != sorted_changed_fns.end();
1214 ++i)
1215 {
1216 diff_sptr diff = *i;
1217 if (!diff)
1218 continue;
1219
1220 if (diff_to_be_reported(diff.get()))
1221 {
1222 function_decl_sptr fn = (*i)->first_function_decl();
1223 out << indent << " [C] '"
1224 << fn->get_pretty_representation() << "'";
1225 report_loc_info((*i)->second_function_decl(), *ctxt, out);
1226 out << " has some sub-type changes:\n";
1227 if ((fn->get_symbol()->has_aliases()
1228 && !(is_member_function(fn)
1230 && !(is_member_function(fn)
1232 || (is_c_language(get_translation_unit(fn)->get_language())
1233 && fn->get_name() != fn->get_linkage_name()))
1234 {
1235 int number_of_aliases =
1236 fn->get_symbol()->get_number_of_aliases();
1237 if (number_of_aliases == 0)
1238 {
1239 out << indent << " "
1240 << "Please note that the exported symbol of "
1241 "this function is "
1242 << fn->get_symbol()->get_id_string()
1243 << "\n";
1244 }
1245 else
1246 {
1247 out << indent << " "
1248 << "Please note that the symbol of this function is "
1249 << fn->get_symbol()->get_id_string()
1250 << "\n and it aliases symbol";
1251 if (number_of_aliases > 1)
1252 out << "s";
1253 out << ": "
1254 << fn->get_symbol()->get_aliases_id_string(false)
1255 << "\n";
1256 }
1257 }
1258 diff->report(out, indent + " ");
1259 // Extra spacing.
1260 out << "\n";
1261 }
1262 }
1263 // Changed functions have extra spacing already. No new line here.
1264 }
1265
1266 // Report removed/added/changed variables.
1267 if (ctxt->show_deleted_vars())
1268 {
1269 if (s.net_num_vars_removed() == 1)
1270 out << indent << "1 Removed variable:\n\n";
1271 else if (s.net_num_vars_removed() > 1)
1272 out << indent << s.net_num_vars_removed()
1273 << " Removed variables:\n\n";
1274 string n;
1275 bool emitted = false;
1276 corpus::variables sorted_deleted_vars;
1277 sort_string_var_ptr_map(d.priv_->deleted_vars_, sorted_deleted_vars);
1278 for (auto v : sorted_deleted_vars)
1279 {
1280 if (d.priv_->deleted_variable_is_suppressed(v))
1281 continue;
1282
1283 n = v->get_pretty_representation();
1284
1285 out << indent
1286 << " ";
1287 out << "[D] ";
1288 out << "'"
1289 << n
1290 << "'";
1291 if (ctxt->show_linkage_names())
1292 {
1293 out << " {";
1294 show_linkage_name_and_aliases(out, "", *v->get_symbol(),
1295 d.first_corpus()->get_var_symbol_map());
1296 out << "}";
1297 }
1298 out << "\n";
1299 emitted = true;
1300 }
1301 if (emitted)
1302 out << "\n";
1303 }
1304
1305 if (ctxt->show_added_vars())
1306 {
1307 if (s.net_num_vars_added() == 1)
1308 out << indent << "1 Added variable:\n\n";
1309 else if (s.net_num_vars_added() > 1)
1310 out << indent << s.net_num_vars_added()
1311 << " Added variables:\n\n";
1312 string n;
1313 bool emitted = false;
1314 corpus::variables sorted_added_vars;
1315 sort_string_var_ptr_map(d.priv_->added_vars_, sorted_added_vars);
1316 for (auto v : sorted_added_vars)
1317 {
1318 if (d.priv_->added_variable_is_suppressed(v))
1319 continue;
1320
1321 n = v->get_pretty_representation();
1322
1323 out << indent
1324 << " ";
1325 out << "[A] ";
1326 out << "'" << n << "'";
1327 if (ctxt->show_linkage_names())
1328 {
1329 out << " {";
1330 show_linkage_name_and_aliases(out, "", *v->get_symbol(),
1331 d.second_corpus()->get_var_symbol_map());
1332 out << "}";
1333 }
1334 out << "\n";
1335 emitted = true;
1336 }
1337 if (emitted)
1338 out << "\n";
1339 }
1340
1341 if (ctxt->show_changed_vars())
1342 {
1343 if (size_t num_changed = s.num_var_with_incompatible_changes())
1344 {
1345 if (num_changed == 1)
1346 out << indent << "1 variable with incompatible sub-type changes:\n\n";
1347 else if (num_changed > 1)
1348 out << indent << num_changed
1349 << " variables with incompatible sub-type changes:\n\n";
1350
1351 sort_var_diffs(const_cast<corpus_diff&>(d).
1352 incompatible_changed_variables());
1353 for (auto& var_diff : d.incompatible_changed_variables())
1354 if (var_diff)
1355 emit_changed_var_report(ctxt, var_diff, out, indent);
1356 }
1357
1358 if (size_t num_changed = (s.net_num_leaf_var_changes()
1359 - s.num_var_with_incompatible_changes()))
1360 {
1361 if (num_changed == 1)
1362 out << indent << "1 Changed variable:\n\n";
1363 else if (num_changed > 1)
1364 out << indent << num_changed
1365 << " Changed variables:\n\n";
1366 string n1, n2;
1367 for (var_diff_sptr diff : d.priv_->sorted_changed_vars_)
1369 emit_changed_var_report(ctxt, diff, out, indent);
1370 }
1371
1372 // Changed variables have extra spacing already. No new line here.
1373 }
1374
1375 // Report removed function symbols not referenced by any debug info.
1376 if (ctxt->show_symbols_unreferenced_by_debug_info()
1377 && d.priv_->deleted_unrefed_fn_syms_.size())
1378 {
1379 if (s.net_num_removed_func_syms() == 1)
1380 out << indent
1381 << "1 Removed function symbol not referenced by debug info:\n\n";
1382 else if (s.net_num_removed_func_syms() > 0)
1383 out << indent
1384 << s.net_num_removed_func_syms()
1385 << " Removed function symbols not referenced by debug info:\n\n";
1386
1387 bool emitted = false;
1388 vector<elf_symbol_sptr> sorted_deleted_unrefed_fn_syms;
1389 sort_string_elf_symbol_map(d.priv_->deleted_unrefed_fn_syms_,
1390 sorted_deleted_unrefed_fn_syms);
1391 for (vector<elf_symbol_sptr>::const_iterator i =
1392 sorted_deleted_unrefed_fn_syms.begin();
1393 i != sorted_deleted_unrefed_fn_syms.end();
1394 ++i)
1395 {
1396 if (d.priv_->deleted_unrefed_fn_sym_is_suppressed((*i).get()))
1397 continue;
1398
1399 out << indent << " ";
1400 out << "[D] ";
1401
1402 show_linkage_name_and_aliases(out, "", **i,
1403 d.first_corpus()->get_fun_symbol_map());
1404 out << "\n";
1405 emitted = true;
1406 }
1407 if (emitted)
1408 out << "\n";
1409 }
1410
1411 // Report added function symbols not referenced by any debug info.
1412 if (ctxt->show_symbols_unreferenced_by_debug_info()
1413 && ctxt->show_added_symbols_unreferenced_by_debug_info()
1414 && d.priv_->added_unrefed_fn_syms_.size())
1415 {
1416 if (s.net_num_added_func_syms() == 1)
1417 out << indent
1418 << "1 Added function symbol not referenced by debug info:\n\n";
1419 else if (s.net_num_added_func_syms() > 0)
1420 out << indent
1421 << s.net_num_added_func_syms()
1422 << " Added function symbols not referenced by debug info:\n\n";
1423
1424 bool emitted = false;
1425 vector<elf_symbol_sptr> sorted_added_unrefed_fn_syms;
1426 sort_string_elf_symbol_map(d.priv_->added_unrefed_fn_syms_,
1427 sorted_added_unrefed_fn_syms);
1428 for (vector<elf_symbol_sptr>::const_iterator i =
1429 sorted_added_unrefed_fn_syms.begin();
1430 i != sorted_added_unrefed_fn_syms.end();
1431 ++i)
1432 {
1433 if (d.priv_->added_unrefed_fn_sym_is_suppressed((*i).get()))
1434 continue;
1435
1436 out << indent << " ";
1437 out << "[A] ";
1439 **i,
1440 d.second_corpus()->get_fun_symbol_map());
1441 out << "\n";
1442 emitted = true;
1443 }
1444 if (emitted)
1445 out << "\n";
1446 }
1447
1448 // Report removed variable symbols not referenced by any debug info.
1449 if (ctxt->show_symbols_unreferenced_by_debug_info()
1450 && d.priv_->deleted_unrefed_var_syms_.size())
1451 {
1452 if (s.net_num_removed_var_syms() == 1)
1453 out << indent
1454 << "1 Removed variable symbol not referenced by debug info:\n\n";
1455 else if (s.net_num_removed_var_syms() > 0)
1456 out << indent
1457 << s.net_num_removed_var_syms()
1458 << " Removed variable symbols not referenced by debug info:\n\n";
1459
1460 bool emitted = false;
1461 vector<elf_symbol_sptr> sorted_deleted_unrefed_var_syms;
1462 sort_string_elf_symbol_map(d.priv_->deleted_unrefed_var_syms_,
1463 sorted_deleted_unrefed_var_syms);
1464 for (vector<elf_symbol_sptr>::const_iterator i =
1465 sorted_deleted_unrefed_var_syms.begin();
1466 i != sorted_deleted_unrefed_var_syms.end();
1467 ++i)
1468 {
1469 if (d.priv_->deleted_unrefed_var_sym_is_suppressed((*i).get()))
1470 continue;
1471
1472 out << indent << " ";
1473 out << "[D] ";
1474
1476 (out, "", **i,
1477 d.first_corpus()->get_fun_symbol_map());
1478
1479 out << "\n";
1480 emitted = true;
1481 }
1482 if (emitted)
1483 out << "\n";
1484 }
1485
1486 // Report added variable symbols not referenced by any debug info.
1487 if (ctxt->show_symbols_unreferenced_by_debug_info()
1488 && ctxt->show_added_symbols_unreferenced_by_debug_info()
1489 && d.priv_->added_unrefed_var_syms_.size())
1490 {
1491 if (s.net_num_added_var_syms() == 1)
1492 out << indent
1493 << "1 Added variable symbol not referenced by debug info:\n\n";
1494 else if (s.net_num_added_var_syms() > 0)
1495 out << indent
1496 << s.net_num_added_var_syms()
1497 << " Added variable symbols not referenced by debug info:\n\n";
1498
1499 bool emitted = false;
1500 vector<elf_symbol_sptr> sorted_added_unrefed_var_syms;
1501 sort_string_elf_symbol_map(d.priv_->added_unrefed_var_syms_,
1502 sorted_added_unrefed_var_syms);
1503 for (vector<elf_symbol_sptr>::const_iterator i =
1504 sorted_added_unrefed_var_syms.begin();
1505 i != sorted_added_unrefed_var_syms.end();
1506 ++i)
1507 {
1508 if (d.priv_->added_unrefed_var_sym_is_suppressed((*i).get()))
1509 continue;
1510
1511 out << indent << " ";
1512 out << "[A] ";
1513 show_linkage_name_and_aliases(out, "", **i,
1514 d.second_corpus()->get_fun_symbol_map());
1515 out << "\n";
1516 emitted = true;
1517 }
1518 if (emitted)
1519 out << "\n";
1520 }
1521
1522 // Now show the changed types.
1523 const diff_maps& leaf_diffs = d.get_leaf_diffs();
1524 report_type_changes_from_diff_maps(*this, leaf_diffs, out, indent);
1525
1526 // Report added/removed/changed types not reacheable from public
1527 // interfaces.
1528 maybe_report_unreachable_type_changes(d, s, indent, out);
1529
1530 d.priv_->maybe_dump_diff_tree();
1531}
1532} // end namespace comparison
1533} // end namespace abigail
The private data and functions of the abigail::ir::comparison types.
#define ABG_ASSERT(cond)
This is a wrapper around the 'assert' glibc call. It allows for its argument to have side effects,...
Definition: abg-fwd.h:1737
The declaration of the reporting types of libabigail's diff engine.
The abstraction of a diff between two arrays.
const diff_sptr & element_type_diff() const
Getter for the diff between the two types of array elements.
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.
This is a document class that aims to capture statistics about the changes carried by a corpus_diff t...
size_t net_num_leaf_var_changes() const
Getter for the net number of leaf variable change diff nodes.
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 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 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 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_type_changes() const
Getter for the net number of leaf type change diff nodes.
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 net_num_vars_added() const
Getter for the net number of added variables.
size_t net_num_leaf_func_changes() const
Getter for the net 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*...
An abstraction of a diff between between two abi corpus.
bool soname_changed() const
Test if the soname of the underlying corpus has changed.
bool architecture_changed() const
Test if the architecture of the underlying corpus has changed.
bool report_local_ptr_to_mbr_type_changes(const ptr_to_mbr_diff &d, std::ostream &out, const std::string &indent="") const
Report the local changes carried by a ptr_to_mbr_diff diff node.
bool report_local_qualified_type_changes(const qualified_type_diff &d, std::ostream &out, const std::string &indent) const
For a qualified_type_diff node, report the changes that are local.
void report_local_function_type_changes(const function_type_diff &d, std::ostream &out, const std::string &indent) const
For a function_type_diff node, report the local changes carried by the diff node.
void report_underlying_changes_of_qualified_type(const qualified_type_diff &d, ostream &out, const string &indent) const
For a qualified_type_diff node, report the changes of its underlying type.
void report_local_reference_type_changes(const reference_diff &d, std::ostream &out, const std::string &indent) const
For a @reference_diff node, report the local changes carried by the diff node.
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.
The abstraction of a change between two ABI artifacts, a.k.a an artifact change.
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...
bool to_be_reported() const
Test if this diff tree node should be reported.
Abstraction of a diff between two function parameters.
const function_decl::parameter_sptr first_parameter() const
Getter for the first 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...
Abstraction of a diff between two function types.
virtual bool diff_has_net_changes(const corpus_diff *d) const
Test if a given instance of corpus_diff carries changes whose reports are not suppressed by any suppr...
void report_changes_from_diff_maps(const diff_maps &, std::ostream &out, const std::string &indent) const
Report the changes carried by an instance of diff_maps.
virtual bool diff_to_be_reported(const diff *d) const
Test if a diff node is to be reported by the current instance of leaf_reporter.
The abstraction of a diff between two ptr_to_mbr_type.
Abstraction of a diff between two qualified types.
The base class of all the reporting classes.
Definition: abg-reporter.h:58
virtual bool diff_to_be_reported(const diff *d) const
Tests if the diff node is to be reported.
The abstraction of the diff between two subrange types.
const array_type_def::subrange_sptr second_subrange() const
Getter of the second subrange of the current instance subrange_diff.
const array_type_def::subrange_sptr first_subrange() const
Getter of the first subrange of the current instance subrange_diff.
Abstraction of a diff between two typedef_decl.
Abstracts a diff between two instances of var_decl.
vector< var_decl_sptr > variables
Convenience typedef for std::vector<abigail::ir::var_decl*>
Definition: abg-corpus.h:37
vector< const function_decl * > functions
Convenience typedef for std::vector<abigail::ir::function_decl*>
Definition: abg-corpus.h:31
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3187
bool has_class_decl_only_def_change(const class_or_union_sptr &first, const class_or_union_sptr &second)
Test if two class_or_union_sptr are different just by the fact that one is decl-only and the other on...
bool has_incompatible_fn_or_var_change(const diff *d)
Test if a diff node carries an incompatible ABI change.
shared_ptr< diff > diff_sptr
Convenience typedef for a shared_ptr for the diff class.
Definition: abg-fwd.h:78
void show_linkage_name_and_aliases(ostream &out, const string &indent, const elf_symbol &symbol, const string_elf_symbols_map_type &sym_map)
For a given symbol, emit a string made of its name and version. The string also contains the list of ...
vector< diff * > diff_ptrs_type
Convenience typedef for a vector of diff*.
void maybe_report_interfaces_impacted_by_diff(const diff *d, ostream &out, const string &indent)
If a given diff node impacts some public interfaces, then report about those impacted interfaces on a...
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...
@ 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...
@ 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 ...
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...
void maybe_report_diff_for_symbol(const elf_symbol_sptr &symbol1, const elf_symbol_sptr &symbol2, const diff_context_sptr &ctxt, ostream &out, const string &indent)
Report the difference between two ELF symbols, if there is any.
void maybe_report_unreachable_type_changes(const corpus_diff &d, const corpus_diff::diff_stats &s, const string &indent, ostream &out)
Report changes about types that are not reachable from global functions and variables,...
shared_ptr< diff_context > diff_context_sptr
Convenience typedef for a shared pointer of diff_context.
Definition: abg-fwd.h:70
void report_size_and_alignment_changes(type_or_decl_base_sptr first, type_or_decl_base_sptr second, diff_context_sptr ctxt, ostream &out, const string &indent)
Report the size and alignment changes of a type.
bool report_loc_info(const type_or_decl_base_sptr &tod, const diff_context &ctxt, ostream &out)
shared_ptr< var_diff > var_diff_sptr
Convenience typedef for a shared pointer to a var_diff type.
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.
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...
void maybe_report_base_class_reordering(const class_diff &d, ostream &out, const string &indent)
Report about the base classes of a class having been re-ordered.
void represent_data_member(var_decl_sptr d, const diff_context_sptr &ctxt, ostream &out, const string &indent)
Stream a string representation for a data member.
void maybe_report_data_members_replaced_by_anon_dm(const class_or_union_diff &d, ostream &out, const string &indent)
Report about data members replaced by an anonymous data member without changing the overall bit-layou...
bool maybe_report_diff_for_member(const decl_base_sptr &decl1, const decl_base_sptr &decl2, const diff_context_sptr &ctxt, ostream &out, const string &indent)
Report the differences in access specifiers and static-ness for class members.
void sort_string_var_ptr_map(const string_var_ptr_map &map, vector< var_decl_sptr > &sorted)
Sort a map of string -> pointer to var_decl.
void report_mem_header(ostream &out, size_t number, size_t num_filtered, diff_kind k, const string &section_name, const string &indent)
Output the header preceding the the report for insertion/deletion/change of a part of a class....
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.
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...
const var_diff * is_var_diff(const diff *diff)
Test if a diff node is about differences between variables.
void sort_var_diffs(var_diff_sptrs_type &var_diffs)
Sort a vector of var_diff_sptr.
void report_name_size_and_alignment_changes(decl_base_sptr first, decl_base_sptr second, diff_context_sptr ctxt, ostream &out, const string &indent)
Report the name, size and alignment changes of a type.
void represent(const diff_context &ctxt, method_decl_sptr mem_fn, ostream &out)
Stream a string representation for a member function.
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc:6454
bool get_member_is_static(const decl_base &d)
Gets a flag saying if a class member is static or not.
Definition: abg-ir.cc:5575
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition: abg-fwd.h:269
ssize_t get_member_function_vtable_offset(const function_decl &f)
Get the vtable offset of a member function.
Definition: abg-ir.cc:6578
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition: abg-ir.cc:10759
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:926
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:11085
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:9280
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:193
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition: abg-fwd.h:256
shared_ptr< type_or_decl_base > type_or_decl_base_sptr
A convenience typedef for a shared_ptr to type_or_decl_base.
Definition: abg-fwd.h:120
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition: abg-ir.cc:6368
bool is_c_language(translation_unit::language l)
Test if a language enumerator designates the C language.
Definition: abg-ir.cc:1792
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6641
translation_unit * get_translation_unit(const type_or_decl_base &t)
Return the translation unit a declaration belongs to.
Definition: abg-ir.cc:10455
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition: abg-ir.cc:5613
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:11808
bool get_member_function_is_ctor(const function_decl &f)
Test whether a member function is a constructor.
Definition: abg-ir.cc:6395
Toplevel namespace for libabigail.