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