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