libabigail
abg-default-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 given instance of @ref corpus_diff carries changes whose
24/// reports are not suppressed by any suppression specification. In
25/// effect, these are deemed incompatible ABI changes.
26///
27/// @param d the @ref corpus_diff to consider
28///
29/// @return true iff @p d carries subtype changes that are deemed
30/// incompatible ABI changes.
31bool
33{
34 if (!d)
35 return false;
36
37 const corpus_diff::diff_stats& stats = const_cast<corpus_diff*>(d)->
38 apply_filters_and_suppressions_before_reporting();
39
40 // Logic here should match emit_diff_stats.
41 return (d->architecture_changed()
42 || d->soname_changed()
43 || stats.net_num_func_removed()
44 || stats.net_num_func_changed()
45 || stats.net_num_func_added()
46 || stats.net_num_vars_removed()
47 || stats.net_num_vars_changed()
48 || stats.net_num_vars_added()
55 || stats.net_num_added_var_syms());
56}
57
58/// Ouputs a report of the differences between of the two type_decl
59/// involved in the @ref type_decl_diff.
60///
61/// @param d the @ref type_decl_diff to consider.
62///
63/// @param out the output stream to emit the report to.
64///
65/// @param indent the string to use for indentatino indent.
66void
67default_reporter::report(const type_decl_diff& d,
68 ostream& out,
69 const string& indent) const
70{
71 if (!d.to_be_reported())
72 return;
73
75
76 string name = f->get_pretty_representation();
77
79 out, indent);
80
81 if (f->get_visibility() != s->get_visibility())
82 {
83 out << indent
84 << "visibility changed from '"
85 << f->get_visibility() << "' to '" << s->get_visibility()
86 << "\n";
87 }
88
89 if (f->get_linkage_name() != s->get_linkage_name())
90 {
91 out << indent
92 << "mangled name changed from '"
93 << f->get_linkage_name() << "' to "
94 << s->get_linkage_name()
95 << "\n";
96 }
97}
98
99/// Report the differences between the two enums.
100///
101/// @param d the enum diff to consider.
102///
103/// @param out the output stream to send the report to.
104///
105/// @param indent the string to use for indentation.
106void
107default_reporter::report(const enum_diff& d, ostream& out,
108 const string& indent) const
109{
110 if (!d.to_be_reported())
111 return;
112
113 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(d.first_subject(),
114 d.second_subject(),
115 "enum type");
116
117 string name = d.first_enum()->get_pretty_representation();
118
119 enum_type_decl_sptr first = d.first_enum(), second = d.second_enum();
120
121 const diff_context_sptr& ctxt = d.context();
122
123 // Report enum decl-only <-> definition changes.
124 if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
126 {
127 string was =
128 first->get_is_declaration_only()
129 ? " was a declaration-only enum type"
130 : " was a defined enum type";
131
132 string is_now =
133 second->get_is_declaration_only()
134 ? " and is now a declaration-only enum type"
135 : " and is now a defined enum type";
136
137 out << indent << "enum type " << name << was << is_now << "\n";
138 return;
139 }
140
141 report_name_size_and_alignment_changes(first, second, ctxt,
142 out, indent);
143 maybe_report_diff_for_member(first, second, ctxt, out, indent);
144
145 //underlying type
146 d.underlying_type_diff()->report(out, indent);
147
148 //report deletions/insertions/change of enumerators
149 unsigned numdels = d.deleted_enumerators().size();
150 unsigned numins = d.inserted_enumerators().size();
151 unsigned numchanges = d.changed_enumerators().size();
152
153 if (numdels)
154 {
155 report_mem_header(out, numdels, 0, del_kind, "enumerator", indent);
156 enum_type_decl::enumerators sorted_deleted_enumerators;
157 sort_enumerators(d.deleted_enumerators(), sorted_deleted_enumerators);
158 for (enum_type_decl::enumerators::const_iterator i =
159 sorted_deleted_enumerators.begin();
160 i != sorted_deleted_enumerators.end();
161 ++i)
162 {
163 out << indent
164 << " '"
165 << i->get_qualified_name()
166 << "' value '"
167 << i->get_value()
168 << "'";
169 out << "\n";
170 }
171 }
172 if (numins)
173 {
174 report_mem_header(out, numins, 0, ins_kind, "enumerator", indent);
175 enum_type_decl::enumerators sorted_inserted_enumerators;
176 sort_enumerators(d.inserted_enumerators(), sorted_inserted_enumerators);
177 for (enum_type_decl::enumerators::const_iterator i =
178 sorted_inserted_enumerators.begin();
179 i != sorted_inserted_enumerators.end();
180 ++i)
181 {
182 out << indent
183 << " '"
184 << i->get_qualified_name()
185 << "' value '"
186 << i->get_value()
187 << "'";
188 out << "\n";
189 }
190 }
191 if (numchanges)
192 {
193 report_mem_header(out, numchanges, 0, change_kind, "enumerator", indent);
194 changed_enumerators_type sorted_changed_enumerators;
195 sort_changed_enumerators(d.changed_enumerators(),
196 sorted_changed_enumerators);
197 for (changed_enumerators_type::const_iterator i =
198 sorted_changed_enumerators.begin();
199 i != sorted_changed_enumerators.end();
200 ++i)
201 {
202 out << indent
203 << " '"
204 << i->first.get_qualified_name()
205 << "' from value '"
206 << i->first.get_value() << "' to '"
207 << i->second.get_value() << "'";
208 report_loc_info(second, *ctxt, out);
209 out << "\n";
210 }
211 }
212
213 if (ctxt->show_leaf_changes_only())
215
216 d.reported_once(true);
217}
218
219/// For a @ref typedef_diff node, report the local changes to the
220/// typedef rather the changes to its underlying type.
221///
222/// Note that changes to the underlying type are also considered
223/// local.
224///
225/// @param d the @ref typedef_diff node to consider.
226///
227/// @param out the output stream to report to.
228///
229/// @param indent the white space string to use for indentation.
230void
232 ostream& out,
233 const string& indent) const
234{
235 if (!d.to_be_reported())
236 return;
237
239
240 maybe_report_diff_for_member(f, s, d.context(), out, indent);
241
243 && ((d.context()->get_allowed_category()
245 || d.context()->show_leaf_changes_only()))
246 || f->get_qualified_name() != s->get_qualified_name())
247 {
248 out << indent << "typedef name changed from "
249 << f->get_qualified_name()
250 << " to "
251 << s->get_qualified_name();
252 report_loc_info(s, *d.context(), out);
253 out << "\n";
254 }
255}
256
257/// Reports the difference between the two subjects of the diff in a
258/// serialized form.
259///
260/// @param d @ref typedef_diff node to consider.
261///
262/// @param out the output stream to emit the report to.
263///
264/// @param indent the indentation string to use.
265void
266default_reporter::report(const typedef_diff& d,
267 ostream& out,
268 const string& indent) const
269{
270 if (!d.to_be_reported())
271 return;
272
274
276 report_non_type_typedef_changes(d, out, indent);
277
279 if (dif && dif->has_changes())
280 {
281 if (dif->to_be_reported())
282 {
283 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(dif,
284 "underlying type");
285 out << indent
286 << "underlying type '"
287 << dif->first_subject()->get_pretty_representation() << "'";
288 report_loc_info(dif->first_subject(), *d.context(), out);
289 out << " changed:\n";
290 dif->report(out, indent + " ");
291 }
292 else
293 {
294 // The typedef change is to be reported, so we'll report its
295 // underlying type change too (even if its redundant),
296 // unless it's suppressed. It makes sense in this
297 // particular case to emit the underlying type change
298 // because of the informative value underneath. We don't
299 // want to just know about the local changes of the typedef,
300 // but also about the changes on the underlying type.
301 diff_category c = dif->get_category();
303 {
304 out << indent
305 << "underlying type '"
306 << dif->first_subject()->get_pretty_representation() << "'";
307 report_loc_info(dif->first_subject(), *d.context(), out);
308 out << " changed:\n";
309 if (c & REDUNDANT_CATEGORY)
310 dif->set_category(c & ~REDUNDANT_CATEGORY);
311 dif->report(out, indent + " ");
312 if (c & REDUNDANT_CATEGORY)
313 dif->set_category(c | REDUNDANT_CATEGORY);
314 }
315 }
316 }
317
318 d.reported_once(true);
319}
320
321/// For a @ref qualified_type_diff node, report the changes that are
322/// local.
323///
324/// @param d the @ref qualified_type_diff node to consider.
325///
326/// @param out the output stream to emit the report to.
327///
328/// @param indent the white string to use for indentation.
329///
330/// @return true iff a local change has been emitted. In this case,
331/// the local change is a name change.
332bool
334 ostream& out,
335 const string& indent) const
336{
337 if (!d.to_be_reported())
338 return false;
339
340 string fname = d.first_qualified_type()->get_pretty_representation(),
341 sname = d.second_qualified_type()->get_pretty_representation();
342
343 if (fname != sname)
344 {
345 out << indent << "'" << fname << "' changed to '" << sname << "'\n";
346 return true;
347 }
348 return false;
349}
350
351/// For a @ref qualified_type_diff node, report the changes of its
352/// underlying type.
353///
354/// @param d the @ref qualified_type_diff node to consider.
355///
356/// @param out the output stream to emit the report to.
357///
358/// @param indent the white string to use for indentation.
359///
360/// @return true iff a local change has been emitted. In this case,
361/// the local change is a name change.
362void
364(const qualified_type_diff& d, ostream& out, const string& indent) const
365{
366 if (!d.to_be_reported())
367 return;
368
370 ABG_ASSERT(dif);
371 ABG_ASSERT(dif->to_be_reported());
372 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(dif,
373 "unqualified "
374 "underlying type");
375
376 string fltname = dif->first_subject()->get_pretty_representation();
377 out << indent << "in unqualified underlying type '" << fltname << "'";
378 report_loc_info(dif->second_subject(), *d.context(), out);
379 out << ":\n";
380 dif->report(out, indent + " ");
381}
382
383/// Report a @ref qualified_type_diff in a serialized form.
384///
385/// @param d the @ref qualified_type_diff node to consider.
386///
387/// @param out the output stream to serialize to.
388///
389/// @param indent the string to use to indent the lines of the report.
390void
391default_reporter::report(const qualified_type_diff& d, ostream& out,
392 const string& indent) const
393{
394 if (!d.to_be_reported())
395 return;
396
397 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_qualified_type(),
399
401 if (report_local_qualified_type_changes(d, out, indent))
402 // The local change was emitted and it's a name change. If the
403 // type name changed, the it means the type changed altogether.
404 // It makes a little sense to detail the changes in extenso here.
405 return;
406
408}
409
410/// Report the @ref pointer_diff in a serialized form.
411///
412/// @param d the @ref pointer_diff node to consider.
413///
414/// @param out the stream to serialize the diff to.
415///
416/// @param indent the prefix to use for the indentation of this
417/// serialization.
418void
419default_reporter::report(const pointer_diff& d, ostream& out,
420 const string& indent) const
421{
422 if (!d.to_be_reported())
423 return;
424
425 if (diff_sptr dif = d.underlying_type_diff())
426 {
427 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(dif, "pointed to type");
428 string repr = dif->first_subject()
429 ? dif->first_subject()->get_pretty_representation()
430 : string("void");
431
432 out << indent
433 << "in pointed to type '" << repr << "'";
434 report_loc_info(dif->second_subject(), *d.context(), out);
435 out << ":\n";
436 dif->report(out, indent + " ");
437 }
438}
439
440/// For a @reference_diff node, report the local changes carried by
441/// the diff node.
442///
443/// @param d the @reference_diff node to consider.
444///
445/// @param out the output stream to report to.
446///
447/// @param indent the white space indentation to use in the report.
448void
450 ostream& out,
451 const string& indent) const
452{
453 if (!d.to_be_reported())
454 return;
455
457 ABG_ASSERT(f && s);
458
459 string f_repr = f->get_pretty_representation(),
460 s_repr = s->get_pretty_representation();
461
462 if (f->is_lvalue() != s->is_lvalue())
463 {
464 out << indent;
465 if (f->is_lvalue())
466 out << "lvalue reference type '" << f_repr
467 << " became an rvalue reference type: '"
468 << s_repr
469 << "'\n";
470 else
471 out << "rvalue reference type '" << f_repr
472 << " became an lvalue reference type: '"
473 << s_repr
474 << "'\n";
475 }
476 else if (!types_have_similar_structure(f->get_pointed_to_type().get(),
477 s->get_pointed_to_type().get()))
478 out << indent
479 << "reference type changed from: '"
480 << f_repr << "' to: '" << s_repr << "'\n";
481}
482
483/// Report a @ref reference_diff in a serialized form.
484///
485/// @param d the @ref reference_diff node to consider.
486///
487/// @param out the output stream to serialize the dif to.
488///
489/// @param indent the string to use for indenting the report.
490void
491default_reporter::report(const reference_diff& d, ostream& out,
492 const string& indent) const
493{
494 if (!d.to_be_reported())
495 return;
496
497 enum change_kind k = ir::NO_CHANGE_KIND;
499
503
504 if (k & SUBTYPE_CHANGE_KIND)
505 if (diff_sptr dif = d.underlying_type_diff())
506 {
507 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(dif,
508 "referenced type");
509
510 out << indent
511 << "in referenced type '"
512 << dif->first_subject()->get_pretty_representation() << "'";
513 report_loc_info(dif->second_subject(), *d.context(), out);
514 out << ":\n";
515 dif->report(out, indent + " ");
516 }
517}
518
519/// Emit a textual report about the a @ref fn_parm_diff instance.
520///
521/// @param d the @ref fn_parm_diff to consider.
522///
523/// @param out the output stream to emit the textual report to.
524///
525/// @param indent the indentation string to use in the report.
526void
527default_reporter::report(const fn_parm_diff& d, ostream& out,
528 const string& indent) const
529{
530 if (!d.to_be_reported())
531 return;
532
533 function_decl::parameter_sptr f = d.first_parameter(),
534 s = d.second_parameter();
535
536 // either the parameter has a sub-type change (if its type name
537 // hasn't changed) or it has a "grey" change (that is, a change that
538 // changes his type name w/o changing the signature of the
539 // function).
540 bool has_sub_type_change =
541 type_has_sub_type_changes(d.first_parameter()->get_type(),
542 d.second_parameter()->get_type());
543
544 diff_sptr type_diff = d.type_diff();
545 ABG_ASSERT(type_diff->has_changes());
546
547 out << indent;
548 if (f->get_is_artificial())
549 out << "implicit ";
550 out << "parameter " << f->get_index();
551 report_loc_info(f, *d.context(), out);
552 out << " of type '"
553 << f->get_type_pretty_representation();
554
555 if (has_sub_type_change)
556 out << "' has sub-type changes:\n";
557 else
558 out << "' changed:\n";
559
560 type_diff->report(out, indent + " ");
561}
562
563/// For a @ref function_type_diff node, report the local changes
564/// carried by the diff node.
565///
566/// @param d the @ref function_type_diff node to consider.
567///
568/// @param out the output stream to report to.
569///
570/// @param indent the white space indentation string to use.
571void
573 ostream& out,
574 const string& indent) const
575
576{
577 if (!d.to_be_reported())
578 return;
579
582
583 diff_context_sptr ctxt = d.context();
584
585 // Report about the size of the function address
586 if (fft->get_size_in_bits() != sft->get_size_in_bits())
587 {
588 out << indent << "address size of function changed from "
589 << fft->get_size_in_bits()
590 << " bits to "
591 << sft->get_size_in_bits()
592 << " bits\n";
593 }
594
595 // Report about the alignment of the function address
596 if (fft->get_alignment_in_bits()
597 != sft->get_alignment_in_bits())
598 {
599 out << indent << "address alignment of function changed from "
600 << fft->get_alignment_in_bits()
601 << " bits to "
602 << sft->get_alignment_in_bits()
603 << " bits\n";
604 }
605
606 // Hmmh, the above was quick. Now report about function parameters;
607 // this shouldn't be as straightforward.
608
609 // Report about the parameters that got removed.
610 for (vector<function_decl::parameter_sptr>::const_iterator i =
611 d.priv_->sorted_deleted_parms_.begin();
612 i != d.priv_->sorted_deleted_parms_.end();
613 ++i)
614 {
615 out << indent << "parameter " << (*i)->get_index()
616 << " of type '" << (*i)->get_type_pretty_representation()
617 << "' was removed\n";
618 }
619
620 // Report about the parameters that got added
621 for (vector<function_decl::parameter_sptr>::const_iterator i =
622 d.priv_->sorted_added_parms_.begin();
623 i != d.priv_->sorted_added_parms_.end();
624 ++i)
625 {
626 out << indent << "parameter " << (*i)->get_index()
627 << " of type '" << (*i)->get_type_pretty_representation()
628 << "' was added\n";
629 }
630}
631
632/// Build and emit a textual report about a @ref function_type_diff.
633///
634/// @param d the @ref function_type_diff to consider.
635///
636/// @param out the output stream.
637///
638/// @param indent the indentation string to use.
639void
640default_reporter::report(const function_type_diff& d, ostream& out,
641 const string& indent) const
642{
643 if (!d.to_be_reported())
644 return;
645
648
649 diff_context_sptr ctxt = d.context();
650 corpus_sptr fc = ctxt->get_first_corpus();
651 corpus_sptr sc = ctxt->get_second_corpus();
652
653 // Report about return type differences.
654 if (d.priv_->return_type_diff_
655 && d.priv_->return_type_diff_->to_be_reported())
656 {
657 out << indent << "return type changed:\n";
658 d.priv_->return_type_diff_->report(out, indent + " ");
659 }
660
661 // Report about the parameter types that have changed sub-types.
662 for (vector<fn_parm_diff_sptr>::const_iterator i =
663 d.priv_->sorted_subtype_changed_parms_.begin();
664 i != d.priv_->sorted_subtype_changed_parms_.end();
665 ++i)
666 {
667 diff_sptr dif = *i;
668 if (dif && dif->to_be_reported())
669 dif->report(out, indent);
670 }
671
674}
675
676/// Report about the change carried by a @ref subrange_diff diff node
677/// in a serialized form.
678///
679/// @param d the diff node to consider.
680///
681/// @param out the output stream to report to.
682///
683/// @param indent the indentation string to use in the report.
684void
685default_reporter::report(const subrange_diff& d, std::ostream& out,
686 const std::string& indent) const
687{
688 if (!diff_to_be_reported(&d))
689 return;
690
691 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(d.first_subrange(),
692 d.second_subrange(),
693 "range type");
694
695 represent(d, d.context(), out,indent, /*local_only=*/false);
696}
697
698/// Report a @ref array_diff in a serialized form.
699///
700/// @param d the @ref array_diff to consider.
701///
702/// @param out the output stream to serialize the dif to.
703///
704/// @param indent the string to use for indenting the report.
705void
706default_reporter::report(const array_diff& d, ostream& out,
707 const string& indent) const
708{
709 if (!d.to_be_reported())
710 return;
711
712 string name = d.first_array()->get_pretty_representation();
713 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(d.first_array(),
714 d.second_array(),
715 "array type");
716
718 if (dif->to_be_reported())
719 {
720 string fn = ir::get_pretty_representation(is_type(dif->first_subject()));
721 // report array element type changes
722 out << indent << "array element type '"
723 << fn << "' changed:\n";
724 dif->report(out, indent + " ");
725 }
726
729 d.second_array(),
730 d.context(),
731 out, indent);
732}
733
734/// Generates a report for an intance of @ref base_diff.
735///
736/// @param d the @ref base_diff to consider.
737///
738/// @param out the output stream to send the report to.
739///
740/// @param indent the string to use for indentation.
741void
742default_reporter::report(const base_diff& d, ostream& out,
743 const string& indent) const
744{
745 if (!d.to_be_reported())
746 return;
747
748 class_decl::base_spec_sptr f = d.first_base(), s = d.second_base();
749 string repr = f->get_base_class()->get_pretty_representation();
750 bool emitted = false;
751
752 if (!d.is_filtered_out_without_looking_at_allowed_changes())
753 {
754 if (f->get_is_static() != s->get_is_static())
755 {
756 if (f->get_is_static())
757 out << indent << "is no more static";
758 else
759 out << indent << "now becomes static";
760 emitted = true;
761 }
762
763 if ((d.context()->get_allowed_category() & ACCESS_CHANGE_CATEGORY)
764 && (f->get_access_specifier() != s->get_access_specifier()))
765 {
766 if (emitted)
767 out << ", ";
768
769 out << "has access changed from '"
770 << f->get_access_specifier()
771 << "' to '"
772 << s->get_access_specifier()
773 << "'";
774
775 emitted = true;
776 }
777 }
778 if (class_diff_sptr dif = d.get_underlying_class_diff())
779 {
780 if (dif->to_be_reported())
781 {
782 if (emitted)
783 out << "\n";
784 dif->report(out, indent);
785 }
786 }
787}
788
789/// Report the changes carried by a @ref scope_diff.
790///
791/// @param d the @ref scope_diff to consider.
792///
793/// @param out the out stream to report the changes to.
794///
795/// @param indent the string to use for indentation.
796void
797default_reporter::report(const scope_diff& d, ostream& out,
798 const string& indent) const
799{
800 if (!d.to_be_reported())
801 return;
802
803 // Report changed types.
804 unsigned num_changed_types = d.changed_types().size();
805 if (num_changed_types == 0)
806 ;
807 else if (num_changed_types == 1)
808 out << indent << "1 changed type:\n";
809 else
810 out << indent << num_changed_types << " changed types:\n";
811
812 for (diff_sptrs_type::const_iterator dif = d.changed_types().begin();
813 dif != d.changed_types().end();
814 ++dif)
815 {
816 if (!*dif)
817 continue;
818
819 out << indent << " '"
820 << (*dif)->first_subject()->get_pretty_representation()
821 << "' changed:\n";
822 (*dif)->report(out, indent + " ");
823 }
824
825 // Report changed decls
826 unsigned num_changed_decls = d.changed_decls().size();
827 if (num_changed_decls == 0)
828 ;
829 else if (num_changed_decls == 1)
830 out << indent << "1 changed declaration:\n";
831 else
832 out << indent << num_changed_decls << " changed declarations:\n";
833
834 for (diff_sptrs_type::const_iterator dif= d.changed_decls().begin();
835 dif != d.changed_decls().end ();
836 ++dif)
837 {
838 if (!*dif)
839 continue;
840
841 out << indent << " '"
842 << (*dif)->first_subject()->get_pretty_representation()
843 << "' was changed to '"
844 << (*dif)->second_subject()->get_pretty_representation() << "'";
845 report_loc_info((*dif)->second_subject(), *d.context(), out);
846 out << ":\n";
847
848 (*dif)->report(out, indent + " ");
849 }
850
851 // Report removed types/decls
852 for (string_decl_base_sptr_map::const_iterator i =
853 d.priv_->deleted_types_.begin();
854 i != d.priv_->deleted_types_.end();
855 ++i)
856 out << indent
857 << " '"
858 << i->second->get_pretty_representation()
859 << "' was removed\n";
860
861 if (d.priv_->deleted_types_.size())
862 out << "\n";
863
864 for (string_decl_base_sptr_map::const_iterator i =
865 d.priv_->deleted_decls_.begin();
866 i != d.priv_->deleted_decls_.end();
867 ++i)
868 out << indent
869 << " '"
870 << i->second->get_pretty_representation()
871 << "' was removed\n";
872
873 if (d.priv_->deleted_decls_.size())
874 out << "\n";
875
876 // Report added types/decls
877 bool emitted = false;
878 for (string_decl_base_sptr_map::const_iterator i =
879 d.priv_->inserted_types_.begin();
880 i != d.priv_->inserted_types_.end();
881 ++i)
882 {
883 // Do not report about type_decl as these are usually built-in
884 // types.
885 if (dynamic_pointer_cast<type_decl>(i->second))
886 continue;
887 out << indent
888 << " '"
889 << i->second->get_pretty_representation()
890 << "' was added\n";
891 emitted = true;
892 }
893
894 if (emitted)
895 out << "\n";
896
897 emitted = false;
898 for (string_decl_base_sptr_map::const_iterator i =
899 d.priv_->inserted_decls_.begin();
900 i != d.priv_->inserted_decls_.end();
901 ++i)
902 {
903 // Do not report about type_decl as these are usually built-in
904 // types.
905 if (dynamic_pointer_cast<type_decl>(i->second))
906 continue;
907 out << indent
908 << " '"
909 << i->second->get_pretty_representation()
910 << "' was added\n";
911 emitted = true;
912 }
913
914 if (emitted)
915 out << "\n";
916}
917
918/// Report the changes carried by a @ref class_or_union_diff node in a
919/// textual format.
920///
921/// @param d the @ref class_or_union_diff node to consider.
922///
923/// @param out the output stream to write the textual report to.
924///
925/// @param indent the number of white space to use as indentation.
926void
927default_reporter::report(const class_or_union_diff& d,
928 ostream& out,
929 const string& indent) const
930{
931 if (!d.to_be_reported())
932 return;
933
934 class_or_union_sptr first = d.first_class_or_union(),
935 second = d.second_class_or_union();
936
937 const diff_context_sptr& ctxt = d.context();
938
939 // Report class decl-only <-> definition change.
940 if (ctxt->get_allowed_category() & TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY)
942 {
943 string was =
944 first->get_is_declaration_only()
945 ? " was a declaration-only type"
946 : " was a defined type";
947
948 string is_now =
949 second->get_is_declaration_only()
950 ? " and is now a declaration-only type"
951 : " and is now a defined type";
952
953 out << indent << "type " << first->get_pretty_representation()
954 << was << is_now << "\n";
955 return;
956 }
957
958 // member functions
959 if (d.member_fns_changes())
960 {
961 // report deletions
962 int numdels = d.get_priv()->deleted_member_functions_.size();
963 size_t num_filtered =
964 d.get_priv()->count_filtered_deleted_mem_fns(ctxt);
965 if (numdels)
966 report_mem_header(out, numdels, num_filtered, del_kind,
967 "member function", indent);
968 for (class_or_union::member_functions::const_iterator i =
969 d.get_priv()->sorted_deleted_member_functions_.begin();
970 i != d.get_priv()->sorted_deleted_member_functions_.end();
971 ++i)
972 {
973 if (!(ctxt->get_allowed_category()
976 continue;
977
978 method_decl_sptr mem_fun = *i;
979 out << indent << " ";
980 represent(*ctxt, mem_fun, out);
981 }
982
983 // report insertions;
984 int numins = d.get_priv()->inserted_member_functions_.size();
985 num_filtered = d.get_priv()->count_filtered_inserted_mem_fns(ctxt);
986 if (numins)
987 report_mem_header(out, numins, num_filtered, ins_kind,
988 "member function", indent);
989 for (class_or_union::member_functions::const_iterator i =
990 d.get_priv()->sorted_inserted_member_functions_.begin();
991 i != d.get_priv()->sorted_inserted_member_functions_.end();
992 ++i)
993 {
994 if (!(ctxt->get_allowed_category()
997 continue;
998
999 method_decl_sptr mem_fun = *i;
1000 out << indent << " ";
1001 represent(*ctxt, mem_fun, out);
1002 }
1003
1004 // report member function with sub-types changes
1005 int numchanges = d.get_priv()->sorted_changed_member_functions_.size();
1006 num_filtered = d.get_priv()->count_filtered_changed_mem_fns(ctxt);
1007 if (numchanges)
1008 report_mem_header(out, numchanges, num_filtered, change_kind,
1009 "member function", indent);
1010 for (function_decl_diff_sptrs_type::const_iterator i =
1011 d.get_priv()->sorted_changed_member_functions_.begin();
1012 i != d.get_priv()->sorted_changed_member_functions_.end();
1013 ++i)
1014 {
1015 if (!(ctxt->get_allowed_category()
1018 ((*i)->first_function_decl()))
1020 ((*i)->second_function_decl())))
1021 continue;
1022
1023 diff_sptr diff = *i;
1024 if (!diff || !diff->to_be_reported())
1025 continue;
1026
1027 string repr =
1028 (*i)->first_function_decl()->get_pretty_representation();
1029 out << indent << " '" << repr << "' has some sub-type changes:\n";
1030 diff->report(out, indent + " ");
1031 }
1032 }
1033
1034 // data members
1035 if (d.data_members_changes())
1036 {
1037 // report deletions
1038 int numdels = d.class_or_union_diff::get_priv()->
1039 get_deleted_non_static_data_members_number();
1040 if (numdels)
1041 {
1042 report_mem_header(out, numdels, 0, del_kind,
1043 "data member", indent);
1044 vector<decl_base_sptr> sorted_dms;
1046 (d.class_or_union_diff::get_priv()->deleted_data_members_,
1047 sorted_dms);
1048 for (vector<decl_base_sptr>::const_iterator i = sorted_dms.begin();
1049 i != sorted_dms.end();
1050 ++i)
1051 {
1052 var_decl_sptr data_mem =
1053 dynamic_pointer_cast<var_decl>(*i);
1054 ABG_ASSERT(data_mem);
1055 if (get_member_is_static(data_mem))
1056 continue;
1057 represent_data_member(data_mem, ctxt, out, indent + " ");
1058 }
1059 }
1060
1061 //report insertions
1062 int numins =
1063 d.class_or_union_diff::get_priv()->inserted_data_members_.size();
1064 if (numins)
1065 {
1066 report_mem_header(out, numins, 0, ins_kind,
1067 "data member", indent);
1068 vector<decl_base_sptr> sorted_dms;
1070 (d.class_or_union_diff::get_priv()->inserted_data_members_,
1071 sorted_dms);
1072 for (vector<decl_base_sptr>::const_iterator i = sorted_dms.begin();
1073 i != sorted_dms.end();
1074 ++i)
1075 {
1076 var_decl_sptr data_mem =
1077 dynamic_pointer_cast<var_decl>(*i);
1078 ABG_ASSERT(data_mem);
1079 represent_data_member(data_mem, ctxt, out, indent + " ");
1080 }
1081 }
1082
1083 // report change
1084 size_t num_changes =
1085 (d.sorted_subtype_changed_data_members().size()
1086 + d.sorted_changed_data_members().size());
1087
1088 size_t num_changes_filtered =
1089 (d.count_filtered_subtype_changed_data_members()
1090 + d.count_filtered_changed_data_members());
1091
1092 if (num_changes)
1093 {
1094 report_mem_header(out, num_changes, num_changes_filtered,
1095 change_kind, "data member", indent);
1096
1097 for (var_diff_sptrs_type::const_iterator it =
1098 d.sorted_changed_data_members().begin();
1099 it != d.sorted_changed_data_members().end();
1100 ++it)
1101 if ((*it)->to_be_reported())
1102 represent(*it, ctxt, out, indent + " ");
1103
1104 for (var_diff_sptrs_type::const_iterator it =
1105 d.sorted_subtype_changed_data_members().begin();
1106 it != d.sorted_subtype_changed_data_members().end();
1107 ++it)
1108 if ((*it)->to_be_reported())
1109 represent(*it, ctxt, out, indent + " ");
1110 }
1111
1112 // Report about data members replaced by an anonymous union data
1113 // member.
1115 }
1116
1117 // member types
1118 if (const edit_script& e = d.member_types_changes())
1119 {
1120 int numchanges =
1121 d.class_or_union_diff::get_priv()->sorted_changed_member_types_.size();
1122 int numdels =
1123 d.class_or_union_diff::get_priv()->deleted_member_types_.size();
1124
1125 // report deletions
1126 if (numdels)
1127 {
1128 report_mem_header(out, numdels, 0, del_kind,
1129 "member type", indent);
1130
1131 for (string_decl_base_sptr_map::const_iterator i =
1132 d.class_or_union_diff::get_priv()->deleted_member_types_.begin();
1133 i != d.class_or_union_diff::get_priv()->deleted_member_types_.end();
1134 ++i)
1135 {
1136 decl_base_sptr mem_type = i->second;
1137 out << indent << " '"
1138 << mem_type->get_pretty_representation()
1139 << "'\n";
1140 }
1141 out << "\n";
1142 }
1143 // report changes
1144 if (numchanges)
1145 {
1146 report_mem_header(out, numchanges, 0, change_kind,
1147 "member type", indent);
1148
1149 for (diff_sptrs_type::const_iterator it =
1150 d.class_or_union_diff::get_priv()->sorted_changed_member_types_.begin();
1151 it != d.class_or_union_diff::get_priv()->sorted_changed_member_types_.end();
1152 ++it)
1153 {
1154 if (!(*it)->to_be_reported())
1155 continue;
1156
1157 type_or_decl_base_sptr o = (*it)->first_subject();
1158 type_or_decl_base_sptr n = (*it)->second_subject();
1159 out << indent << " '"
1160 << o->get_pretty_representation()
1161 << "' changed ";
1162 report_loc_info(n, *ctxt, out);
1163 out << ":\n";
1164 (*it)->report(out, indent + " ");
1165 }
1166 out << "\n";
1167 }
1168
1169 // report insertions
1170 int numins = e.num_insertions();
1171 ABG_ASSERT(numchanges <= numins);
1172 numins -= numchanges;
1173
1174 if (numins)
1175 {
1176 report_mem_header(out, numins, 0, ins_kind,
1177 "member type", indent);
1178
1179 for (vector<insertion>::const_iterator i = e.insertions().begin();
1180 i != e.insertions().end();
1181 ++i)
1182 {
1183 type_base_sptr mem_type;
1184 for (vector<unsigned>::const_iterator j =
1185 i->inserted_indexes().begin();
1186 j != i->inserted_indexes().end();
1187 ++j)
1188 {
1189 mem_type = second->get_member_types()[*j];
1190 if (!d.class_or_union_diff::get_priv()->
1191 member_type_has_changed(get_type_declaration(mem_type)))
1192 {
1193 out << indent << " '"
1194 << get_type_declaration(mem_type)->
1196 << "'\n";
1197 }
1198 }
1199 }
1200 out << "\n";
1201 }
1202 }
1203
1204 // member function templates
1205 if (const edit_script& e = d.member_fn_tmpls_changes())
1206 {
1207 // report deletions
1208 int numdels = e.num_deletions();
1209 if (numdels)
1210 report_mem_header(out, numdels, 0, del_kind,
1211 "member function template", indent);
1212 for (vector<deletion>::const_iterator i = e.deletions().begin();
1213 i != e.deletions().end();
1214 ++i)
1215 {
1216 member_function_template_sptr mem_fn_tmpl =
1217 first->get_member_function_templates()[i->index()];
1218 out << indent << " '"
1219 << mem_fn_tmpl->as_function_tdecl()->get_pretty_representation()
1220 << "'\n";
1221 }
1222
1223 // report insertions
1224 int numins = e.num_insertions();
1225 if (numins)
1226 report_mem_header(out, numins, 0, ins_kind,
1227 "member function template", indent);
1228 for (vector<insertion>::const_iterator i = e.insertions().begin();
1229 i != e.insertions().end();
1230 ++i)
1231 {
1232 member_function_template_sptr mem_fn_tmpl;
1233 for (vector<unsigned>::const_iterator j =
1234 i->inserted_indexes().begin();
1235 j != i->inserted_indexes().end();
1236 ++j)
1237 {
1238 mem_fn_tmpl = second->get_member_function_templates()[*j];
1239 out << indent << " '"
1240 << mem_fn_tmpl->as_function_tdecl()->
1242 << "'\n";
1243 }
1244 }
1245 }
1246
1247 // member class templates.
1248 if (const edit_script& e = d.member_class_tmpls_changes())
1249 {
1250 // report deletions
1251 int numdels = e.num_deletions();
1252 if (numdels)
1253 report_mem_header(out, numdels, 0, del_kind,
1254 "member class template", indent);
1255 for (vector<deletion>::const_iterator i = e.deletions().begin();
1256 i != e.deletions().end();
1257 ++i)
1258 {
1259 member_class_template_sptr mem_cls_tmpl =
1260 first->get_member_class_templates()[i->index()];
1261 out << indent << " '"
1262 << mem_cls_tmpl->as_class_tdecl()->get_pretty_representation()
1263 << "'\n";
1264 }
1265
1266 // report insertions
1267 int numins = e.num_insertions();
1268 if (numins)
1269 report_mem_header(out, numins, 0, ins_kind,
1270 "member class template", indent);
1271 for (vector<insertion>::const_iterator i = e.insertions().begin();
1272 i != e.insertions().end();
1273 ++i)
1274 {
1275 member_class_template_sptr mem_cls_tmpl;
1276 for (vector<unsigned>::const_iterator j =
1277 i->inserted_indexes().begin();
1278 j != i->inserted_indexes().end();
1279 ++j)
1280 {
1281 mem_cls_tmpl = second->get_member_class_templates()[*j];
1282 out << indent << " '"
1283 << mem_cls_tmpl->as_class_tdecl()
1284 ->get_pretty_representation()
1285 << "'\n";
1286 }
1287 }
1288 }
1289}
1290
1291/// Produce a basic report about the changes carried by a @ref
1292/// class_diff node.
1293///
1294/// @param d the @ref class_diff node to consider.
1295///
1296/// @param out the output stream to report the changes to.
1297///
1298/// @param indent the string to use as an indentation prefix in the
1299/// report.
1300void
1301default_reporter::report(const class_diff& d, ostream& out,
1302 const string& indent) const
1303{
1304 if (!d.to_be_reported())
1305 return;
1306
1307 string name = d.first_subject()->get_pretty_representation();
1308
1309 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_subject(),
1310 d.second_subject());
1311
1312 d.currently_reporting(true);
1313
1314 // Now report the changes about the differents parts of the type.
1315 class_decl_sptr first = d.first_class_decl(),
1316 second = d.second_class_decl();
1317
1318 report_name_size_and_alignment_changes(first, second, d.context(),
1319 out, indent);
1320
1321 const diff_context_sptr& ctxt = d.context();
1322 maybe_report_diff_for_member(first, second, ctxt, out, indent);
1323
1324 // bases classes
1325 if (d.base_changes())
1326 {
1327 // Report deletions.
1328 int numdels = d.get_priv()->deleted_bases_.size();
1329 size_t numchanges = d.get_priv()->sorted_changed_bases_.size();
1330
1331 if (numdels)
1332 {
1333 report_mem_header(out, numdels, 0, del_kind,
1334 "base class", indent);
1335
1336 for (class_decl::base_specs::const_iterator i
1337 = d.get_priv()->sorted_deleted_bases_.begin();
1338 i != d.get_priv()->sorted_deleted_bases_.end();
1339 ++i)
1340 {
1341 if (i != d.get_priv()->sorted_deleted_bases_.begin())
1342 out << "\n";
1343
1345
1346 if (d.get_priv()->base_has_changed(base))
1347 continue;
1348 out << indent << " "
1349 << base->get_base_class()->get_pretty_representation();
1350 report_loc_info(base->get_base_class(), *d.context(), out);
1351 }
1352 out << "\n";
1353 }
1354
1355 // Report changes.
1356 size_t num_filtered = d.get_priv()->count_filtered_bases();
1357 if (numchanges)
1358 {
1359 report_mem_header(out, numchanges, num_filtered, change_kind,
1360 "base class", indent);
1361 for (base_diff_sptrs_type::const_iterator it =
1362 d.get_priv()->sorted_changed_bases_.begin();
1363 it != d.get_priv()->sorted_changed_bases_.end();
1364 ++it)
1365 {
1366 base_diff_sptr diff = *it;
1367 if (!diff || !diff->to_be_reported())
1368 continue;
1369
1370 class_decl::base_spec_sptr o = diff->first_base();
1371 out << indent << " '"
1372 << o->get_base_class()->get_pretty_representation() << "'";
1373 report_loc_info(o->get_base_class(), *d.context(), out);
1374 out << " changed:\n";
1375 diff->report(out, indent + " ");
1376 }
1377 }
1378
1379 //Report insertions.
1380 int numins = d.get_priv()->inserted_bases_.size();
1381 if (numins)
1382 {
1383 report_mem_header(out, numins, 0, ins_kind,
1384 "base class", indent);
1385
1386 for (class_decl::base_specs::const_iterator i =
1387 d.get_priv()->sorted_inserted_bases_.begin();
1388 i != d.get_priv()->sorted_inserted_bases_.end();
1389 ++i)
1390 {
1391 class_decl_sptr b = (*i)->get_base_class();
1392 out << indent << " " << b->get_pretty_representation();
1393 report_loc_info(b, *ctxt, out);
1394 out << "\n";
1395 }
1396 }
1397
1398 // Report base classes re-organisation
1399 maybe_report_base_class_reordering(d, out, indent);
1400 }
1401
1402 d.class_or_union_diff::report(out, indent);
1403
1404 d.currently_reporting(false);
1405
1406 d.reported_once(true);
1407}
1408
1409/// Produce a basic report about the changes carried by a @ref
1410/// union_diff node.
1411///
1412/// @param d the @ref union_diff node to consider.
1413///
1414/// @param out the output stream to report the changes to.
1415///
1416/// @param indent the string to use as an indentation prefix in the
1417/// report.
1418void
1419default_reporter::report(const union_diff& d, ostream& out,
1420 const string& indent) const
1421{
1422 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_subject(),
1423 d.second_subject());
1424
1425 d.currently_reporting(true);
1426
1427 // Now report the changes about the differents parts of the type.
1428 union_decl_sptr first = d.first_union_decl(), second = d.second_union_decl();
1429
1430 report_name_size_and_alignment_changes(first, second, d.context(),
1431 out, indent);
1432
1433 maybe_report_diff_for_member(first, second,d. context(), out, indent);
1434
1435 d.class_or_union_diff::report(out, indent);
1436
1437 if (d.context()->get_allowed_category() & HARMLESS_UNION_CHANGE_CATEGORY
1439 {
1440 // The user wants to see harmless changes and the union diff we
1441 // are looking at does carry some harmless changes. Let's show
1442 // the "before" and "after" carried by the diff node.
1443 out << indent << "type changed from:\n"
1444 << get_class_or_union_flat_representation(first, indent + " ",
1445 /*one_line=*/true,
1446 /*internal=*/false,
1447 /*qualified_names=*/false)
1448 << "\n"
1449 << indent << "to:\n"
1450 << get_class_or_union_flat_representation(second, indent + " ",
1451 /*one_line=*/true,
1452 /*internal=*/false,
1453 /*qualified_names=*/false)
1454 << "\n";
1455 }
1456
1457 d.currently_reporting(false);
1458
1459 d.reported_once(true);
1460}
1461
1462/// Emit a report about the changes carried by a @ref distinct_diff
1463/// node.
1464///
1465/// @param d the @ref distinct_diff node to consider.
1466///
1467/// @param out the output stream to send the diff report to.
1468///
1469/// @param indent the indentation string to use in the report.
1470void
1471default_reporter::report(const distinct_diff& d, ostream& out,
1472 const string& indent) const
1473{
1474 if (!d.to_be_reported())
1475 return;
1476
1477 type_or_decl_base_sptr f = d.first(), s = d.second();
1478
1479 string f_repr = f ? f->get_pretty_representation() : "'void'";
1480 string s_repr = s ? s->get_pretty_representation() : "'void'";
1481
1482 diff_sptr diff = d.compatible_child_diff();
1483
1484 string compatible = diff ? " to compatible type '": " to '";
1485
1486 out << indent << "entity changed from '" << f_repr << "'"
1487 << compatible << s_repr << "'";
1488 report_loc_info(s, *d.context(), out);
1489 out << "\n";
1490
1491 type_base_sptr fs = strip_typedef(is_type(f)),
1492 ss = strip_typedef(is_type(s));
1493
1494 if (diff)
1495 diff->report(out, indent + " ");
1496 else
1497 report_size_and_alignment_changes(f, s, d.context(), out, indent);
1498}
1499
1500/// Serialize a report of the changes encapsulated in the current
1501/// instance of @ref function_decl_diff over to an output stream.
1502///
1503/// @param d the @ref function_decl_diff node to consider.
1504///
1505/// @param out the output stream to serialize the report to.
1506///
1507/// @param indent the string to use an an indentation prefix.
1508void
1509default_reporter::report(const function_decl_diff& d, ostream& out,
1510 const string& indent) const
1511{
1512 if (!d.to_be_reported())
1513 return;
1514
1515 maybe_report_diff_for_member(d.first_function_decl(),
1516 d.second_function_decl(),
1517 d.context(), out, indent);
1518
1519 function_decl_sptr ff = d.first_function_decl();
1520 function_decl_sptr sf = d.second_function_decl();
1521
1522 diff_context_sptr ctxt = d.context();
1523 corpus_sptr fc = ctxt->get_first_corpus();
1524 corpus_sptr sc = ctxt->get_second_corpus();
1525
1526
1527 string qn1 = ff->get_qualified_name(), qn2 = sf->get_qualified_name(),
1528 linkage_names1, linkage_names2;
1529 elf_symbol_sptr s1 = ff->get_symbol(), s2 = sf->get_symbol();
1530
1531 if (s1)
1532 linkage_names1 = s1->get_id_string();
1533 if (s2)
1534 linkage_names2 = s2->get_id_string();
1535
1536 // If the symbols for ff and sf have aliases, get all the names of
1537 // the aliases;
1538 if (fc && s1)
1539 linkage_names1 =
1540 s1->get_aliases_id_string(fc->get_fun_symbol_map());
1541 if (sc && s2)
1542 linkage_names2 =
1543 s2->get_aliases_id_string(sc->get_fun_symbol_map());
1544
1545 if (!d.is_filtered_out_without_looking_at_allowed_changes())
1546 {
1547 /// If the set of linkage names of the function have changed, report
1548 /// it.
1549 if (linkage_names1 != linkage_names2)
1550 {
1551 if (linkage_names1.empty())
1552 {
1553 out << indent << ff->get_pretty_representation()
1554 << " didn't have any linkage name, and it now has: '"
1555 << linkage_names2 << "'\n";
1556 }
1557 else if (linkage_names2.empty())
1558 {
1559 out << indent << ff->get_pretty_representation()
1560 << " did have linkage names '" << linkage_names1
1561 << "'\n"
1562 << indent << "but it doesn't have any linkage name anymore\n";
1563 }
1564 else
1565 out << indent << "linkage names of "
1566 << ff->get_pretty_representation()
1567 << "\n" << indent << "changed from '"
1568 << linkage_names1 << "' to '" << linkage_names2 << "'\n";
1569 }
1570
1571 if (qn1 != qn2
1572 && d.type_diff()
1573 && d.type_diff()->to_be_reported())
1574 {
1575 // So the function has sub-type changes that are to be
1576 // reported. Let's see if the function name changed too; if it
1577 // did, then we'd report that change right before reporting the
1578 // sub-type changes.
1579 string frep1 = d.first_function_decl()->get_pretty_representation(),
1580 frep2 = d.second_function_decl()->get_pretty_representation();
1581 out << indent << "'" << frep1 << " {" << linkage_names1<< "}"
1582 << "' now becomes '"
1583 << frep2 << " {" << linkage_names2 << "}" << "'\n";
1584 }
1585
1586 maybe_report_diff_for_symbol(ff->get_symbol(),
1587 sf->get_symbol(),
1588 d.context(), out, indent);
1589
1590 // Now report about inline-ness changes
1591 if (ff->is_declared_inline() != sf->is_declared_inline())
1592 {
1593 out << indent;
1594 if (ff->is_declared_inline())
1595 out << sf->get_pretty_representation()
1596 << " is not declared inline anymore\n";
1597 else
1598 out << sf->get_pretty_representation()
1599 << " is now declared inline\n";
1600 }
1601
1602 // Report about vtable offset changes.
1604 {
1605 bool ff_is_virtual = get_member_function_is_virtual(ff),
1606 sf_is_virtual = get_member_function_is_virtual(sf);
1607 if (ff_is_virtual != sf_is_virtual)
1608 {
1609 out << indent;
1610 if (ff_is_virtual)
1611 out << ff->get_pretty_representation()
1612 << " is no more declared virtual\n";
1613 else
1614 out << ff->get_pretty_representation()
1615 << " is now declared virtual\n";
1616 }
1617
1618 size_t ff_vtable_offset = get_member_function_vtable_offset(ff),
1619 sf_vtable_offset = get_member_function_vtable_offset(sf);
1620 if (ff_is_virtual && sf_is_virtual
1621 && (ff_vtable_offset != sf_vtable_offset))
1622 {
1623 out << indent
1624 << "the vtable offset of " << ff->get_pretty_representation()
1625 << " changed from " << ff_vtable_offset
1626 << " to " << sf_vtable_offset << "\n";
1627 }
1628
1629 // the parent types (classe or union) of the two member
1630 // functions.
1631 class_or_union_sptr f =
1632 is_class_or_union_type(is_method_type(ff->get_type())->get_class_type());
1633 class_or_union_sptr s =
1634 is_class_or_union_type(is_method_type(sf->get_type())->get_class_type());
1635
1638
1639 // Detect if the virtual member function changes above
1640 // introduced a vtable change or not.
1641 bool vtable_added = false, vtable_removed = false;
1642 if (!f->get_is_declaration_only() && !s->get_is_declaration_only())
1643 {
1644 if (fc && sc)
1645 {
1646 vtable_added = !fc->has_vtable() && sc->has_vtable();
1647 vtable_removed = fc->has_vtable() && !sc->has_vtable();
1648 }
1649 }
1650 bool vtable_changed = ((ff_is_virtual != sf_is_virtual)
1651 || (ff_vtable_offset != sf_vtable_offset));
1652 bool incompatible_change = (ff_vtable_offset != sf_vtable_offset);
1653
1654 if (vtable_added)
1655 out << indent
1656 << " note that a vtable was added to "
1657 << fc->get_pretty_representation()
1658 << "\n";
1659 else if (vtable_removed)
1660 out << indent
1661 << " note that the vtable was removed from "
1662 << fc->get_pretty_representation()
1663 << "\n";
1664 else if (vtable_changed)
1665 {
1666 out << indent;
1667 if (incompatible_change)
1668 out << " note that this is an ABI incompatible "
1669 "change to the vtable of ";
1670 else
1671 out << " note that this induces a change to the vtable of ";
1672 out << fc->get_pretty_representation()
1673 << "\n";
1674 }
1675
1676 }
1677 }
1678
1679 // Report about function type differences.
1680 if (d.type_diff() && d.type_diff()->to_be_reported())
1681 d.type_diff()->report(out, indent);
1682}
1683
1684/// Report the changes carried by a @ref var_diff node in a serialized
1685/// form.
1686///
1687/// @param d the @ref var_diff node to consider.
1688///
1689/// @param out the stream to serialize the diff to.
1690///
1691/// @param indent the prefix to use for the indentation of this
1692/// serialization.
1693void
1694default_reporter::report(const var_diff& d, ostream& out,
1695 const string& indent) const
1696{
1697 if (!d.to_be_reported())
1698 return;
1699
1700 decl_base_sptr first = d.first_var(), second = d.second_var();
1701 string n = first->get_pretty_representation();
1702
1703 if (!d.is_filtered_out_without_looking_at_allowed_changes())
1704 {
1706 d.context(),
1707 out, indent);
1708
1709 maybe_report_diff_for_symbol(d.first_var()->get_symbol(),
1710 d.second_var()->get_symbol(),
1711 d.context(), out, indent);
1712
1713 maybe_report_diff_for_member(first, second, d.context(), out, indent);
1714
1715 maybe_report_diff_for_variable(first, second, d.context(), out, indent);
1716 }
1717
1718 if (diff_sptr dif = d.type_diff())
1719 {
1720 if (dif->to_be_reported())
1721 {
1722 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(dif, "type");
1723 out << indent << "type of variable changed:\n";
1724 dif->report(out, indent + " ");
1725 }
1726 }
1727}
1728
1729/// Report the changes carried by a @ref translation_unit_diff node in
1730/// a serialized form.
1731///
1732/// @param d the @ref translation_unit_diff node to consider.
1733///
1734/// @param out the output stream to serialize the report to.
1735///
1736/// @param indent the prefix to use as indentation for the report.
1737void
1738default_reporter::report(const translation_unit_diff& d,
1739 ostream& out,
1740 const string& indent) const
1741{
1742 static_cast<const scope_diff&>(d).report(out, indent);
1743}
1744
1745/// Report the changes carried by a @ref corpus_diff node in a
1746/// serialized form.
1747///
1748/// @param d the @ref corpus_diff node to consider.
1749///
1750/// @param out the output stream to serialize the report to.
1751///
1752/// @param indent the prefix to use as indentation for the report.
1753void
1754default_reporter::report(const corpus_diff& d, ostream& out,
1755 const string& indent) const
1756{
1757 const corpus_diff::diff_stats &s =
1758 const_cast<corpus_diff&>(d).
1759 apply_filters_and_suppressions_before_reporting();
1760
1761 const diff_context_sptr& ctxt = d.context();
1762
1763 d.priv_->emit_diff_stats(s, out, indent);
1764 if (ctxt->show_stats_only())
1765 return;
1766 out << "\n";
1767
1768 if (ctxt->show_soname_change()
1769 && !d.priv_->sonames_equal_)
1770 out << indent << "SONAME changed from '"
1771 << d.first_corpus()->get_soname() << "' to '"
1772 << d.second_corpus()->get_soname() << "'\n\n";
1773
1774 if (ctxt->show_architecture_change()
1775 && !d.priv_->architectures_equal_)
1776 out << indent << "architecture changed from '"
1777 << d.first_corpus()->get_architecture_name() << "' to '"
1778 << d.second_corpus()->get_architecture_name() << "'\n\n";
1779
1780 /// Report removed/added/changed functions.
1781 if (ctxt->show_deleted_fns())
1782 {
1783 if (s.net_num_func_removed() == 1)
1784 out << indent << "1 Removed function:\n\n";
1785 else if (s.net_num_func_removed() > 1)
1786 out << indent << s.net_num_func_removed() << " Removed functions:\n\n";
1787
1788 bool emitted = false;
1789 vector<function_decl*>sorted_deleted_fns;
1790 sort_string_function_ptr_map(d.priv_->deleted_fns_, sorted_deleted_fns);
1791 for (vector<function_decl*>::const_iterator i =
1792 sorted_deleted_fns.begin();
1793 i != sorted_deleted_fns.end();
1794 ++i)
1795 {
1796 if (d.priv_->deleted_function_is_suppressed(*i))
1797 continue;
1798
1799 out << indent
1800 << " ";
1801 out << "[D] ";
1802 out << "'" << (*i)->get_pretty_representation() << "'";
1803 if (ctxt->show_linkage_names())
1804 {
1805 out << " {";
1806 show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
1807 d.first_corpus()->get_fun_symbol_map());
1808 out << "}";
1809 }
1810 out << "\n";
1812 {
1813 class_decl_sptr c =
1814 is_class_type(is_method_type((*i)->get_type())->get_class_type());
1815 out << indent
1816 << " "
1817 << "note that this removes an entry from the vtable of "
1818 << c->get_pretty_representation()
1819 << "\n";
1820 }
1821 emitted = true;
1822 }
1823 if (emitted)
1824 out << "\n";
1825 }
1826
1827 if (ctxt->show_added_fns())
1828 {
1829 if (s.net_num_func_added() == 1)
1830 out << indent << "1 Added function:\n\n";
1831 else if (s.net_num_func_added() > 1)
1832 out << indent << s.net_num_func_added()
1833 << " Added functions:\n\n";
1834 bool emitted = false;
1835 vector<function_decl*> sorted_added_fns;
1836 sort_string_function_ptr_map(d.priv_->added_fns_, sorted_added_fns);
1837 for (vector<function_decl*>::const_iterator i = sorted_added_fns.begin();
1838 i != sorted_added_fns.end();
1839 ++i)
1840 {
1841 if (d.priv_->added_function_is_suppressed(*i))
1842 continue;
1843
1844 out
1845 << indent
1846 << " ";
1847 out << "[A] ";
1848 out << "'"
1849 << (*i)->get_pretty_representation()
1850 << "'";
1851 if (ctxt->show_linkage_names())
1852 {
1853 out << " {";
1855 (out, "", *(*i)->get_symbol(),
1856 d.second_corpus()->get_fun_symbol_map());
1857 out << "}";
1858 }
1859 out << "\n";
1861 {
1862 class_decl_sptr c =
1863 is_class_type(is_method_type((*i)->get_type())->get_class_type());
1864 out << indent
1865 << " "
1866 << "note that this adds a new entry to the vtable of "
1867 << c->get_pretty_representation()
1868 << "\n";
1869 }
1870 emitted = true;
1871 }
1872 if (emitted)
1873 out << "\n";
1874 }
1875
1876 if (ctxt->show_changed_fns())
1877 {
1878 size_t num_changed = s.num_func_changed() - s.num_changed_func_filtered_out();
1879 if (num_changed == 1)
1880 out << indent << "1 function with some indirect sub-type change:\n\n";
1881 else if (num_changed > 1)
1882 out << indent << num_changed
1883 << " functions with some indirect sub-type change:\n\n";
1884
1885 vector<function_decl_diff_sptr> sorted_changed_fns;
1886 sort_string_function_decl_diff_sptr_map(d.priv_->changed_fns_map_,
1887 sorted_changed_fns);
1888 for (vector<function_decl_diff_sptr>::const_iterator i =
1889 sorted_changed_fns.begin();
1890 i != sorted_changed_fns.end();
1891 ++i)
1892 {
1893 diff_sptr diff = *i;
1894 if (!diff)
1895 continue;
1896
1897 if (diff->to_be_reported())
1898 {
1899 function_decl_sptr fn = (*i)->first_function_decl();
1900 out << indent << " [C] '"
1901 << fn->get_pretty_representation() << "'";
1902 report_loc_info((*i)->first_function_decl(), *ctxt, out);
1903 out << " has some indirect sub-type changes:\n";
1904 if (// The symbol of the function has aliases and the
1905 // function is not a cdtor (yeah because c++ cdtors
1906 // usually have several aliases).
1907 (fn->get_symbol()->has_aliases()
1908 && !(is_member_function(fn)
1910 && !(is_member_function(fn)
1912 || // We are in C and the name of the function is
1913 // different from the symbol name -- without
1914 // taking the possible symbol version into
1915 // account (this usually means the programmers
1916 // was playing tricks with symbol names and
1917 // versions).
1918 (is_c_language(get_translation_unit(fn)->get_language())
1919 && fn->get_name() != fn->get_symbol()->get_name()))
1920 {
1921 // As the name of the symbol of the function doesn't
1922 // seem to be obvious here, make sure to tell the
1923 // user about the name of the (function) symbol she
1924 // is looking at here.
1925 int number_of_aliases =
1926 fn->get_symbol()->get_number_of_aliases();
1927 if (number_of_aliases == 0)
1928 {
1929 out << indent << " "
1930 << "Please note that the exported symbol of "
1931 "this function is "
1932 << fn->get_symbol()->get_id_string()
1933 << "\n";
1934 }
1935 else
1936 {
1937 out << indent << " "
1938 << "Please note that the symbol of this function is "
1939 << fn->get_symbol()->get_id_string()
1940 << "\n and it aliases symbol";
1941 if (number_of_aliases > 1)
1942 out << "s";
1943 out << ": "
1944 << fn->get_symbol()->get_aliases_id_string(false)
1945 << "\n";
1946 }
1947 }
1948 diff->report(out, indent + " ");
1949 // Extra spacing.
1950 out << "\n";
1951 }
1952 }
1953 // Changed functions have extra spacing already. No new line here.
1954 }
1955
1956 // Report removed/added/changed variables.
1957 if (ctxt->show_deleted_vars())
1958 {
1959 if (s.net_num_vars_removed() == 1)
1960 out << indent << "1 Removed variable:\n\n";
1961 else if (s.net_num_vars_removed() > 1)
1962 out << indent << s.net_num_vars_removed()
1963 << " Removed variables:\n\n";
1964 string n;
1965 bool emitted = false;
1966 vector<var_decl*> sorted_deleted_vars;
1967 sort_string_var_ptr_map(d.priv_->deleted_vars_, sorted_deleted_vars);
1968 for (vector<var_decl*>::const_iterator i =
1969 sorted_deleted_vars.begin();
1970 i != sorted_deleted_vars.end();
1971 ++i)
1972 {
1973 if (d.priv_->deleted_variable_is_suppressed(*i))
1974 continue;
1975
1976 n = (*i)->get_pretty_representation();
1977
1978 out << indent
1979 << " ";
1980 out << "[D] ";
1981 out << "'"
1982 << n
1983 << "'";
1984 if (ctxt->show_linkage_names())
1985 {
1986 out << " {";
1987 show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
1988 d.first_corpus()->get_var_symbol_map());
1989 out << "}";
1990 }
1991 out << "\n";
1992 emitted = true;
1993 }
1994 if (emitted)
1995 out << "\n";
1996 }
1997
1998 if (ctxt->show_added_vars())
1999 {
2000 if (s.net_num_vars_added() == 1)
2001 out << indent << "1 Added variable:\n\n";
2002 else if (s.net_num_vars_added() > 1)
2003 out << indent << s.net_num_vars_added()
2004 << " Added variables:\n\n";
2005 string n;
2006 bool emitted = false;
2007 vector<var_decl*> sorted_added_vars;
2008 sort_string_var_ptr_map(d.priv_->added_vars_, sorted_added_vars);
2009 for (vector<var_decl*>::const_iterator i =
2010 sorted_added_vars.begin();
2011 i != sorted_added_vars.end();
2012 ++i)
2013 {
2014 if (d.priv_->added_variable_is_suppressed(*i))
2015 continue;
2016
2017 n = (*i)->get_pretty_representation();
2018
2019 out << indent
2020 << " ";
2021 out << "[A] ";
2022 out << "'" << n << "'";
2023 if (ctxt->show_linkage_names())
2024 {
2025 out << " {";
2026 show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
2027 d.second_corpus()->get_var_symbol_map());
2028 out << "}";
2029 }
2030 out << "\n";
2031 emitted = true;
2032 }
2033 if (emitted)
2034 out << "\n";
2035 }
2036
2037 if (ctxt->show_changed_vars())
2038 {
2039 size_t num_changed =
2040 s.num_vars_changed() - s.num_changed_vars_filtered_out();
2041 if (num_changed == 1)
2042 out << indent << "1 Changed variable:\n\n";
2043 else if (num_changed > 1)
2044 out << indent << num_changed
2045 << " Changed variables:\n\n";
2046 string n1, n2;
2047
2048 for (var_diff_sptrs_type::const_iterator i =
2049 d.priv_->sorted_changed_vars_.begin();
2050 i != d.priv_->sorted_changed_vars_.end();
2051 ++i)
2052 {
2053 diff_sptr diff = *i;
2054
2055 if (!diff)
2056 continue;
2057
2058 if (!diff->to_be_reported())
2059 continue;
2060
2061 n1 = diff->first_subject()->get_pretty_representation();
2062 n2 = diff->second_subject()->get_pretty_representation();
2063
2064 out << indent << " [C] '" << n1 << "' was changed";
2065 if (n1 != n2)
2066 out << " to '" << n2 << "'";
2067 report_loc_info(diff->second_subject(), *ctxt, out);
2068 out << ":\n";
2069 diff->report(out, indent + " ");
2070 // Extra spacing.
2071 out << "\n";
2072 }
2073 // Changed variables have extra spacing already. No new line here.
2074 }
2075
2076 // Report removed function symbols not referenced by any debug info.
2077 if (ctxt->show_symbols_unreferenced_by_debug_info()
2078 && d.priv_->deleted_unrefed_fn_syms_.size())
2079 {
2080 if (s.net_num_removed_func_syms() == 1)
2081 out << indent
2082 << "1 Removed function symbol not referenced by debug info:\n\n";
2083 else if (s.net_num_removed_func_syms() > 0)
2084 out << indent
2085 << s.net_num_removed_func_syms()
2086 << " Removed function symbols not referenced by debug info:\n\n";
2087
2088 bool emitted = false;
2089 vector<elf_symbol_sptr> sorted_deleted_unrefed_fn_syms;
2090 sort_string_elf_symbol_map(d.priv_->deleted_unrefed_fn_syms_,
2091 sorted_deleted_unrefed_fn_syms);
2092 for (vector<elf_symbol_sptr>::const_iterator i =
2093 sorted_deleted_unrefed_fn_syms.begin();
2094 i != sorted_deleted_unrefed_fn_syms.end();
2095 ++i)
2096 {
2097 if (d.priv_->deleted_unrefed_fn_sym_is_suppressed((*i).get()))
2098 continue;
2099
2100 out << indent << " ";
2101 out << "[D] ";
2102
2103 show_linkage_name_and_aliases(out, "", **i,
2104 d.first_corpus()->get_fun_symbol_map());
2105 out << "\n";
2106 emitted = true;
2107 }
2108 if (emitted)
2109 out << "\n";
2110 }
2111
2112 // Report added function symbols not referenced by any debug info.
2113 if (ctxt->show_symbols_unreferenced_by_debug_info()
2114 && ctxt->show_added_symbols_unreferenced_by_debug_info()
2115 && d.priv_->added_unrefed_fn_syms_.size())
2116 {
2117 if (s.net_num_added_func_syms() == 1)
2118 out << indent
2119 << "1 Added function symbol not referenced by debug info:\n\n";
2120 else if (s.net_num_added_func_syms() > 0)
2121 out << indent
2122 << s.net_num_added_func_syms()
2123 << " Added function symbols not referenced by debug info:\n\n";
2124
2125 bool emitted = false;
2126 vector<elf_symbol_sptr> sorted_added_unrefed_fn_syms;
2127 sort_string_elf_symbol_map(d.priv_->added_unrefed_fn_syms_,
2128 sorted_added_unrefed_fn_syms);
2129 for (vector<elf_symbol_sptr>::const_iterator i =
2130 sorted_added_unrefed_fn_syms.begin();
2131 i != sorted_added_unrefed_fn_syms.end();
2132 ++i)
2133 {
2134 if (d.priv_->added_unrefed_fn_sym_is_suppressed((*i).get()))
2135 continue;
2136
2137 out << indent << " ";
2138 out << "[A] ";
2140 **i,
2141 d.second_corpus()->get_fun_symbol_map());
2142 out << "\n";
2143 emitted = true;
2144 }
2145 if (emitted)
2146 out << "\n";
2147 }
2148
2149 // Report removed variable symbols not referenced by any debug info.
2150 if (ctxt->show_symbols_unreferenced_by_debug_info()
2151 && d.priv_->deleted_unrefed_var_syms_.size())
2152 {
2153 if (s.net_num_removed_var_syms() == 1)
2154 out << indent
2155 << "1 Removed variable symbol not referenced by debug info:\n\n";
2156 else if (s.net_num_removed_var_syms() > 0)
2157 out << indent
2158 << s.net_num_removed_var_syms()
2159 << " Removed variable symbols not referenced by debug info:\n\n";
2160
2161 bool emitted = false;
2162 vector<elf_symbol_sptr> sorted_deleted_unrefed_var_syms;
2163 sort_string_elf_symbol_map(d.priv_->deleted_unrefed_var_syms_,
2164 sorted_deleted_unrefed_var_syms);
2165 for (vector<elf_symbol_sptr>::const_iterator i =
2166 sorted_deleted_unrefed_var_syms.begin();
2167 i != sorted_deleted_unrefed_var_syms.end();
2168 ++i)
2169 {
2170 if (d.priv_->deleted_unrefed_var_sym_is_suppressed((*i).get()))
2171 continue;
2172
2173 out << indent << " ";
2174 out << "[D] ";
2175
2177 (out, "", **i,
2178 d.first_corpus()->get_fun_symbol_map());
2179
2180 out << "\n";
2181 emitted = true;
2182 }
2183 if (emitted)
2184 out << "\n";
2185 }
2186
2187 // Report added variable symbols not referenced by any debug info.
2188 if (ctxt->show_symbols_unreferenced_by_debug_info()
2189 && ctxt->show_added_symbols_unreferenced_by_debug_info()
2190 && d.priv_->added_unrefed_var_syms_.size())
2191 {
2192 if (s.net_num_added_var_syms() == 1)
2193 out << indent
2194 << "1 Added variable symbol not referenced by debug info:\n\n";
2195 else if (s.net_num_added_var_syms() > 0)
2196 out << indent
2197 << s.net_num_added_var_syms()
2198 << " Added variable symbols not referenced by debug info:\n\n";
2199
2200 bool emitted = false;
2201 vector<elf_symbol_sptr> sorted_added_unrefed_var_syms;
2202 sort_string_elf_symbol_map(d.priv_->added_unrefed_var_syms_,
2203 sorted_added_unrefed_var_syms);
2204 for (vector<elf_symbol_sptr>::const_iterator i =
2205 sorted_added_unrefed_var_syms.begin();
2206 i != sorted_added_unrefed_var_syms.end();
2207 ++i)
2208 {
2209 if (d.priv_->added_unrefed_var_sym_is_suppressed((*i).get()))
2210 continue;
2211
2212 out << indent << " ";
2213 out << "[A] ";
2214 show_linkage_name_and_aliases(out, "", **i,
2215 d.second_corpus()->get_fun_symbol_map());
2216 out << "\n";
2217 emitted = true;
2218 }
2219 if (emitted)
2220 out << "\n";
2221 }
2222
2223 // Report added/removed/changed types not reacheable from public
2224 // interfaces.
2225 maybe_report_unreachable_type_changes(d, s, indent, out);
2226
2227 d.priv_->maybe_dump_diff_tree();
2228}
2229
2230} // end namespace comparison
2231}// end namespace libabigail
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_func_changed() const
Getter for the number of functions that have a change in their sub-types, minus the number of these f...
size_t net_num_vars_removed() const
Getter for the net number of removed variables.
size_t net_num_added_unreachable_types() const
Getter of the number of added types that are unreachable from public interfaces and that are *NOT* fi...
size_t 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_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_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from public interfaces and that have *NOT*...
size_t net_num_vars_changed() const
Getter for the number of variables that have a change in their sub-types, minus the number of these v...
An abstraction of a diff between between two abi corpus.
bool 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.
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_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.
void report_non_type_typedef_changes(const typedef_diff &d, std::ostream &out, const std::string &indent) const
For a typedef_diff node, report the local changes to the typedef rather the changes to its underlying...
bool is_filtered_out_without_looking_at_allowed_changes() const
Test if this diff tree node is to be filtered out for reporting purposes, but without considering the...
const diff_context_sptr context() const
Getter of the context of the current diff.
bool to_be_reported() const
Test if this diff tree node should be reported.
bool reported_once() const
Tests if a report has already been emitted for the current diff.
Abstraction of a diff between two function types.
const function_type_sptr first_function_type() const
Getter for the first subject of the diff.
const function_type_sptr second_function_type() const
Getter for the second subject of the diff.
The abstraction of a diff between two pointers.
diff_sptr underlying_type_diff() const
Getter for the diff between the pointed-to types of the pointers of this diff.
Abstraction of a diff between two qualified types.
diff_sptr leaf_underlying_type_diff() const
Getter for the diff between the most underlying non-qualified types of two qualified types.
const qualified_type_def_sptr second_qualified_type() const
Getter for the second qualified type of the diff.
const qualified_type_def_sptr first_qualified_type() const
Getter for the first qualified type of the diff.
The abstraction of a diff between two references.
reference_type_def_sptr first_reference() const
Getter for the first reference of the diff.
reference_type_def_sptr second_reference() const
Getter for the second reference of the diff.
const diff_sptr & underlying_type_diff() const
Getter for the diff between the two referred-to types.
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 basic type declarations.
const type_decl_sptr first_type_decl() const
Getter for the first subject of the type_decl_diff.
const type_decl_sptr second_type_decl() const
Getter for the second subject of the type_decl_diff.
Abstraction of a diff between two typedef_decl.
const typedef_decl_sptr second_typedef_decl() const
Getter for the second typedef_decl involved in the diff.
const typedef_decl_sptr first_typedef_decl() const
Getter for the firt typedef_decl involved in the diff.
const diff_sptr underlying_type_diff() const
Getter for the diff between the two underlying types of the typedefs.
shared_ptr< base_spec > base_spec_sptr
Convenience typedef.
Definition: abg-ir.h:4168
std::vector< enumerator > enumerators
Convenience typedef for a list of enumerator.
Definition: abg-ir.h:2702
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3057
bool has_enum_decl_only_def_change(const enum_type_decl_sptr &first, const enum_type_decl_sptr &second)
Test if two enum_sptr are different just by the fact that one is decl-only and the other one is defin...
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_harmless_name_change(const decl_base_sptr &f, const decl_base_sptr &s)
Test if two decls represents a harmless name change.
bool union_diff_has_harmless_changes(const diff *d)
Test if a union diff node does have changes that don't impact its size.
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 ...
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...
diff_category
An enum for the different categories that a diff tree node falls into, regarding the kind of changes ...
@ ACCESS_CHANGE_CATEGORY
This means the diff node (or at least one of its descendant nodes) carries access related changes,...
@ SUPPRESSED_CATEGORY
This means that a diff node was marked as suppressed by a user-provided suppression specification.
@ REDUNDANT_CATEGORY
A diff node in this category is redundant. That means it's present as a child of a other nodes in the...
@ NON_VIRT_MEM_FUN_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a non-virtual member fu...
@ PRIVATE_TYPE_CATEGORY
This means that a diff node was warked as being for a private type. That is, the diff node is meant t...
@ 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 ...
@ HARMLESS_DECL_NAME_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless declaration name change....
@ HARMLESS_UNION_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a harmless union change.
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...
bool maybe_report_diff_for_variable(const decl_base_sptr &decl1, const decl_base_sptr &decl2, const diff_context_sptr &ctxt, ostream &out, const string &indent)
Report the differences between two generic variables.
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.
string get_pretty_representation(diff *d)
Get a copy of the pretty representation of a diff node.
shared_ptr< base_diff > base_diff_sptr
Convenience typedef for a shared pointer to a base_diff type.
shared_ptr< class_diff > class_diff_sptr
Convenience typedef for a shared pointer on a class_diff type.
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.
void sort_changed_enumerators(const string_changed_enumerator_map &enumerators_map, changed_enumerators_type &sorted)
Sort a map of changed enumerators.
vector< changed_enumerator > changed_enumerators_type
Convenience typedef for a vector of changed enumerators.
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_enumerators(const string_enumerator_map &enumerators_map, enum_type_decl::enumerators &sorted)
Sort a map of enumerators by their value.
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...
shared_ptr< reference_type_def > reference_type_def_sptr
Convenience typedef for a shared pointer on a reference_type_def.
Definition: abg-fwd.h:232
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc: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
change_kind
A bitfield that gives callers of abigail::ir::equals() some insight about how different two internal ...
Definition: abg-ir.h:1309
@ SUBTYPE_CHANGE_KIND
This means that a given IR artifact has changes in some of its sub-types, with respect to the other a...
Definition: abg-ir.h:1329
@ ALL_LOCAL_CHANGES_MASK
Testing (anding) against this mask means that a given IR artifact has local differences,...
Definition: abg-ir.h:1324
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
bool types_have_similar_structure(const type_base_sptr &first, const type_base_sptr &second, bool indirect_type)
Test if two types have similar structures, even though they are (or can be) different.
Definition: abg-ir.cc:26870
class_or_union * is_class_or_union_type(const type_or_decl_base *t)
Test if a type is a class_or_union.
Definition: abg-ir.cc:10586
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:190
shared_ptr< function_type > function_type_sptr
Convenience typedef for a shared pointer on a function_type.
Definition: abg-fwd.h:207
shared_ptr< typedef_decl > typedef_decl_sptr
Convenience typedef for a shared pointer on a typedef_decl.
Definition: abg-fwd.h:164
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 equals(const decl_base &l, const decl_base &r, change_kind *k)
Compares two instances of decl_base.
Definition: abg-ir.cc:5268
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
string get_class_or_union_flat_representation(const class_or_union &cou, const string &indent, bool one_line, bool internal, bool qualified_names)
Get the flat representation of an instance of class_or_union type.
Definition: abg-ir.cc:9420
shared_ptr< enum_type_decl > enum_type_decl_sptr
Convenience typedef for shared pointer to a enum_type_decl.
Definition: abg-fwd.h:172
type_base_sptr strip_typedef(const type_base_sptr type)
Recursively returns the the underlying type of a typedef. The return type should not be a typedef of ...
Definition: abg-ir.cc:6764
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6674
const decl_base * get_type_declaration(const type_base *t)
Get the declaration for a given type.
Definition: abg-ir.cc:9881
shared_ptr< type_decl > type_decl_sptr
Convenience typedef for a shared pointer on a type_decl.
Definition: abg-fwd.h:158
translation_unit * get_translation_unit(const decl_base &decl)
Return the translation unit a declaration belongs to.
Definition: abg-ir.cc:9964
bool type_has_sub_type_changes(const type_base_sptr t_v1, const type_base_sptr t_v2)
Tests if the change of a given type effectively comes from just its sub-types. That is,...
Definition: abg-ir.cc:26511
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.