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-2023 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 fn_parm_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 fn_parm_diff& d,
266 ostream& out,
267 const string& indent) const
268{
269 if (!diff_to_be_reported(&d))
270 return;
271
272 ABG_ASSERT(diff_to_be_reported(d.type_diff().get()));
273
274 function_decl::parameter_sptr f = d.first_parameter();
275
276 out << indent
277 << "parameter " << f->get_index();
278
279 report_loc_info(f, *d.context(), out);
280
281 out << " of type '"
282 << f->get_type_pretty_representation()
283 << "' changed:\n";
284 d.type_diff()->report(out, indent + " ");
285}
286
287/// Report the changes carried by a @ref function_type_diff node.
288///
289/// @param out the output stream to report to.
290///
291/// @param indent the white space string to use for indentation.
292void
293leaf_reporter::report(const function_type_diff& d,
294 ostream& out,
295 const string& indent) const
296{
297 if (!diff_to_be_reported(&d))
298 return;
299
301
302 if (diff_to_be_reported(d.priv_->return_type_diff_.get()))
303 {
304 out << indent << "return type changed:\n";
305 d.priv_->return_type_diff_->report(out, indent + " ");
306 }
307
308 // Hmmh, the above was quick. Now report about function parameters;
309 //
310 // Report about the parameter types that have changed sub-types.
311 for (vector<fn_parm_diff_sptr>::const_iterator i =
312 d.priv_->sorted_subtype_changed_parms_.begin();
313 i != d.priv_->sorted_subtype_changed_parms_.end();
314 ++i)
315 {
316 diff_sptr dif = *i;
317 if (diff_to_be_reported(dif.get()))
318 dif->report(out, indent);
319 }
320}
321
322/// Report the changes carried by a @ref scope_diff node.
323///
324/// @param out the output stream to report to.
325///
326/// @param indent the white space string to use for indentation.
327void
328leaf_reporter::report(const scope_diff& d,
329 ostream& out,
330 const string& indent) const
331{
332 if (!d.to_be_reported())
333 return;
334
335 // Report changed types.
336 unsigned num_changed_types = d.changed_types().size();
337 if (num_changed_types)
338 out << indent << "changed types:\n";
339
340 for (diff_sptrs_type::const_iterator dif = d.changed_types().begin();
341 dif != d.changed_types().end();
342 ++dif)
343 {
344 if (!*dif || !diff_to_be_reported((*dif).get()))
345 continue;
346
347 out << indent << " '"
348 << (*dif)->first_subject()->get_pretty_representation()
349 << "' changed:\n";
350 (*dif)->report(out, indent + " ");
351 }
352
353 // Report changed decls
354 unsigned num_changed_decls = d.changed_decls().size();
355 if (num_changed_decls)
356 out << indent << "changed declarations:\n";
357
358 for (diff_sptrs_type::const_iterator dif= d.changed_decls().begin();
359 dif != d.changed_decls().end ();
360 ++dif)
361 {
362 if (!*dif || !diff_to_be_reported((*dif).get()))
363 continue;
364
365 out << indent << " '"
366 << (*dif)->first_subject()->get_pretty_representation()
367 << "' was changed to '"
368 << (*dif)->second_subject()->get_pretty_representation() << "'";
369 report_loc_info((*dif)->second_subject(), *d.context(), out);
370 out << ":\n";
371
372 (*dif)->report(out, indent + " ");
373 }
374
375 // Report removed types/decls
376 for (string_decl_base_sptr_map::const_iterator i =
377 d.priv_->deleted_types_.begin();
378 i != d.priv_->deleted_types_.end();
379 ++i)
380 out << indent
381 << " '"
382 << i->second->get_pretty_representation()
383 << "' was removed\n";
384
385 if (d.priv_->deleted_types_.size())
386 out << "\n";
387
388 for (string_decl_base_sptr_map::const_iterator i =
389 d.priv_->deleted_decls_.begin();
390 i != d.priv_->deleted_decls_.end();
391 ++i)
392 out << indent
393 << " '"
394 << i->second->get_pretty_representation()
395 << "' was removed\n";
396
397 if (d.priv_->deleted_decls_.size())
398 out << "\n";
399
400 // Report added types/decls
401 bool emitted = false;
402 for (string_decl_base_sptr_map::const_iterator i =
403 d.priv_->inserted_types_.begin();
404 i != d.priv_->inserted_types_.end();
405 ++i)
406 {
407 // Do not report about type_decl as these are usually built-in
408 // types.
409 if (dynamic_pointer_cast<type_decl>(i->second))
410 continue;
411 out << indent
412 << " '"
413 << i->second->get_pretty_representation()
414 << "' was added\n";
415 emitted = true;
416 }
417
418 if (emitted)
419 out << "\n";
420
421 emitted = false;
422 for (string_decl_base_sptr_map::const_iterator i =
423 d.priv_->inserted_decls_.begin();
424 i != d.priv_->inserted_decls_.end();
425 ++i)
426 {
427 // Do not report about type_decl as these are usually built-in
428 // types.
429 if (dynamic_pointer_cast<type_decl>(i->second))
430 continue;
431 out << indent
432 << " '"
433 << i->second->get_pretty_representation()
434 << "' was added\n";
435 emitted = true;
436 }
437
438 if (emitted)
439 out << "\n";
440}
441
442/// Report about the change carried by a @ref subrange_diff diff node
443/// in a serialized form.
444///
445/// @param d the diff node to consider.
446///
447/// @param out the output stream to report to.
448///
449/// @param indent the indentation string to use in the report.
450void
451leaf_reporter::report(const subrange_diff& d, std::ostream& out,
452 const std::string& indent) const
453{
454 if (!diff_to_be_reported(&d))
455 return;
456
457 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(d.first_subrange(),
458 d.second_subrange(),
459 "range type");
460
461 represent(d, d.context(), out,indent, /*local_only=*/true);
462
464}
465
466/// Report the changes carried by a @ref array_diff node.
467///
468/// @param out the output stream to report to.
469///
470/// @param indent the white space string to use for indentation.
471void
472leaf_reporter::report(const array_diff& d,
473 ostream& out,
474 const string& indent) const
475{
476 if (!diff_to_be_reported(&d))
477 return;
478
479 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(d.first_array(),
480 d.second_array(),
481 "array type");
482
484 d.second_array(),
485 d.context(),
486 out, indent);
487
489 if (diff_to_be_reported(dif.get()))
490 {
491 string fn = ir::get_pretty_representation(is_type(dif->first_subject()));
492 // report array element type changes
493 out << indent << "array element type '"
494 << fn << "' changed: \n";
495 dif->report(out, indent + " ");
496 }
497
499}
500
501/// Report the changes carried by a @ref class_or_union_diff node.
502///
503/// @param out the output stream to report to.
504///
505/// @param indent the white space string to use for indentation.
506void
507leaf_reporter::report(const class_or_union_diff& d,
508 ostream& out,
509 const string& indent) const
510{
511 if (!diff_to_be_reported(&d))
512 return;
513
514 class_or_union_sptr first = d.first_class_or_union(),
515 second = d.second_class_or_union();
516
517 const diff_context_sptr& ctxt = d.context();
518
519 // Report class decl-only -> definition change.
520 if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
522 {
523 string was =
524 first->get_is_declaration_only()
525 ? " was a declaration-only type"
526 : " was a defined type";
527
528 string is_now =
529 second->get_is_declaration_only()
530 ? " and is now a declaration-only type"
531 : " and is now a defined type";
532
533 out << indent << "type " << first->get_pretty_representation()
534 << was << is_now << "\n";
535 return;
536 }
537
538 // member functions
539 if (d.member_fns_changes())
540 {
541 // report deletions
542 int numdels = d.get_priv()->deleted_member_functions_.size();
543 size_t num_filtered =
544 d.get_priv()->count_filtered_deleted_mem_fns(ctxt);
545 if (numdels)
546 report_mem_header(out, numdels, num_filtered, del_kind,
547 "member function", indent);
548 for (string_member_function_sptr_map::const_iterator i =
549 d.get_priv()->deleted_member_functions_.begin();
550 i != d.get_priv()->deleted_member_functions_.end();
551 ++i)
552 {
553 if (!(ctxt->get_allowed_category()
555 && !get_member_function_is_virtual(i->second))
556 continue;
557
558 method_decl_sptr mem_fun = i->second;
559 out << indent << " ";
560 represent(*ctxt, mem_fun, out);
561 }
562
563 // report insertions;
564 int numins = d.get_priv()->inserted_member_functions_.size();
565 num_filtered = d.get_priv()->count_filtered_inserted_mem_fns(ctxt);
566 if (numins)
567 report_mem_header(out, numins, num_filtered, ins_kind,
568 "member function", indent);
569 for (string_member_function_sptr_map::const_iterator i =
570 d.get_priv()->inserted_member_functions_.begin();
571 i != d.get_priv()->inserted_member_functions_.end();
572 ++i)
573 {
574 if (!(ctxt->get_allowed_category()
576 && !get_member_function_is_virtual(i->second))
577 continue;
578
579 method_decl_sptr mem_fun = i->second;
580 out << indent << " ";
581 represent(*ctxt, mem_fun, out);
582 }
583
584 // report member function with sub-types changes
585 int numchanges = d.get_priv()->sorted_changed_member_functions_.size();
586 if (numchanges)
587 report_mem_header(out, change_kind, "member function", indent);
588 for (function_decl_diff_sptrs_type::const_iterator i =
589 d.get_priv()->sorted_changed_member_functions_.begin();
590 i != d.get_priv()->sorted_changed_member_functions_.end();
591 ++i)
592 {
593 if (!(ctxt->get_allowed_category()
596 ((*i)->first_function_decl()))
598 ((*i)->second_function_decl())))
599 continue;
600
601 diff_sptr diff = *i;
602 if (!diff_to_be_reported(diff.get()))
603 continue;
604
605 string repr =
606 (*i)->first_function_decl()->get_pretty_representation();
607 out << indent << " '" << repr << "' has some changes:\n";
608 diff->report(out, indent + " ");
609 }
610 }
611
612 // data members
613 if (d.data_members_changes())
614 {
615 // report deletions
616 int numdels = d.class_or_union_diff::get_priv()->
617 get_deleted_non_static_data_members_number();
618 if (numdels)
619 {
620 report_mem_header(out, numdels, 0, del_kind,
621 "data member", indent);
622 vector<decl_base_sptr> sorted_dms;
624 (d.class_or_union_diff::get_priv()->deleted_data_members_,
625 sorted_dms);
626 for (vector<decl_base_sptr>::const_iterator i = sorted_dms.begin();
627 i != sorted_dms.end();
628 ++i)
629 {
630 var_decl_sptr data_mem =
631 dynamic_pointer_cast<var_decl>(*i);
632 ABG_ASSERT(data_mem);
633 if (get_member_is_static(data_mem))
634 continue;
635 represent_data_member(data_mem, ctxt, out, indent + " ");
636 }
637 }
638
639 //report insertions
640 int numins =
641 d.class_or_union_diff::get_priv()->inserted_data_members_.size();
642 if (numins)
643 {
644 report_mem_header(out, numins, 0, ins_kind,
645 "data member", indent);
646 vector<decl_base_sptr> sorted_dms;
648 (d.class_or_union_diff::get_priv()->inserted_data_members_,
649 sorted_dms);
650 for (vector<decl_base_sptr>::const_iterator i = sorted_dms.begin();
651 i != sorted_dms.end();
652 ++i)
653 {
654 var_decl_sptr data_mem =
655 dynamic_pointer_cast<var_decl>(*i);
656 ABG_ASSERT(data_mem);
657 represent_data_member(data_mem, ctxt, out, indent + " ");
658 }
659 }
660
661 // report changes
662 size_t numchanges = (d.sorted_changed_data_members().size()
663 + d.sorted_subtype_changed_data_members().size());
664
665 size_t num_filtered =
666 (d.count_filtered_changed_data_members(/*local_only=*/true)
667 + d.count_filtered_subtype_changed_data_members(/*local_only=*/true));
668
669 ABG_ASSERT(numchanges >= num_filtered);
670 size_t net_numchanges = numchanges - num_filtered;
671
672 if (net_numchanges)
673 {
674 report_mem_header(out, change_kind, "data member", indent);
675
676 for (var_diff_sptrs_type::const_iterator it =
677 d.sorted_changed_data_members().begin();
678 it != d.sorted_changed_data_members().end();
679 ++it)
680 if (diff_to_be_reported((*it).get()))
681 represent(*it, ctxt, out, indent + " ", /*local_only=*/true);
682
683 for (var_diff_sptrs_type::const_iterator it =
684 d.sorted_subtype_changed_data_members().begin();
685 it != d.sorted_subtype_changed_data_members().end();
686 ++it)
687 if (diff_to_be_reported((*it).get()))
688 represent(*it, ctxt, out, indent + " ", /*local_only=*/true);
689 }
690
691 // Report about data members replaced by an anonymous union data
692 // member.
694 }
695}
696
697/// Report the changes carried by a @ref class_diff node.
698///
699/// @param out the output stream to report to.
700///
701/// @param indent the white space string to use for indentation.
702void
703leaf_reporter::report(const class_diff& d,
704 ostream& out,
705 const string& indent) const
706{
707 if (!diff_to_be_reported(&d))
708 return;
709
710 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_subject(),
711 d.second_subject());
712
713 string name = d.first_subject()->get_pretty_representation();
714
715 // Now report the changes about the differents parts of the type.
716 class_decl_sptr first = d.first_class_decl(),
717 second = d.second_class_decl();
718
719 report_name_size_and_alignment_changes(first, second, d.context(),
720 out, indent);
721
722 const diff_context_sptr& ctxt = d.context();
723 maybe_report_diff_for_member(first, second, ctxt, out, indent);
724
725 d.class_or_union_diff::report(out, indent);
726
728
730
731 d.reported_once(true);
732}
733
734/// Report the changes carried by a @ref union_diff node.
735///
736/// @param out the output stream to report to.
737///
738/// @param indent the white space string to use for indentation.
739void
740leaf_reporter::report(const union_diff& d,
741 ostream& out,
742 const string& indent) const
743{
744 if (!diff_to_be_reported(&d))
745 return;
746
747 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_subject(),
748 d.second_subject());
749
750 // Now report the changes about the differents parts of the type.
751 union_decl_sptr first = d.first_union_decl(), second = d.second_union_decl();
752
753 report_name_size_and_alignment_changes(first, second, d.context(),
754 out, indent);
755
756 maybe_report_diff_for_member(first, second,d. context(), out, indent);
757
758 d.class_or_union_diff::report(out, indent);
759
761}
762
763/// Report the changes carried by a @ref distinct_diff node.
764///
765/// @param out the output stream to report to.
766///
767/// @param indent the white space string to use for indentation.
768void
769leaf_reporter::report(const distinct_diff& d,
770 ostream& out,
771 const string& indent) const
772{
773 if (!diff_to_be_reported(&d))
774 return;
775
776 type_or_decl_base_sptr f = d.first(), s = d.second();
777
778 string f_repr = f ? f->get_pretty_representation() : "'void'";
779 string s_repr = s ? s->get_pretty_representation() : "'void'";
780
781 diff_sptr diff = d.compatible_child_diff();
782
783 string compatible = diff ? " to compatible type '": " to '";
784
785 out << indent << "entity changed from '" << f_repr << "'"
786 << compatible << s_repr << "'";
787 report_loc_info(s, *d.context(), out);
788 out << "\n";
789
790 report_size_and_alignment_changes(f, s, d.context(), out, indent);
792}
793
794/// Report the changes carried by a @ref function_decl_diff node.
795///
796/// @param out the output stream to report to.
797///
798/// @param indent the white space string to use for indentation.
799void
800leaf_reporter::report(const function_decl_diff& d,
801 ostream& out,
802 const string& indent) const
803{
804 if (!diff_to_be_reported(&d))
805 return;
806
807 maybe_report_diff_for_member(d.first_function_decl(),
808 d.second_function_decl(),
809 d.context(), out, indent);
810
811 function_decl_sptr ff = d.first_function_decl();
812 function_decl_sptr sf = d.second_function_decl();
813
814 diff_context_sptr ctxt = d.context();
815 corpus_sptr fc = ctxt->get_corpus_diff()->first_corpus();
816 corpus_sptr sc = ctxt->get_corpus_diff()->second_corpus();
817
818 string qn1 = ff->get_qualified_name(), qn2 = sf->get_qualified_name(),
819 linkage_names1, linkage_names2;
820 elf_symbol_sptr s1 = ff->get_symbol(), s2 = sf->get_symbol();
821
822 if (s1)
823 linkage_names1 = s1->get_id_string();
824 if (s2)
825 linkage_names2 = s2->get_id_string();
826
827 // If the symbols for ff and sf have aliases, get all the names of
828 // the aliases;
829 if (fc && s1)
830 linkage_names1 =
831 s1->get_aliases_id_string(fc->get_fun_symbol_map());
832 if (sc && s2)
833 linkage_names2 =
834 s2->get_aliases_id_string(sc->get_fun_symbol_map());
835
836 /// If the set of linkage names of the function have changed, report
837 /// it.
838 if (linkage_names1 != linkage_names2)
839 {
840 if (linkage_names1.empty())
841 {
842 out << indent << ff->get_pretty_representation()
843 << " didn't have any linkage name, and it now has: '"
844 << linkage_names2 << "'\n";
845 }
846 else if (linkage_names2.empty())
847 {
848 out << indent << ff->get_pretty_representation()
849 << " did have linkage names '" << linkage_names1
850 << "'\n"
851 << indent << "but it doesn't have any linkage name anymore\n";
852 }
853 else
854 out << indent << "linkage names of "
855 << ff->get_pretty_representation()
856 << "\n" << indent << "changed from '"
857 << linkage_names1 << "' to '" << linkage_names2 << "'\n";
858 }
859
860 if (qn1 != qn2
861 && diff_to_be_reported(d.type_diff().get()))
862 {
863 // So the function has sub-type changes that are to be
864 // reported. Let's see if the function name changed too; if it
865 // did, then we'd report that change right before reporting the
866 // sub-type changes.
867 string frep1 = d.first_function_decl()->get_pretty_representation(),
868 frep2 = d.second_function_decl()->get_pretty_representation();
869 out << indent << "'" << frep1 << " {" << linkage_names1<< "}"
870 << "' now becomes '"
871 << frep2 << " {" << linkage_names2 << "}" << "'\n";
872 }
873
874 maybe_report_diff_for_symbol(ff->get_symbol(),
875 sf->get_symbol(),
876 ctxt, out, indent);
877
878 // Now report about inline-ness changes
879 if (ff->is_declared_inline() != sf->is_declared_inline())
880 {
881 out << indent;
882 if (ff->is_declared_inline())
883 out << sf->get_pretty_representation()
884 << " is not declared inline anymore\n";
885 else
886 out << sf->get_pretty_representation()
887 << " is now declared inline\n";
888 }
889
890 // Report about vtable offset changes.
892 {
893 bool ff_is_virtual = get_member_function_is_virtual(ff),
894 sf_is_virtual = get_member_function_is_virtual(sf);
895 if (ff_is_virtual != sf_is_virtual)
896 {
897 out << indent;
898 if (ff_is_virtual)
899 out << ff->get_pretty_representation()
900 << " is no more declared virtual\n";
901 else
902 out << ff->get_pretty_representation()
903 << " is now declared virtual\n";
904 }
905
906 size_t ff_vtable_offset = get_member_function_vtable_offset(ff),
907 sf_vtable_offset = get_member_function_vtable_offset(sf);
908 if (ff_is_virtual && sf_is_virtual
909 && (ff_vtable_offset != sf_vtable_offset))
910 {
911 out << indent
912 << "the vtable offset of " << ff->get_pretty_representation()
913 << " changed from " << ff_vtable_offset
914 << " to " << sf_vtable_offset << "\n";
915 }
916
917 // the classes of the two member functions.
918 class_decl_sptr fc =
919 is_class_type(is_method_type(ff->get_type())->get_class_type());
920 class_decl_sptr sc =
921 is_class_type(is_method_type(sf->get_type())->get_class_type());
922
923 // Detect if the virtual member function changes above
924 // introduced a vtable change or not.
925 bool vtable_added = false, vtable_removed = false;
926 if (!fc->get_is_declaration_only() && !sc->get_is_declaration_only())
927 {
928 vtable_added = !fc->has_vtable() && sc->has_vtable();
929 vtable_removed = fc->has_vtable() && !sc->has_vtable();
930 }
931 bool vtable_changed = ((ff_is_virtual != sf_is_virtual)
932 || (ff_vtable_offset != sf_vtable_offset));
933 bool incompatible_change = (ff_vtable_offset != sf_vtable_offset);
934
935 if (vtable_added)
936 out << indent
937 << " note that a vtable was added to "
938 << fc->get_pretty_representation()
939 << "\n";
940 else if (vtable_removed)
941 out << indent
942 << " note that the vtable was removed from "
943 << fc->get_pretty_representation()
944 << "\n";
945 else if (vtable_changed)
946 {
947 out << indent;
948 if (incompatible_change)
949 out << " note that this is an ABI incompatible "
950 "change to the vtable of ";
951 else
952 out << " note that this induces a change to the vtable of ";
953 out << fc->get_pretty_representation()
954 << "\n";
955 }
956
957 }
958
959 // Report about function type differences.
960 if (diff_to_be_reported(d.type_diff().get()))
961 d.type_diff()->report(out, indent);
962}
963
964/// Report the changes carried by a @ref var_diff node.
965///
966/// @param out the output stream to report to.
967///
968/// @param indent the white space string to use for indentation.
969void
970leaf_reporter::report(const var_diff& d,
971 ostream& out,
972 const string& indent) const
973{
974 if (!diff_to_be_reported(&d))
975 return;
976
977 decl_base_sptr first = d.first_var(), second = d.second_var();
978 string n = first->get_pretty_representation();
979
981 d.context(),
982 out, indent);
983
984 maybe_report_diff_for_symbol(d.first_var()->get_symbol(),
985 d.second_var()->get_symbol(),
986 d.context(), out, indent);
987
988 maybe_report_diff_for_member(first, second, d.context(), out, indent);
989
990 if (diff_sptr dif = d.type_diff())
991 {
992 if (diff_to_be_reported(dif.get()))
993 {
994 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(dif, "type");
995 out << indent << "type of variable changed:\n";
996 dif->report(out, indent + " ");
997 }
998 }
999}
1000
1001/// Report the changes carried by a @ref translation_unit_diff node.
1002///
1003/// @param out the output stream to report to.
1004///
1005/// @param indent the white space string to use for indentation.
1006void
1007leaf_reporter::report(const translation_unit_diff& d,
1008 ostream& out,
1009 const string& indent) const
1010{
1011 if (!d.to_be_reported())
1012 return;
1013
1014 static_cast<const scope_diff&>(d).report(out, indent);
1015}
1016
1017/// Report the changes carried by a @ref corpus_diff node.
1018///
1019/// @param out the output stream to report to.
1020///
1021/// @param indent the white space string to use for indentation.
1022void
1023leaf_reporter::report(const corpus_diff& d,
1024 ostream& out,
1025 const string& indent) const
1026{
1027 if (!d.has_changes())
1028 return;
1029
1030 const corpus_diff::diff_stats &s =
1031 const_cast<corpus_diff&>(d).
1032 apply_filters_and_suppressions_before_reporting();
1033
1034 const diff_context_sptr& ctxt = d.context();
1035
1036 d.priv_->emit_diff_stats(s, out, indent);
1037 if (ctxt->show_stats_only())
1038 return;
1039 out << "\n";
1040
1041 if (ctxt->show_soname_change()
1042 && !d.priv_->sonames_equal_)
1043 out << indent << "SONAME changed from '"
1044 << d.first_corpus()->get_soname() << "' to '"
1045 << d.second_corpus()->get_soname() << "'\n\n";
1046
1047 if (ctxt->show_architecture_change()
1048 && !d.priv_->architectures_equal_)
1049 out << indent << "architecture changed from '"
1050 << d.first_corpus()->get_architecture_name() << "' to '"
1051 << d.second_corpus()->get_architecture_name() << "'\n\n";
1052
1053 /// Report removed/added/changed functions.
1054 if (ctxt->show_deleted_fns())
1055 {
1056 if (s.net_num_func_removed() == 1)
1057 out << indent << "1 Removed function:\n\n";
1058 else if (s.net_num_func_removed() > 1)
1059 out << indent << s.net_num_func_removed() << " Removed functions:\n\n";
1060
1061 bool emitted = false;
1062 vector<function_decl*>sorted_deleted_fns;
1063 sort_string_function_ptr_map(d.priv_->deleted_fns_, sorted_deleted_fns);
1064 for (vector<function_decl*>::const_iterator i =
1065 sorted_deleted_fns.begin();
1066 i != sorted_deleted_fns.end();
1067 ++i)
1068 {
1069 if (d.priv_->deleted_function_is_suppressed(*i))
1070 continue;
1071
1072 out << indent
1073 << " ";
1074 out << "[D] ";
1075 out << "'" << (*i)->get_pretty_representation() << "'";
1076 if (ctxt->show_linkage_names())
1077 {
1078 out << " {";
1079 show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
1080 d.first_corpus()->get_fun_symbol_map());
1081 out << "}";
1082 }
1083 out << "\n";
1085 {
1086 class_decl_sptr c =
1087 is_class_type(is_method_type((*i)->get_type())->get_class_type());
1088 out << indent
1089 << " "
1090 << "note that this removes an entry from the vtable of "
1091 << c->get_pretty_representation()
1092 << "\n";
1093 }
1094 emitted = true;
1095 }
1096 if (emitted)
1097 out << "\n";
1098 }
1099
1100 if (ctxt->show_added_fns())
1101 {
1102 if (s.net_num_func_added() == 1)
1103 out << indent << "1 Added function:\n\n";
1104 else if (s.net_num_func_added() > 1)
1105 out << indent << s.net_num_func_added()
1106 << " Added functions:\n\n";
1107 bool emitted = false;
1108 vector<function_decl*> sorted_added_fns;
1109 sort_string_function_ptr_map(d.priv_->added_fns_, sorted_added_fns);
1110 for (vector<function_decl*>::const_iterator i = sorted_added_fns.begin();
1111 i != sorted_added_fns.end();
1112 ++i)
1113 {
1114 if (d.priv_->added_function_is_suppressed(*i))
1115 continue;
1116
1117 out
1118 << indent
1119 << " ";
1120 out << "[A] ";
1121 out << "'"
1122 << (*i)->get_pretty_representation()
1123 << "'";
1124 if (ctxt->show_linkage_names())
1125 {
1126 out << " {";
1128 (out, "", *(*i)->get_symbol(),
1129 d.second_corpus()->get_fun_symbol_map());
1130 out << "}";
1131 }
1132 out << "\n";
1134 {
1135 class_decl_sptr c =
1136 is_class_type(is_method_type((*i)->get_type())->get_class_type());
1137 out << indent
1138 << " "
1139 << "note that this adds a new entry to the vtable of "
1140 << c->get_pretty_representation()
1141 << "\n";
1142 }
1143 emitted = true;
1144 }
1145 if (emitted)
1146 out << "\n";
1147 }
1148
1149 if (ctxt->show_changed_fns())
1150 {
1151 // Show changed functions.
1152 size_t num_changed = s.net_num_leaf_func_changes();
1153 if (num_changed == 1)
1154 out << indent << "1 function with some sub-type change:\n\n";
1155 else if (num_changed > 1)
1156 out << indent << num_changed
1157 << " functions with some sub-type change:\n\n";
1158
1159 vector<function_decl_diff_sptr> sorted_changed_fns;
1160 sort_string_function_decl_diff_sptr_map(d.priv_->changed_fns_map_,
1161 sorted_changed_fns);
1162 for (vector<function_decl_diff_sptr>::const_iterator i =
1163 sorted_changed_fns.begin();
1164 i != sorted_changed_fns.end();
1165 ++i)
1166 {
1167 diff_sptr diff = *i;
1168 if (!diff)
1169 continue;
1170
1171 if (diff_to_be_reported(diff.get()))
1172 {
1173 function_decl_sptr fn = (*i)->first_function_decl();
1174 out << indent << " [C] '"
1175 << fn->get_pretty_representation() << "'";
1176 report_loc_info((*i)->second_function_decl(), *ctxt, out);
1177 out << " has some sub-type changes:\n";
1178 if ((fn->get_symbol()->has_aliases()
1179 && !(is_member_function(fn)
1181 && !(is_member_function(fn)
1183 || (is_c_language(get_translation_unit(fn)->get_language())
1184 && fn->get_name() != fn->get_linkage_name()))
1185 {
1186 int number_of_aliases =
1187 fn->get_symbol()->get_number_of_aliases();
1188 if (number_of_aliases == 0)
1189 {
1190 out << indent << " "
1191 << "Please note that the exported symbol of "
1192 "this function is "
1193 << fn->get_symbol()->get_id_string()
1194 << "\n";
1195 }
1196 else
1197 {
1198 out << indent << " "
1199 << "Please note that the symbol of this function is "
1200 << fn->get_symbol()->get_id_string()
1201 << "\n and it aliases symbol";
1202 if (number_of_aliases > 1)
1203 out << "s";
1204 out << ": "
1205 << fn->get_symbol()->get_aliases_id_string(false)
1206 << "\n";
1207 }
1208 }
1209 diff->report(out, indent + " ");
1210 // Extra spacing.
1211 out << "\n";
1212 }
1213 }
1214 // Changed functions have extra spacing already. No new line here.
1215 }
1216
1217 // Report removed/added/changed variables.
1218 if (ctxt->show_deleted_vars())
1219 {
1220 if (s.net_num_vars_removed() == 1)
1221 out << indent << "1 Removed variable:\n\n";
1222 else if (s.net_num_vars_removed() > 1)
1223 out << indent << s.net_num_vars_removed()
1224 << " Removed variables:\n\n";
1225 string n;
1226 bool emitted = false;
1227 vector<var_decl*> sorted_deleted_vars;
1228 sort_string_var_ptr_map(d.priv_->deleted_vars_, sorted_deleted_vars);
1229 for (vector<var_decl*>::const_iterator i =
1230 sorted_deleted_vars.begin();
1231 i != sorted_deleted_vars.end();
1232 ++i)
1233 {
1234 if (d.priv_->deleted_variable_is_suppressed(*i))
1235 continue;
1236
1237 n = (*i)->get_pretty_representation();
1238
1239 out << indent
1240 << " ";
1241 out << "[D] ";
1242 out << "'"
1243 << n
1244 << "'";
1245 if (ctxt->show_linkage_names())
1246 {
1247 out << " {";
1248 show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
1249 d.first_corpus()->get_var_symbol_map());
1250 out << "}";
1251 }
1252 out << "\n";
1253 emitted = true;
1254 }
1255 if (emitted)
1256 out << "\n";
1257 }
1258
1259 if (ctxt->show_added_vars())
1260 {
1261 if (s.net_num_vars_added() == 1)
1262 out << indent << "1 Added variable:\n\n";
1263 else if (s.net_num_vars_added() > 1)
1264 out << indent << s.net_num_vars_added()
1265 << " Added variables:\n\n";
1266 string n;
1267 bool emitted = false;
1268 vector<var_decl*> sorted_added_vars;
1269 sort_string_var_ptr_map(d.priv_->added_vars_, sorted_added_vars);
1270 for (vector<var_decl*>::const_iterator i =
1271 sorted_added_vars.begin();
1272 i != sorted_added_vars.end();
1273 ++i)
1274 {
1275 if (d.priv_->added_variable_is_suppressed(*i))
1276 continue;
1277
1278 n = (*i)->get_pretty_representation();
1279
1280 out << indent
1281 << " ";
1282 out << "[A] ";
1283 out << "'" << n << "'";
1284 if (ctxt->show_linkage_names())
1285 {
1286 out << " {";
1287 show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
1288 d.second_corpus()->get_var_symbol_map());
1289 out << "}";
1290 }
1291 out << "\n";
1292 emitted = true;
1293 }
1294 if (emitted)
1295 out << "\n";
1296 }
1297
1298 if (ctxt->show_changed_vars())
1299 {
1300 size_t num_changed = s.net_num_leaf_var_changes();
1301 if (num_changed == 1)
1302 out << indent << "1 Changed variable:\n\n";
1303 else if (num_changed > 1)
1304 out << indent << num_changed
1305 << " Changed variables:\n\n";
1306 string n1, n2;
1307 for (var_diff_sptrs_type::const_iterator i =
1308 d.priv_->sorted_changed_vars_.begin();
1309 i != d.priv_->sorted_changed_vars_.end();
1310 ++i)
1311 {
1312 diff_sptr diff = *i;
1313
1314 if (!diff)
1315 continue;
1316
1317 if (!diff_to_be_reported(diff.get()))
1318 continue;
1319
1320 n1 = diff->first_subject()->get_pretty_representation();
1321 n2 = diff->second_subject()->get_pretty_representation();
1322
1323 out << indent << " [C] '" << n1 << "' was changed";
1324 if (n1 != n2)
1325 out << " to '" << n2 << "'";
1326 report_loc_info(diff->second_subject(), *ctxt, out);
1327 out << ":\n";
1328 diff->report(out, indent + " ");
1329 // Extra spacing.
1330 out << "\n";
1331 }
1332 // Changed variables have extra spacing already. No new line here.
1333 }
1334
1335 // Report removed function symbols not referenced by any debug info.
1336 if (ctxt->show_symbols_unreferenced_by_debug_info()
1337 && d.priv_->deleted_unrefed_fn_syms_.size())
1338 {
1339 if (s.net_num_removed_func_syms() == 1)
1340 out << indent
1341 << "1 Removed function symbol not referenced by debug info:\n\n";
1342 else if (s.net_num_removed_func_syms() > 0)
1343 out << indent
1344 << s.net_num_removed_func_syms()
1345 << " Removed function symbols not referenced by debug info:\n\n";
1346
1347 bool emitted = false;
1348 vector<elf_symbol_sptr> sorted_deleted_unrefed_fn_syms;
1349 sort_string_elf_symbol_map(d.priv_->deleted_unrefed_fn_syms_,
1350 sorted_deleted_unrefed_fn_syms);
1351 for (vector<elf_symbol_sptr>::const_iterator i =
1352 sorted_deleted_unrefed_fn_syms.begin();
1353 i != sorted_deleted_unrefed_fn_syms.end();
1354 ++i)
1355 {
1356 if (d.priv_->deleted_unrefed_fn_sym_is_suppressed((*i).get()))
1357 continue;
1358
1359 out << indent << " ";
1360 out << "[D] ";
1361
1362 show_linkage_name_and_aliases(out, "", **i,
1363 d.first_corpus()->get_fun_symbol_map());
1364 out << "\n";
1365 emitted = true;
1366 }
1367 if (emitted)
1368 out << "\n";
1369 }
1370
1371 // Report added function symbols not referenced by any debug info.
1372 if (ctxt->show_symbols_unreferenced_by_debug_info()
1373 && ctxt->show_added_symbols_unreferenced_by_debug_info()
1374 && d.priv_->added_unrefed_fn_syms_.size())
1375 {
1376 if (s.net_num_added_func_syms() == 1)
1377 out << indent
1378 << "1 Added function symbol not referenced by debug info:\n\n";
1379 else if (s.net_num_added_func_syms() > 0)
1380 out << indent
1381 << s.net_num_added_func_syms()
1382 << " Added function symbols not referenced by debug info:\n\n";
1383
1384 bool emitted = false;
1385 vector<elf_symbol_sptr> sorted_added_unrefed_fn_syms;
1386 sort_string_elf_symbol_map(d.priv_->added_unrefed_fn_syms_,
1387 sorted_added_unrefed_fn_syms);
1388 for (vector<elf_symbol_sptr>::const_iterator i =
1389 sorted_added_unrefed_fn_syms.begin();
1390 i != sorted_added_unrefed_fn_syms.end();
1391 ++i)
1392 {
1393 if (d.priv_->added_unrefed_fn_sym_is_suppressed((*i).get()))
1394 continue;
1395
1396 out << indent << " ";
1397 out << "[A] ";
1399 **i,
1400 d.second_corpus()->get_fun_symbol_map());
1401 out << "\n";
1402 emitted = true;
1403 }
1404 if (emitted)
1405 out << "\n";
1406 }
1407
1408 // Report removed variable symbols not referenced by any debug info.
1409 if (ctxt->show_symbols_unreferenced_by_debug_info()
1410 && d.priv_->deleted_unrefed_var_syms_.size())
1411 {
1412 if (s.net_num_removed_var_syms() == 1)
1413 out << indent
1414 << "1 Removed variable symbol not referenced by debug info:\n\n";
1415 else if (s.net_num_removed_var_syms() > 0)
1416 out << indent
1417 << s.net_num_removed_var_syms()
1418 << " Removed variable symbols not referenced by debug info:\n\n";
1419
1420 bool emitted = false;
1421 vector<elf_symbol_sptr> sorted_deleted_unrefed_var_syms;
1422 sort_string_elf_symbol_map(d.priv_->deleted_unrefed_var_syms_,
1423 sorted_deleted_unrefed_var_syms);
1424 for (vector<elf_symbol_sptr>::const_iterator i =
1425 sorted_deleted_unrefed_var_syms.begin();
1426 i != sorted_deleted_unrefed_var_syms.end();
1427 ++i)
1428 {
1429 if (d.priv_->deleted_unrefed_var_sym_is_suppressed((*i).get()))
1430 continue;
1431
1432 out << indent << " ";
1433 out << "[D] ";
1434
1436 (out, "", **i,
1437 d.first_corpus()->get_fun_symbol_map());
1438
1439 out << "\n";
1440 emitted = true;
1441 }
1442 if (emitted)
1443 out << "\n";
1444 }
1445
1446 // Report added variable symbols not referenced by any debug info.
1447 if (ctxt->show_symbols_unreferenced_by_debug_info()
1448 && ctxt->show_added_symbols_unreferenced_by_debug_info()
1449 && d.priv_->added_unrefed_var_syms_.size())
1450 {
1451 if (s.net_num_added_var_syms() == 1)
1452 out << indent
1453 << "1 Added variable symbol not referenced by debug info:\n\n";
1454 else if (s.net_num_added_var_syms() > 0)
1455 out << indent
1456 << s.net_num_added_var_syms()
1457 << " Added variable symbols not referenced by debug info:\n\n";
1458
1459 bool emitted = false;
1460 vector<elf_symbol_sptr> sorted_added_unrefed_var_syms;
1461 sort_string_elf_symbol_map(d.priv_->added_unrefed_var_syms_,
1462 sorted_added_unrefed_var_syms);
1463 for (vector<elf_symbol_sptr>::const_iterator i =
1464 sorted_added_unrefed_var_syms.begin();
1465 i != sorted_added_unrefed_var_syms.end();
1466 ++i)
1467 {
1468 if (d.priv_->added_unrefed_var_sym_is_suppressed((*i).get()))
1469 continue;
1470
1471 out << indent << " ";
1472 out << "[A] ";
1473 show_linkage_name_and_aliases(out, "", **i,
1474 d.second_corpus()->get_fun_symbol_map());
1475 out << "\n";
1476 emitted = true;
1477 }
1478 if (emitted)
1479 out << "\n";
1480 }
1481
1482 // Now show the changed types.
1483 const diff_maps& leaf_diffs = d.get_leaf_diffs();
1484 report_type_changes_from_diff_maps(*this, leaf_diffs, out, indent);
1485
1486 // Report added/removed/changed types not reacheable from public
1487 // interfaces.
1488 maybe_report_unreachable_type_changes(d, s, indent, out);
1489
1490 d.priv_->maybe_dump_diff_tree();
1491}
1492} // end namespace comparison
1493} // 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:1612
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_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.
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.
Abstraction of a diff between two qualified types.
The base class of all the reporting classes.
Definition: abg-reporter.h:57
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.
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3057
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...
shared_ptr< diff > diff_sptr
Convenience typedef for a shared_ptr for the diff class.
Definition: abg-fwd.h:79
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 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 sort_string_var_ptr_map(const string_var_ptr_map &map, vector< var_decl * > &sorted)
Sort a map of string -> pointer to var_decl.
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:71
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)
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 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 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.
void sort_string_function_ptr_map(const string_function_ptr_map &map, vector< function_decl * > &sorted)
Sort an instance of string_function_ptr_map map and stuff a resulting sorted vector of pointers to fu...
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc:6487
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:5717
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition: abg-fwd.h:266
ssize_t get_member_function_vtable_offset(const function_decl &f)
Get the vtable offset of a member function.
Definition: abg-ir.cc:6611
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition: abg-ir.cc:10248
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:874
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:10512
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:9198
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:190
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition: abg-fwd.h:249
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
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition: abg-ir.cc:6401
bool is_c_language(translation_unit::language l)
Test if a language enumerator designates the C language.
Definition: abg-ir.cc:1637
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6674
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition: abg-ir.cc:5755
translation_unit * get_translation_unit(const decl_base &decl)
Return the translation unit a declaration belongs to.
Definition: abg-ir.cc:9964
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:10913
bool get_member_function_is_ctor(const function_decl &f)
Test whether a member function is a constructor.
Definition: abg-ir.cc:6428
Toplevel namespace for libabigail.