libabigail
abg-leaf-reporter.cc
Go to the documentation of this file.
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2017-2023 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 
9 /// @file
10 ///
11 /// This is the implementation of the
12 /// abigail::comparison::default_reporter type.
13 
14 #include "abg-comparison-priv.h"
15 #include "abg-reporter.h"
16 #include "abg-reporter-priv.h"
17 
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 numchanges = (d.sorted_changed_data_members().size()
678  + d.sorted_subtype_changed_data_members().size());
679 
680  size_t num_filtered =
681  (d.count_filtered_changed_data_members(/*local_only=*/true)
682  + d.count_filtered_subtype_changed_data_members(/*local_only=*/true));
683 
684  ABG_ASSERT(numchanges >= num_filtered);
685  size_t net_numchanges = numchanges - num_filtered;
686 
687  if (net_numchanges)
688  {
689  report_mem_header(out, change_kind, "data member", indent);
690 
691  for (var_diff_sptrs_type::const_iterator it =
692  d.sorted_changed_data_members().begin();
693  it != d.sorted_changed_data_members().end();
694  ++it)
695  if (diff_to_be_reported((*it).get()))
696  represent(*it, ctxt, out, indent + " ", /*local_only=*/true);
697 
698  for (var_diff_sptrs_type::const_iterator it =
699  d.sorted_subtype_changed_data_members().begin();
700  it != d.sorted_subtype_changed_data_members().end();
701  ++it)
702  if (diff_to_be_reported((*it).get()))
703  represent(*it, ctxt, out, indent + " ", /*local_only=*/true);
704  }
705 
706  // Report about data members replaced by an anonymous union data
707  // member.
709  }
710 }
711 
712 /// Report the changes carried by a @ref class_diff node.
713 ///
714 /// @param out the output stream to report to.
715 ///
716 /// @param indent the white space string to use for indentation.
717 void
718 leaf_reporter::report(const class_diff& d,
719  ostream& out,
720  const string& indent) const
721 {
722  if (!diff_to_be_reported(&d))
723  return;
724 
725  RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_subject(),
726  d.second_subject());
727 
728  string name = d.first_subject()->get_pretty_representation();
729 
730  // Now report the changes about the differents parts of the type.
731  class_decl_sptr first = d.first_class_decl(),
732  second = d.second_class_decl();
733 
734  report_name_size_and_alignment_changes(first, second, d.context(),
735  out, indent);
736 
737  const diff_context_sptr& ctxt = d.context();
738  maybe_report_diff_for_member(first, second, ctxt, out, indent);
739 
740  d.class_or_union_diff::report(out, indent);
741 
742  maybe_report_base_class_reordering(d, out, indent);
743 
745 
746  d.reported_once(true);
747 }
748 
749 /// Report the changes carried by a @ref union_diff node.
750 ///
751 /// @param out the output stream to report to.
752 ///
753 /// @param indent the white space string to use for indentation.
754 void
755 leaf_reporter::report(const union_diff& d,
756  ostream& out,
757  const string& indent) const
758 {
759  if (!diff_to_be_reported(&d))
760  return;
761 
762  RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_subject(),
763  d.second_subject());
764 
765  // Now report the changes about the differents parts of the type.
766  union_decl_sptr first = d.first_union_decl(), second = d.second_union_decl();
767 
768  report_name_size_and_alignment_changes(first, second, d.context(),
769  out, indent);
770 
771  maybe_report_diff_for_member(first, second,d. context(), out, indent);
772 
773  d.class_or_union_diff::report(out, indent);
774 
776 }
777 
778 /// Report the changes carried by a @ref distinct_diff node.
779 ///
780 /// @param out the output stream to report to.
781 ///
782 /// @param indent the white space string to use for indentation.
783 void
784 leaf_reporter::report(const distinct_diff& d,
785  ostream& out,
786  const string& indent) const
787 {
788  if (!diff_to_be_reported(&d))
789  return;
790 
791  type_or_decl_base_sptr f = d.first(), s = d.second();
792 
793  string f_repr = f ? f->get_pretty_representation() : "'void'";
794  string s_repr = s ? s->get_pretty_representation() : "'void'";
795 
796  diff_sptr diff = d.compatible_child_diff();
797 
798  string compatible = diff ? " to compatible type '": " to '";
799 
800  out << indent << "entity changed from '" << f_repr << "'"
801  << compatible << s_repr << "'";
802  report_loc_info(s, *d.context(), out);
803  out << "\n";
804 
805  report_size_and_alignment_changes(f, s, d.context(), out, indent);
807 }
808 
809 /// Report the changes carried by a @ref function_decl_diff node.
810 ///
811 /// @param out the output stream to report to.
812 ///
813 /// @param indent the white space string to use for indentation.
814 void
815 leaf_reporter::report(const function_decl_diff& d,
816  ostream& out,
817  const string& indent) const
818 {
819  if (!diff_to_be_reported(&d))
820  return;
821 
822  maybe_report_diff_for_member(d.first_function_decl(),
823  d.second_function_decl(),
824  d.context(), out, indent);
825 
826  function_decl_sptr ff = d.first_function_decl();
827  function_decl_sptr sf = d.second_function_decl();
828 
829  diff_context_sptr ctxt = d.context();
830  corpus_sptr fc = ctxt->get_corpus_diff()->first_corpus();
831  corpus_sptr sc = ctxt->get_corpus_diff()->second_corpus();
832 
833  string qn1 = ff->get_qualified_name(), qn2 = sf->get_qualified_name(),
834  linkage_names1, linkage_names2;
835  elf_symbol_sptr s1 = ff->get_symbol(), s2 = sf->get_symbol();
836 
837  if (s1)
838  linkage_names1 = s1->get_id_string();
839  if (s2)
840  linkage_names2 = s2->get_id_string();
841 
842  // If the symbols for ff and sf have aliases, get all the names of
843  // the aliases;
844  if (fc && s1)
845  linkage_names1 =
846  s1->get_aliases_id_string(fc->get_fun_symbol_map());
847  if (sc && s2)
848  linkage_names2 =
849  s2->get_aliases_id_string(sc->get_fun_symbol_map());
850 
851  /// If the set of linkage names of the function have changed, report
852  /// it.
853  if (linkage_names1 != linkage_names2)
854  {
855  if (linkage_names1.empty())
856  {
857  out << indent << ff->get_pretty_representation()
858  << " didn't have any linkage name, and it now has: '"
859  << linkage_names2 << "'\n";
860  }
861  else if (linkage_names2.empty())
862  {
863  out << indent << ff->get_pretty_representation()
864  << " did have linkage names '" << linkage_names1
865  << "'\n"
866  << indent << "but it doesn't have any linkage name anymore\n";
867  }
868  else
869  out << indent << "linkage names of "
870  << ff->get_pretty_representation()
871  << "\n" << indent << "changed from '"
872  << linkage_names1 << "' to '" << linkage_names2 << "'\n";
873  }
874 
875  if (qn1 != qn2
876  && diff_to_be_reported(d.type_diff().get()))
877  {
878  // So the function has sub-type changes that are to be
879  // reported. Let's see if the function name changed too; if it
880  // did, then we'd report that change right before reporting the
881  // sub-type changes.
882  string frep1 = d.first_function_decl()->get_pretty_representation(),
883  frep2 = d.second_function_decl()->get_pretty_representation();
884  out << indent << "'" << frep1 << " {" << linkage_names1<< "}"
885  << "' now becomes '"
886  << frep2 << " {" << linkage_names2 << "}" << "'\n";
887  }
888 
889  maybe_report_diff_for_symbol(ff->get_symbol(),
890  sf->get_symbol(),
891  ctxt, out, indent);
892 
893  // Now report about inline-ness changes
894  if (ff->is_declared_inline() != sf->is_declared_inline())
895  {
896  out << indent;
897  if (ff->is_declared_inline())
898  out << sf->get_pretty_representation()
899  << " is not declared inline anymore\n";
900  else
901  out << sf->get_pretty_representation()
902  << " is now declared inline\n";
903  }
904 
905  // Report about vtable offset changes.
906  if (is_member_function(ff) && is_member_function(sf))
907  {
908  bool ff_is_virtual = get_member_function_is_virtual(ff),
909  sf_is_virtual = get_member_function_is_virtual(sf);
910  if (ff_is_virtual != sf_is_virtual)
911  {
912  out << indent;
913  if (ff_is_virtual)
914  out << ff->get_pretty_representation()
915  << " is no more declared virtual\n";
916  else
917  out << ff->get_pretty_representation()
918  << " is now declared virtual\n";
919  }
920 
921  size_t ff_vtable_offset = get_member_function_vtable_offset(ff),
922  sf_vtable_offset = get_member_function_vtable_offset(sf);
923  if (ff_is_virtual && sf_is_virtual
924  && (ff_vtable_offset != sf_vtable_offset))
925  {
926  out << indent
927  << "the vtable offset of " << ff->get_pretty_representation()
928  << " changed from " << ff_vtable_offset
929  << " to " << sf_vtable_offset << "\n";
930  }
931 
932  // the classes of the two member functions.
933  class_decl_sptr fc =
934  is_class_type(is_method_type(ff->get_type())->get_class_type());
935  class_decl_sptr sc =
936  is_class_type(is_method_type(sf->get_type())->get_class_type());
937 
938  // Detect if the virtual member function changes above
939  // introduced a vtable change or not.
940  bool vtable_added = false, vtable_removed = false;
941  if (!fc->get_is_declaration_only() && !sc->get_is_declaration_only())
942  {
943  vtable_added = !fc->has_vtable() && sc->has_vtable();
944  vtable_removed = fc->has_vtable() && !sc->has_vtable();
945  }
946  bool vtable_changed = ((ff_is_virtual != sf_is_virtual)
947  || (ff_vtable_offset != sf_vtable_offset));
948  bool incompatible_change = (ff_vtable_offset != sf_vtable_offset);
949 
950  if (vtable_added)
951  out << indent
952  << " note that a vtable was added to "
953  << fc->get_pretty_representation()
954  << "\n";
955  else if (vtable_removed)
956  out << indent
957  << " note that the vtable was removed from "
958  << fc->get_pretty_representation()
959  << "\n";
960  else if (vtable_changed)
961  {
962  out << indent;
963  if (incompatible_change)
964  out << " note that this is an ABI incompatible "
965  "change to the vtable of ";
966  else
967  out << " note that this induces a change to the vtable of ";
968  out << fc->get_pretty_representation()
969  << "\n";
970  }
971 
972  }
973 
974  // Report about function type differences.
975  if (diff_to_be_reported(d.type_diff().get()))
976  d.type_diff()->report(out, indent);
977 }
978 
979 /// Report the changes carried by a @ref var_diff node.
980 ///
981 /// @param out the output stream to report to.
982 ///
983 /// @param indent the white space string to use for indentation.
984 void
985 leaf_reporter::report(const var_diff& d,
986  ostream& out,
987  const string& indent) const
988 {
989  if (!diff_to_be_reported(&d))
990  return;
991 
992  decl_base_sptr first = d.first_var(), second = d.second_var();
993  string n = first->get_pretty_representation();
994 
996  d.context(),
997  out, indent);
998 
999  maybe_report_diff_for_symbol(d.first_var()->get_symbol(),
1000  d.second_var()->get_symbol(),
1001  d.context(), out, indent);
1002 
1003  maybe_report_diff_for_member(first, second, d.context(), out, indent);
1004 
1005  if (diff_sptr dif = d.type_diff())
1006  {
1007  if (diff_to_be_reported(dif.get()))
1008  {
1009  RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(dif, "type");
1010  out << indent << "type of variable changed:\n";
1011  dif->report(out, indent + " ");
1012  }
1013  }
1014 }
1015 
1016 /// Report the changes carried by a @ref translation_unit_diff node.
1017 ///
1018 /// @param out the output stream to report to.
1019 ///
1020 /// @param indent the white space string to use for indentation.
1021 void
1022 leaf_reporter::report(const translation_unit_diff& d,
1023  ostream& out,
1024  const string& indent) const
1025 {
1026  if (!d.to_be_reported())
1027  return;
1028 
1029  static_cast<const scope_diff&>(d).report(out, indent);
1030 }
1031 
1032 /// Report the changes carried by a @ref corpus_diff node.
1033 ///
1034 /// @param out the output stream to report to.
1035 ///
1036 /// @param indent the white space string to use for indentation.
1037 void
1038 leaf_reporter::report(const corpus_diff& d,
1039  ostream& out,
1040  const string& indent) const
1041 {
1042  if (!d.has_changes())
1043  return;
1044 
1045  const corpus_diff::diff_stats &s =
1046  const_cast<corpus_diff&>(d).
1047  apply_filters_and_suppressions_before_reporting();
1048 
1049  const diff_context_sptr& ctxt = d.context();
1050 
1051  d.priv_->emit_diff_stats(s, out, indent);
1052  if (ctxt->show_stats_only())
1053  return;
1054  out << "\n";
1055 
1056  if (ctxt->show_soname_change()
1057  && !d.priv_->sonames_equal_)
1058  out << indent << "SONAME changed from '"
1059  << d.first_corpus()->get_soname() << "' to '"
1060  << d.second_corpus()->get_soname() << "'\n\n";
1061 
1062  if (ctxt->show_architecture_change()
1063  && !d.priv_->architectures_equal_)
1064  out << indent << "architecture changed from '"
1065  << d.first_corpus()->get_architecture_name() << "' to '"
1066  << d.second_corpus()->get_architecture_name() << "'\n\n";
1067 
1068  /// Report removed/added/changed functions.
1069  if (ctxt->show_deleted_fns())
1070  {
1071  if (s.net_num_func_removed() == 1)
1072  out << indent << "1 Removed function:\n\n";
1073  else if (s.net_num_func_removed() > 1)
1074  out << indent << s.net_num_func_removed() << " Removed functions:\n\n";
1075 
1076  bool emitted = false;
1077  corpus::functions sorted_deleted_fns;
1078  sort_string_function_ptr_map(d.priv_->deleted_fns_, sorted_deleted_fns);
1079  for (auto f : sorted_deleted_fns)
1080  {
1081  if (d.priv_->deleted_function_is_suppressed(f))
1082  continue;
1083 
1084  out << indent
1085  << " ";
1086  out << "[D] ";
1087  out << "'" << f->get_pretty_representation() << "'";
1088  if (ctxt->show_linkage_names())
1089  {
1090  out << " {";
1091  show_linkage_name_and_aliases(out, "", *f->get_symbol(),
1092  d.first_corpus()->get_fun_symbol_map());
1093  out << "}";
1094  }
1095  out << "\n";
1097  {
1098  class_decl_sptr c =
1099  is_class_type(is_method_type(f->get_type())->get_class_type());
1100  out << indent
1101  << " "
1102  << "note that this removes an entry from the vtable of "
1103  << c->get_pretty_representation()
1104  << "\n";
1105  }
1106  emitted = true;
1107  }
1108  if (emitted)
1109  out << "\n";
1110  }
1111 
1112  if (ctxt->show_added_fns())
1113  {
1114  if (s.net_num_func_added() == 1)
1115  out << indent << "1 Added function:\n\n";
1116  else if (s.net_num_func_added() > 1)
1117  out << indent << s.net_num_func_added()
1118  << " Added functions:\n\n";
1119  bool emitted = false;
1120  corpus::functions sorted_added_fns;
1121  sort_string_function_ptr_map(d.priv_->added_fns_, sorted_added_fns);
1122  for (auto f : sorted_added_fns)
1123  {
1124  if (d.priv_->added_function_is_suppressed(f))
1125  continue;
1126 
1127  out
1128  << indent
1129  << " ";
1130  out << "[A] ";
1131  out << "'"
1132  << f->get_pretty_representation()
1133  << "'";
1134  if (ctxt->show_linkage_names())
1135  {
1136  out << " {";
1138  (out, "", *f->get_symbol(),
1139  d.second_corpus()->get_fun_symbol_map());
1140  out << "}";
1141  }
1142  out << "\n";
1144  {
1145  class_decl_sptr c =
1146  is_class_type(is_method_type(f->get_type())->get_class_type());
1147  out << indent
1148  << " "
1149  << "note that this adds a new entry to the vtable of "
1150  << c->get_pretty_representation()
1151  << "\n";
1152  }
1153  emitted = true;
1154  }
1155  if (emitted)
1156  out << "\n";
1157  }
1158 
1159  if (ctxt->show_changed_fns())
1160  {
1161  // Show changed functions.
1162  size_t num_changed = s.net_num_leaf_func_changes();
1163  if (num_changed == 1)
1164  out << indent << "1 function with some sub-type change:\n\n";
1165  else if (num_changed > 1)
1166  out << indent << num_changed
1167  << " functions with some sub-type change:\n\n";
1168 
1169  vector<function_decl_diff_sptr> sorted_changed_fns;
1170  sort_string_function_decl_diff_sptr_map(d.priv_->changed_fns_map_,
1171  sorted_changed_fns);
1172  for (vector<function_decl_diff_sptr>::const_iterator i =
1173  sorted_changed_fns.begin();
1174  i != sorted_changed_fns.end();
1175  ++i)
1176  {
1177  diff_sptr diff = *i;
1178  if (!diff)
1179  continue;
1180 
1181  if (diff_to_be_reported(diff.get()))
1182  {
1183  function_decl_sptr fn = (*i)->first_function_decl();
1184  out << indent << " [C] '"
1185  << fn->get_pretty_representation() << "'";
1186  report_loc_info((*i)->second_function_decl(), *ctxt, out);
1187  out << " has some sub-type changes:\n";
1188  if ((fn->get_symbol()->has_aliases()
1189  && !(is_member_function(fn)
1191  && !(is_member_function(fn)
1193  || (is_c_language(get_translation_unit(fn)->get_language())
1194  && fn->get_name() != fn->get_linkage_name()))
1195  {
1196  int number_of_aliases =
1197  fn->get_symbol()->get_number_of_aliases();
1198  if (number_of_aliases == 0)
1199  {
1200  out << indent << " "
1201  << "Please note that the exported symbol of "
1202  "this function is "
1203  << fn->get_symbol()->get_id_string()
1204  << "\n";
1205  }
1206  else
1207  {
1208  out << indent << " "
1209  << "Please note that the symbol of this function is "
1210  << fn->get_symbol()->get_id_string()
1211  << "\n and it aliases symbol";
1212  if (number_of_aliases > 1)
1213  out << "s";
1214  out << ": "
1215  << fn->get_symbol()->get_aliases_id_string(false)
1216  << "\n";
1217  }
1218  }
1219  diff->report(out, indent + " ");
1220  // Extra spacing.
1221  out << "\n";
1222  }
1223  }
1224  // Changed functions have extra spacing already. No new line here.
1225  }
1226 
1227  // Report removed/added/changed variables.
1228  if (ctxt->show_deleted_vars())
1229  {
1230  if (s.net_num_vars_removed() == 1)
1231  out << indent << "1 Removed variable:\n\n";
1232  else if (s.net_num_vars_removed() > 1)
1233  out << indent << s.net_num_vars_removed()
1234  << " Removed variables:\n\n";
1235  string n;
1236  bool emitted = false;
1237  corpus::variables sorted_deleted_vars;
1238  sort_string_var_ptr_map(d.priv_->deleted_vars_, sorted_deleted_vars);
1239  for (auto v : sorted_deleted_vars)
1240  {
1241  if (d.priv_->deleted_variable_is_suppressed(v))
1242  continue;
1243 
1244  n = v->get_pretty_representation();
1245 
1246  out << indent
1247  << " ";
1248  out << "[D] ";
1249  out << "'"
1250  << n
1251  << "'";
1252  if (ctxt->show_linkage_names())
1253  {
1254  out << " {";
1255  show_linkage_name_and_aliases(out, "", *v->get_symbol(),
1256  d.first_corpus()->get_var_symbol_map());
1257  out << "}";
1258  }
1259  out << "\n";
1260  emitted = true;
1261  }
1262  if (emitted)
1263  out << "\n";
1264  }
1265 
1266  if (ctxt->show_added_vars())
1267  {
1268  if (s.net_num_vars_added() == 1)
1269  out << indent << "1 Added variable:\n\n";
1270  else if (s.net_num_vars_added() > 1)
1271  out << indent << s.net_num_vars_added()
1272  << " Added variables:\n\n";
1273  string n;
1274  bool emitted = false;
1275  corpus::variables sorted_added_vars;
1276  sort_string_var_ptr_map(d.priv_->added_vars_, sorted_added_vars);
1277  for (auto v : sorted_added_vars)
1278  {
1279  if (d.priv_->added_variable_is_suppressed(v))
1280  continue;
1281 
1282  n = v->get_pretty_representation();
1283 
1284  out << indent
1285  << " ";
1286  out << "[A] ";
1287  out << "'" << n << "'";
1288  if (ctxt->show_linkage_names())
1289  {
1290  out << " {";
1291  show_linkage_name_and_aliases(out, "", *v->get_symbol(),
1292  d.second_corpus()->get_var_symbol_map());
1293  out << "}";
1294  }
1295  out << "\n";
1296  emitted = true;
1297  }
1298  if (emitted)
1299  out << "\n";
1300  }
1301 
1302  if (ctxt->show_changed_vars())
1303  {
1304  size_t num_changed = s.net_num_leaf_var_changes();
1305  if (num_changed == 1)
1306  out << indent << "1 Changed variable:\n\n";
1307  else if (num_changed > 1)
1308  out << indent << num_changed
1309  << " Changed variables:\n\n";
1310  string n1, n2;
1311  for (auto d : d.priv_->sorted_changed_vars_)
1312  {
1313  diff_sptr diff = d;
1314 
1315  if (!diff)
1316  continue;
1317 
1318  if (!diff_to_be_reported(diff.get()))
1319  continue;
1320 
1321  n1 = diff->first_subject()->get_pretty_representation();
1322  n2 = diff->second_subject()->get_pretty_representation();
1323 
1324  out << indent << " [C] '" << n1 << "' was changed";
1325  if (n1 != n2)
1326  out << " to '" << n2 << "'";
1327  report_loc_info(diff->second_subject(), *ctxt, out);
1328  out << ":\n";
1329  diff->report(out, indent + " ");
1330  // Extra spacing.
1331  out << "\n";
1332  }
1333  // Changed variables have extra spacing already. No new line here.
1334  }
1335 
1336  // Report removed function symbols not referenced by any debug info.
1337  if (ctxt->show_symbols_unreferenced_by_debug_info()
1338  && d.priv_->deleted_unrefed_fn_syms_.size())
1339  {
1340  if (s.net_num_removed_func_syms() == 1)
1341  out << indent
1342  << "1 Removed function symbol not referenced by debug info:\n\n";
1343  else if (s.net_num_removed_func_syms() > 0)
1344  out << indent
1345  << s.net_num_removed_func_syms()
1346  << " Removed function symbols not referenced by debug info:\n\n";
1347 
1348  bool emitted = false;
1349  vector<elf_symbol_sptr> sorted_deleted_unrefed_fn_syms;
1350  sort_string_elf_symbol_map(d.priv_->deleted_unrefed_fn_syms_,
1351  sorted_deleted_unrefed_fn_syms);
1352  for (vector<elf_symbol_sptr>::const_iterator i =
1353  sorted_deleted_unrefed_fn_syms.begin();
1354  i != sorted_deleted_unrefed_fn_syms.end();
1355  ++i)
1356  {
1357  if (d.priv_->deleted_unrefed_fn_sym_is_suppressed((*i).get()))
1358  continue;
1359 
1360  out << indent << " ";
1361  out << "[D] ";
1362 
1363  show_linkage_name_and_aliases(out, "", **i,
1364  d.first_corpus()->get_fun_symbol_map());
1365  out << "\n";
1366  emitted = true;
1367  }
1368  if (emitted)
1369  out << "\n";
1370  }
1371 
1372  // Report added function symbols not referenced by any debug info.
1373  if (ctxt->show_symbols_unreferenced_by_debug_info()
1374  && ctxt->show_added_symbols_unreferenced_by_debug_info()
1375  && d.priv_->added_unrefed_fn_syms_.size())
1376  {
1377  if (s.net_num_added_func_syms() == 1)
1378  out << indent
1379  << "1 Added function symbol not referenced by debug info:\n\n";
1380  else if (s.net_num_added_func_syms() > 0)
1381  out << indent
1382  << s.net_num_added_func_syms()
1383  << " Added function symbols not referenced by debug info:\n\n";
1384 
1385  bool emitted = false;
1386  vector<elf_symbol_sptr> sorted_added_unrefed_fn_syms;
1387  sort_string_elf_symbol_map(d.priv_->added_unrefed_fn_syms_,
1388  sorted_added_unrefed_fn_syms);
1389  for (vector<elf_symbol_sptr>::const_iterator i =
1390  sorted_added_unrefed_fn_syms.begin();
1391  i != sorted_added_unrefed_fn_syms.end();
1392  ++i)
1393  {
1394  if (d.priv_->added_unrefed_fn_sym_is_suppressed((*i).get()))
1395  continue;
1396 
1397  out << indent << " ";
1398  out << "[A] ";
1400  **i,
1401  d.second_corpus()->get_fun_symbol_map());
1402  out << "\n";
1403  emitted = true;
1404  }
1405  if (emitted)
1406  out << "\n";
1407  }
1408 
1409  // Report removed variable symbols not referenced by any debug info.
1410  if (ctxt->show_symbols_unreferenced_by_debug_info()
1411  && d.priv_->deleted_unrefed_var_syms_.size())
1412  {
1413  if (s.net_num_removed_var_syms() == 1)
1414  out << indent
1415  << "1 Removed variable symbol not referenced by debug info:\n\n";
1416  else if (s.net_num_removed_var_syms() > 0)
1417  out << indent
1418  << s.net_num_removed_var_syms()
1419  << " Removed variable symbols not referenced by debug info:\n\n";
1420 
1421  bool emitted = false;
1422  vector<elf_symbol_sptr> sorted_deleted_unrefed_var_syms;
1423  sort_string_elf_symbol_map(d.priv_->deleted_unrefed_var_syms_,
1424  sorted_deleted_unrefed_var_syms);
1425  for (vector<elf_symbol_sptr>::const_iterator i =
1426  sorted_deleted_unrefed_var_syms.begin();
1427  i != sorted_deleted_unrefed_var_syms.end();
1428  ++i)
1429  {
1430  if (d.priv_->deleted_unrefed_var_sym_is_suppressed((*i).get()))
1431  continue;
1432 
1433  out << indent << " ";
1434  out << "[D] ";
1435 
1437  (out, "", **i,
1438  d.first_corpus()->get_fun_symbol_map());
1439 
1440  out << "\n";
1441  emitted = true;
1442  }
1443  if (emitted)
1444  out << "\n";
1445  }
1446 
1447  // Report added variable symbols not referenced by any debug info.
1448  if (ctxt->show_symbols_unreferenced_by_debug_info()
1449  && ctxt->show_added_symbols_unreferenced_by_debug_info()
1450  && d.priv_->added_unrefed_var_syms_.size())
1451  {
1452  if (s.net_num_added_var_syms() == 1)
1453  out << indent
1454  << "1 Added variable symbol not referenced by debug info:\n\n";
1455  else if (s.net_num_added_var_syms() > 0)
1456  out << indent
1457  << s.net_num_added_var_syms()
1458  << " Added variable symbols not referenced by debug info:\n\n";
1459 
1460  bool emitted = false;
1461  vector<elf_symbol_sptr> sorted_added_unrefed_var_syms;
1462  sort_string_elf_symbol_map(d.priv_->added_unrefed_var_syms_,
1463  sorted_added_unrefed_var_syms);
1464  for (vector<elf_symbol_sptr>::const_iterator i =
1465  sorted_added_unrefed_var_syms.begin();
1466  i != sorted_added_unrefed_var_syms.end();
1467  ++i)
1468  {
1469  if (d.priv_->added_unrefed_var_sym_is_suppressed((*i).get()))
1470  continue;
1471 
1472  out << indent << " ";
1473  out << "[A] ";
1474  show_linkage_name_and_aliases(out, "", **i,
1475  d.second_corpus()->get_fun_symbol_map());
1476  out << "\n";
1477  emitted = true;
1478  }
1479  if (emitted)
1480  out << "\n";
1481  }
1482 
1483  // Now show the changed types.
1484  const diff_maps& leaf_diffs = d.get_leaf_diffs();
1485  report_type_changes_from_diff_maps(*this, leaf_diffs, out, indent);
1486 
1487  // Report added/removed/changed types not reacheable from public
1488  // interfaces.
1489  maybe_report_unreachable_type_changes(d, s, indent, out);
1490 
1491  d.priv_->maybe_dump_diff_tree();
1492 }
1493 } // end namespace comparison
1494 } // end namespace abigail
The private data and functions of the abigail::ir::comparison types.
#define ABG_ASSERT(cond)
This is a wrapper around the 'assert' glibc call. It allows for its argument to have side effects,...
Definition: abg-fwd.h:1714
The declaration of the reporting types of libabigail's diff engine.
The abstraction of a diff between two arrays.
const diff_sptr & element_type_diff() const
Getter for the diff between the two types of array elements.
const array_type_def_sptr second_array() const
Getter for the second array of the diff.
const array_type_def_sptr first_array() const
Getter for the first array of the diff.
This is a document class that aims to capture statistics about the changes carried by a corpus_diff t...
size_t net_num_leaf_var_changes() const
Getter for the net number of leaf variable change diff nodes.
size_t net_num_vars_removed() const
Getter for the net number of removed variables.
size_t net_num_added_unreachable_types() const
Getter of the number of added types that are unreachable from public interfaces and that are *NOT* fi...
size_t net_num_added_func_syms() const
Getter of the net number of added function symbols that are not referenced by any debug info.
size_t net_num_removed_func_syms() const
Getter of the net number of removed function symbols that are not referenced by any debug info.
size_t net_num_removed_var_syms() const
Getter of the net number of removed variable symbols that are not referenced by any debug info.
size_t net_num_func_removed() const
Getter for the net number of function removed.
size_t net_num_func_added() const
Getter for the net number of added functions.
size_t net_num_removed_unreachable_types() const
Getter of the number of removed types that are not reachable from public interfaces and that have *NO...
size_t net_num_leaf_type_changes() const
Getter for the net number of leaf type change diff nodes.
size_t net_num_added_var_syms() const
Getter of the net number of added variable symbols that are not referenced by any debug info.
size_t net_num_vars_added() const
Getter for the net number of added variables.
size_t net_num_leaf_func_changes() const
Getter for the net number of leaf function change diff nodes.
size_t net_num_changed_unreachable_types() const
Getter of the number of changed types that are unreachable from public interfaces and that have *NOT*...
An abstraction of a diff between between two abi corpus.
bool soname_changed() const
Test if the soname of the underlying corpus has changed.
bool architecture_changed() const
Test if the architecture of the underlying corpus has changed.
bool report_local_ptr_to_mbr_type_changes(const ptr_to_mbr_diff &d, std::ostream &out, const std::string &indent="") const
Report the local changes carried by a ptr_to_mbr_diff diff node.
bool report_local_qualified_type_changes(const qualified_type_diff &d, std::ostream &out, const std::string &indent) const
For a qualified_type_diff node, report the changes that are local.
void report_local_function_type_changes(const function_type_diff &d, std::ostream &out, const std::string &indent) const
For a function_type_diff node, report the local changes carried by the diff node.
void report_underlying_changes_of_qualified_type(const qualified_type_diff &d, ostream &out, const string &indent) const
For a qualified_type_diff node, report the changes of its underlying type.
void report_local_reference_type_changes(const reference_diff &d, std::ostream &out, const std::string &indent) const
For a @reference_diff node, report the local changes carried by the diff node.
This type contains maps. Each map associates a type name to a diff of that type. Not all kinds of dif...
const string_diff_ptr_map & get_function_decl_diff_map() const
Getter of the map that contains function decl diffs.
const string_diff_ptr_map & get_var_decl_diff_map() const
Getter of the map that contains var decl diffs.
The abstraction of a change between two ABI artifacts, a.k.a an artifact change.
const diff_context_sptr context() const
Getter of the context of the current diff.
virtual enum change_kind has_local_changes() const =0
Pure interface to know if the current instance of @diff carries a local change. A local change is a c...
bool to_be_reported() const
Test if this diff tree node should be reported.
Abstraction of a diff between two function parameters.
const function_decl::parameter_sptr first_parameter() const
Getter for the first subject of this diff node.
diff_sptr type_diff() const
Getter for the diff representing the changes on the type of the function parameter involved in the cu...
Abstraction of a diff between two function types.
virtual bool diff_has_net_changes(const corpus_diff *d) const
Test if a given instance of corpus_diff carries changes whose reports are not suppressed by any suppr...
void report_changes_from_diff_maps(const diff_maps &, std::ostream &out, const std::string &indent) const
Report the changes carried by an instance of diff_maps.
virtual bool diff_to_be_reported(const diff *d) const
Test if a diff node is to be reported by the current instance of leaf_reporter.
The abstraction of a diff between two ptr_to_mbr_type.
Abstraction of a diff between two qualified types.
The base class of all the reporting classes.
Definition: abg-reporter.h:58
virtual bool diff_to_be_reported(const diff *d) const
Tests if the diff node is to be reported.
The abstraction of the diff between two subrange types.
const array_type_def::subrange_sptr second_subrange() const
Getter of the second subrange of the current instance subrange_diff.
const array_type_def::subrange_sptr first_subrange() const
Getter of the first subrange of the current instance subrange_diff.
Abstraction of a diff between two typedef_decl.
Abstracts a diff between two instances of var_decl.
vector< const var_decl * > variables
Convenience typedef for std::vector<abigail::ir::var_decl*>
Definition: abg-corpus.h:37
vector< const function_decl * > functions
Convenience typedef for std::vector<abigail::ir::function_decl*>
Definition: abg-corpus.h:31
shared_ptr< parameter > parameter_sptr
Convenience typedef for a shared pointer on a function_decl::parameter.
Definition: abg-ir.h:3131
bool has_class_decl_only_def_change(const class_or_union_sptr &first, const class_or_union_sptr &second)
Test if two class_or_union_sptr are different just by the fact that one is decl-only and the other on...
shared_ptr< diff > diff_sptr
Convenience typedef for a shared_ptr for the diff class.
Definition: abg-fwd.h:76
void show_linkage_name_and_aliases(ostream &out, const string &indent, const elf_symbol &symbol, const string_elf_symbols_map_type &sym_map)
For a given symbol, emit a string made of its name and version. The string also contains the list of ...
vector< diff * > diff_ptrs_type
Convenience typedef for a vector of diff*.
void maybe_report_interfaces_impacted_by_diff(const diff *d, ostream &out, const string &indent)
If a given diff node impacts some public interfaces, then report about those impacted interfaces on a...
void sort_string_diff_ptr_map(const string_diff_ptr_map &map, diff_ptrs_type &sorted)
Sort a map ofg string -> diff* into a vector of diff_ptr. The diff_ptr are sorted lexicographically w...
@ NON_VIRT_MEM_FUN_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries an addition or removal of a non-virtual member fu...
@ TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
This means that a diff node in the sub-tree carries a type that was declaration-only and that is now ...
void sort_string_function_ptr_map(const string_function_ptr_map &map, vector< const function_decl * > &sorted)
Sort an instance of string_function_ptr_map map and stuff a resulting sorted vector of pointers to fu...
void maybe_report_diff_for_symbol(const elf_symbol_sptr &symbol1, const elf_symbol_sptr &symbol2, const diff_context_sptr &ctxt, ostream &out, const string &indent)
Report the difference between two ELF symbols, if there is any.
void maybe_report_unreachable_type_changes(const corpus_diff &d, const corpus_diff::diff_stats &s, const string &indent, ostream &out)
Report changes about types that are not reachable from global functions and variables,...
shared_ptr< diff_context > diff_context_sptr
Convenience typedef for a shared pointer of diff_context.
Definition: abg-fwd.h:68
void report_size_and_alignment_changes(type_or_decl_base_sptr first, type_or_decl_base_sptr second, diff_context_sptr ctxt, ostream &out, const string &indent)
Report the size and alignment changes of a type.
bool report_loc_info(const type_or_decl_base_sptr &tod, const diff_context &ctxt, ostream &out)
void sort_string_elf_symbol_map(const string_elf_symbol_map &map, vector< elf_symbol_sptr > &sorted)
Sort a map of string -> pointer to elf_symbol.
void sort_string_function_decl_diff_sptr_map(const string_function_decl_diff_sptr_map &map, function_decl_diff_sptrs_type &sorted)
Sort the values of a string_function_decl_diff_sptr_map map and store the result in a vector of funct...
void maybe_report_base_class_reordering(const class_diff &d, ostream &out, const string &indent)
Report about the base classes of a class having been re-ordered.
void represent_data_member(var_decl_sptr d, const diff_context_sptr &ctxt, ostream &out, const string &indent)
Stream a string representation for a data member.
void maybe_report_data_members_replaced_by_anon_dm(const class_or_union_diff &d, ostream &out, const string &indent)
Report about data members replaced by an anonymous data member without changing the overall bit-layou...
bool maybe_report_diff_for_member(const decl_base_sptr &decl1, const decl_base_sptr &decl2, const diff_context_sptr &ctxt, ostream &out, const string &indent)
Report the differences in access specifiers and static-ness for class members.
void report_mem_header(ostream &out, size_t number, size_t num_filtered, diff_kind k, const string &section_name, const string &indent)
Output the header preceding the the report for insertion/deletion/change of a part of a class....
void sort_data_members(const string_decl_base_sptr_map &data_members, vector< decl_base_sptr > &sorted)
Sort a map of data members by the offset of their initial value.
void sort_string_var_ptr_map(const string_var_ptr_map &map, vector< const var_decl * > &sorted)
Sort a map of string -> pointer to var_decl.
unordered_map< string, diff * > string_diff_ptr_map
Convenience typedef for a map which value is a diff*. The key of the map is the qualified name of the...
const var_diff * is_var_diff(const diff *diff)
Test if a diff node is about differences between variables.
void report_name_size_and_alignment_changes(decl_base_sptr first, decl_base_sptr second, diff_context_sptr ctxt, ostream &out, const string &indent)
Report the name, size and alignment changes of a type.
void represent(const diff_context &ctxt, method_decl_sptr mem_fn, ostream &out)
Stream a string representation for a member function.
bool get_member_function_is_dtor(const function_decl &f)
Test whether a member function is a destructor.
Definition: abg-ir.cc:6695
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:5816
shared_ptr< function_decl > function_decl_sptr
Convenience typedef for a shared pointer on a function_decl.
Definition: abg-fwd.h:267
ssize_t get_member_function_vtable_offset(const function_decl &f)
Get the vtable offset of a member function.
Definition: abg-ir.cc:6819
bool is_type(const type_or_decl_base &tod)
Test whether a declaration is a type.
Definition: abg-ir.cc:10665
shared_ptr< elf_symbol > elf_symbol_sptr
A convenience typedef for a shared pointer to elf_symbol.
Definition: abg-ir.h:886
bool is_class_type(const type_or_decl_base &t)
Test whether a type is a class.
Definition: abg-ir.cc:10947
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:9456
shared_ptr< class_decl > class_decl_sptr
Convenience typedef for a shared pointer on a class_decl.
Definition: abg-fwd.h:191
shared_ptr< var_decl > var_decl_sptr
Convenience typedef for a shared pointer on a var_decl.
Definition: abg-fwd.h:254
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:119
bool is_member_function(const function_decl &f)
Test whether a function_decl is a member function.
Definition: abg-ir.cc:6609
bool is_c_language(translation_unit::language l)
Test if a language enumerator designates the C language.
Definition: abg-ir.cc:1729
bool get_member_function_is_virtual(const function_decl &f)
Test if a given member function is virtual.
Definition: abg-ir.cc:6882
bool is_data_member(const var_decl &v)
Test if a var_decl is a data member.
Definition: abg-ir.cc:5854
translation_unit * get_translation_unit(const decl_base &decl)
Return the translation unit a declaration belongs to.
Definition: abg-ir.cc:10381
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:11670
bool get_member_function_is_ctor(const function_decl &f)
Test whether a member function is a constructor.
Definition: abg-ir.cc:6636
Toplevel namespace for libabigail.