3 // Copyright (C) 2013-2015 Red Hat, Inc.
5 // This file is part of the GNU Application Binary Interface Generic
6 // Analysis and Instrumentation Library (libabigail). This library is
7 // free software; you can redistribute it and/or modify it under the
8 // terms of the GNU Lesser General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option) any
12 // This library is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Lesser Public License for more details.
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this program; see the file COPYING-LGPLV3. If
19 // not, see <http://www.gnu.org/licenses/>.
21 // Author: Dodji Seketeli
25 /// This contains the implementation of the comparison engine of
32 #include "abg-comparison.h"
33 #include "abg-comp-filter.h"
34 #include "abg-sptr-utils.h"
45 ///@defgroup DiffNode Internal Representation of the comparison engine
48 /// @brief How changes are represented in libabigail's comparison engine.
52 /// The internal representation of the comparison engine is basically
53 /// a graph of @ref instances of @ref diff node. We refer to these
54 /// just as <em>diff nodes</em>. A diff node represents a change
55 /// between two ABI artifacts represented by instances of types of the
56 /// abigail::ir namespace. These two artifacts that are being
57 /// compared are called the <em>subjects of the diff</em>.
59 /// The types of that IR are in the abigail::comparison namespace.
61 ///@par comparing diff nodes
63 /// Comparing two instances of @ref diff nodes amounts to comparing
64 /// the subject of the diff. In other words, two @ref diff nodes are
65 /// equal if and only if their subjects are equal. Thus, two @ref
66 /// diff nodes can have different memory addresses and yet be equal.
68 ///@par diff reporting and context
70 /// A diff node can be serialized to an output stream to express, in
71 /// a human-readable textual form, the different changes that exist
72 /// between its two subjects. This is done by invoking the
73 /// diff::report() method. That reporting is controlled by several
74 /// parameters that are conceptually part of the context of the diff.
75 /// That context is materialized by an instance of the @ref
76 /// diff_context type.
78 /// Please note that the role of the instance(s) of @ref diff_context
79 /// is boreader than just controlling the reporting of @ref diff
80 /// nodes. Basically, a @ref diff node itself is created following
81 /// behaviours that are controlled by a particular instance of
82 /// diff_context. A diff node is created in a particular diff
83 /// context, so to speak.
89 ///@defgroup CanonicalDiff Canonical diff tree nodes
92 /// @brief How equivalent diff nodes are quickly spotted.
94 /// @par Equivalence of diff nodes.
96 /// Each @ref diff node has a property named <em>Canonical Diff
97 /// Node</em>. If \c D is a diff node, the canonical diff node of @c
98 /// D, noted @c C(D) is a particular diff node that is equal to @c D.
99 /// Thus, a fast way to compare two @ref diff node is to perform a
100 /// pointer comparison of their canonical diff nodes.
102 /// A set of equivalent @ref diff nodes is a set of diff nodes that
103 /// all have the same canonical node. All the nodes of that set are
106 /// A canonical node is registereded for a given diff node by invoking
107 /// the method diff_context::initialize_canonical_diff().
109 /// Please note that the diff_context holds all the canonical diffs
110 /// that got registered through it. Thus, the life time of all of
111 /// canonical diff objects is the same as the life time of the @ref
112 /// diff_context they relate to.
117 // Inject types from outside in here.
119 using std::tr1::dynamic_pointer_cast;
120 using std::tr1::static_pointer_cast;
121 using abigail::sptr_utils::noop_deleter;
123 /// Convenience typedef for a pair of decls or types.
124 typedef std::pair<const type_or_decl_base_sptr,
125 const type_or_decl_base_sptr> types_or_decls_type;
127 /// A hashing functor for @ref types_or_decls_type.
128 struct types_or_decls_hash
131 operator()(const types_or_decls_type& d) const
133 size_t h1 = hash_type_or_decl(d.first);
134 size_t h2 = hash_type_or_decl(d.second);
135 return hashing::combine_hashes(h1, h2);
139 /// An equality functor for @ref types_or_decls_type.
140 struct types_or_decls_equal
143 operator()(const types_or_decls_type d1, const types_or_decls_type d2) const
144 {return d1.first == d2.first && d1.second == d2.second;}
147 /// A convenience typedef for a map of @ref types_or_decls_type and
149 typedef unordered_map<types_or_decls_type, diff_sptr,
150 types_or_decls_hash, types_or_decls_equal>
151 types_or_decls_diff_map_type;
153 /// The overloaded or operator for @ref visiting_kind.
155 operator|(visiting_kind l, visiting_kind r)
156 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
157 | static_cast<unsigned>(r));}
159 /// The overloaded and operator for @ref visiting_kind.
161 operator&(visiting_kind l, visiting_kind r)
163 return static_cast<visiting_kind>(static_cast<unsigned>(l)
164 & static_cast<unsigned>(r));
167 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
169 operator~(visiting_kind l)
170 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
172 /// This is a subroutine of a *::report() function.
174 /// If the diff about two subjects S1 and S2 was reported earlier or
175 /// is being reported, emit a diagnostic message about this and return
176 /// from the current diff reporting function.
178 /// @param S1 the first diff subject to take in account.
180 /// @param S2 the second diff subject to take in account.
181 #define RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(S1, S2) \
183 if (diff_sptr _diff_ = context()->get_canonical_diff_for(S1, S2)) \
184 if (_diff_->currently_reporting() || _diff_->reported_once()) \
186 if (_diff_->currently_reporting()) \
187 out << indent << "details are being reported\n"; \
189 out << indent << "details were reported earlier\n"; \
194 /// This is a subroutine of a *::report() function.
196 /// If a given diff was reported earlier or is being reported, emit a
197 /// diagnostic message about this and return from the current diff
198 /// reporting function.
200 /// @param S1 the first diff subject to take in account.
202 /// @param S2 the second diff subject to take in account.
204 /// @param INTRO_TEXT the introductory text that precedes the
206 #define RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(D, INTRO_TEXT) \
208 if (diff_sptr _diff_ = context()->get_canonical_diff_for(D)) \
209 if (_diff_->currently_reporting() || _diff_->reported_once()) \
211 string _name_ = _diff_->first_subject()->get_pretty_representation(); \
212 if (_diff_->currently_reporting()) \
213 out << indent << INTRO_TEXT << " '" << _name_ << "' changed; " \
214 "details are being reported\n"; \
216 out << indent << INTRO_TEXT << " '" << _name_ << "' changed, " \
217 "as reported earlier\n"; \
222 /// This is a subroutine of a *::report() function.
224 /// If the diff about two subjects S1 and S2 was reported earlier or
225 /// is being reported, emit a diagnostic message about this and return
226 /// from the current diff reporting function.
229 /// @param INTRO_TEXT the introductory text that precedes the
231 #define RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(S1, S2, INTRO_TEXT) \
233 if (diff_sptr _diff_ = context()->get_canonical_diff_for(S1, S2)) \
234 if (_diff_->currently_reporting() || _diff_->reported_once()) \
236 string _name_ = _diff_->first_subject()->get_pretty_representation(); \
237 if (_diff_->currently_reporting()) \
238 out << indent << INTRO_TEXT << " '" << _name_ << "' changed; " \
239 "details are being reported\n"; \
241 out << indent << INTRO_TEXT << " '" << _name_ << "' changed, " \
242 "as reported earlier\n"; \
248 sort_string_function_decl_diff_sptr_map
249 (const string_function_decl_diff_sptr_map& map,
250 function_decl_diff_sptrs_type& sorted);
253 sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
254 var_diff_sptrs_type& sorted);
257 sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,
258 var_diff_sptrs_type& sorted);
261 sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map,
262 var_diff_sptrs_type& sorted);
265 sort_string_virtual_member_function_diff_sptr_map
266 (const string_function_decl_diff_sptr_map& map,
267 function_decl_diff_sptrs_type& sorted);
270 sort_string_diff_sptr_map(const string_diff_sptr_map& map,
271 diff_sptrs_type& sorted);
274 sort_string_base_diff_sptr_map(const string_base_diff_sptr_map& map,
275 base_diff_sptrs_type& sorted);
278 sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map,
279 vector<fn_parm_diff_sptr>& sorted);
282 sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map& map,
283 vector<fn_parm_diff_sptr>& sorted);
286 sort_string_parm_map(const string_parm_map& map,
287 vector<function_decl::parameter_sptr>& sorted);
289 static type_base_sptr
290 get_leaf_type(qualified_type_def_sptr t);
292 /// Test if a diff node is about differences between types.
294 /// @param diff the diff node to test.
296 /// @return a pointer to the actual type_diff_base* that @p diff
297 /// extends, iff it is about differences between types.
298 static const type_diff_base*
299 is_type_diff(const diff* diff)
300 {return dynamic_cast<const type_diff_base*>(diff);}
302 /// Test if a diff node is about differences between declarations.
304 /// @param diff the diff node to test.
306 /// @return a pointer to the actual decl_diff_base @p diff extends,
307 /// iff it is about differences between declarations.
308 static const decl_diff_base*
309 is_decl_diff(const diff* diff)
310 {return dynamic_cast<const decl_diff_base*>(diff);}
312 /// Test if a diff node is about differences between variables.
314 /// @param diff the diff node to test.
316 /// @return a pointer to the actual var_diff that @p diff is a type
317 /// of, iff it is about differences between variables.
318 static const var_diff*
319 is_var_diff(const diff* diff)
321 const var_diff* d = dynamic_cast<const var_diff*>(diff);
323 assert(is_decl_diff(diff));
327 /// Test if a diff node is about differences between functions.
329 /// @param diff the diff node to test.
331 /// @return a pointer to the actual var_diff that @p diff is a type
332 /// of, iff it is about differences between variables.
333 static const function_decl_diff*
334 is_function_decl_diff(const diff* diff)
336 const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
338 assert(is_decl_diff(diff));
342 /// Test if a diff node is about differences between two pointers.
344 /// @param diff the diff node to consider.
346 /// @return the @p diff converted into an instance of @ref
347 /// pointer_diff iff @p diff is about differences between two
349 static const pointer_diff*
350 is_pointer_diff(const diff* diff)
351 {return dynamic_cast<const pointer_diff*>(diff);}
353 /// Test if a diff node is about differences between two references.
355 /// @param diff the diff node to consider.
357 /// @return the @p diff converted into an instance of @ref
358 /// reference_diff iff @p diff is about differences between two
360 static const reference_diff*
361 is_reference_diff(const diff* diff)
362 {return dynamic_cast<const reference_diff*>(diff);}
364 /// Test if a diff node is either a reference diff node or a pointer
367 /// @param diff the diff node to test.
369 /// @return true iff @p diff is either reference diff node or a
370 /// pointer diff node.
372 is_reference_or_pointer_diff(const diff* diff)
373 {return is_reference_diff(diff) || is_pointer_diff(diff);}
375 /// Test if a diff node is about differences between two function
378 /// @param diff the diff node to consider.
380 /// @return the @p diff converted into an instance of @ref
381 /// reference_diff iff @p diff is about differences between two
382 /// function parameters.
383 static const fn_parm_diff*
384 is_fn_parm_diff(const diff* diff)
385 {return dynamic_cast<const fn_parm_diff*>(diff);}
387 /// Test if a diff node is about differences between two base class
390 /// @param diff the diff node to consider.
392 /// @return the @p diff converted into an instance of @ref base_diff
393 /// iff @p diff is about differences between two base class
395 static const base_diff*
396 is_base_diff(const diff* diff)
397 {return dynamic_cast<const base_diff*>(diff);}
399 /// Test if a diff node is a child node of a function parameter diff node.
401 /// @param diff the diff node to test.
403 /// @return true iff @p diff is a child node of a function parameter
406 is_child_node_of_function_parm_diff(const diff* diff)
407 {return diff && is_fn_parm_diff(diff->parent_node());}
409 /// Test if a diff node is a child node of a base diff node.
411 /// @param diff the diff node to test.
413 /// @return true iff @p diff is a child node of a base diff node.
415 is_child_node_of_base_diff(const diff* diff)
416 {return diff && is_base_diff(diff->parent_node());}
418 /// Test if the current diff node has an ancestor node that has been
421 /// @param diff the diff node to take into account.
423 /// @return true iff the current diff node has an ancestor node that
424 /// has been filtered out.
426 diff_has_ancestor_filtered_out(const diff* diff)
428 if (!diff || !diff->parent_node())
430 if (diff->parent_node()->is_filtered_out())
432 return diff_has_ancestor_filtered_out(diff->parent_node());
435 /// The default traverse function.
439 diff_traversable_base::traverse(diff_node_visitor&)
442 // <suppression_base stuff>
444 /// The private data of @ref suppression_base.
445 class suppression_base::priv
453 priv(const string& label)
457 friend class suppression_base;
458 }; // end clas suppression_base::priv
460 /// Constructor for @ref suppression_base
462 /// @param a label for the suppression. This represents just a
464 suppression_base::suppression_base(const string& label)
465 : priv_(new priv(label))
468 /// Getter for the label associated to this suppression specification.
470 /// @return the label.
472 suppression_base::get_label() const
473 {return priv_->label_;}
475 /// Setter for the label associated to this suppression specification.
477 /// @param label the new label.
479 suppression_base::set_label(const string& label)
480 {priv_->label_ = label;}
482 suppression_base::~suppression_base()
485 static type_suppression_sptr
486 read_type_suppression(const ini::config::section& section);
488 static function_suppression_sptr
489 read_function_suppression(const ini::config::section& section);
491 static variable_suppression_sptr
492 read_variable_suppression(const ini::config::section& section);
494 /// Read a vector of suppression specifications from the sections of
497 /// Note that this function needs to be updated each time a new kind
498 /// of suppression specification is added.
500 /// @param config the config to read from.
502 /// @param suppressions out parameter. The vector of suppressions to
503 /// append the newly read suppressions to.
505 read_suppressions(const ini::config& config,
506 suppressions_type& suppressions)
509 for (ini::config::sections_type::const_iterator i =
510 config.get_sections().begin();
511 i != config.get_sections().end();
513 if ((s = read_type_suppression(**i))
514 || (s = read_function_suppression(**i))
515 || (s = read_variable_suppression(**i)))
516 suppressions.push_back(s);
520 /// Read suppressions specifications from an input stream.
522 /// @param input the input stream to read from.
524 /// @param suppressions the vector of suppressions to append the newly
525 /// read suppressions to.
527 read_suppressions(std::istream& input,
528 suppressions_type& suppressions)
530 if (ini::config_sptr config = ini::read_config(input))
531 read_suppressions(*config, suppressions);
534 /// Read suppressions specifications from an input file on disk.
536 /// @param input the path to the input file to read from.
538 /// @param suppressions the vector of suppressions to append the newly
539 /// read suppressions to.
541 read_suppressions(const string& file_path,
542 suppressions_type& suppressions)
544 if (ini::config_sptr config = ini::read_config(file_path))
545 read_suppressions(*config, suppressions);
547 // </suppression_base stuff>
549 // <type_suppression stuff>
551 /// The private data for @ref type_suppression.
552 class type_suppression::priv
554 string type_name_regex_str_;
555 mutable sptr_utils::regex_t_sptr type_name_regex_;
557 bool consider_type_kind_;
558 type_suppression::type_kind type_kind_;
559 bool consider_reach_kind_;
560 type_suppression::reach_kind reach_kind_;
561 type_suppression::insertion_ranges insertion_ranges_;
566 priv(const string& type_name_regexp,
567 const string& type_name,
568 bool consider_type_kind,
569 type_suppression::type_kind type_kind,
570 bool consider_reach_kind,
571 type_suppression::reach_kind reach_kind)
572 : type_name_regex_str_(type_name_regexp),
573 type_name_(type_name),
574 consider_type_kind_(consider_type_kind),
575 type_kind_(type_kind),
576 consider_reach_kind_(consider_reach_kind),
577 reach_kind_(reach_kind)
580 /// Get the regular expression object associated to the 'type_name_regex'
581 /// property of @ref type_suppression.
583 /// If the regular expression object is not created, this method
584 /// creates it and returns it.
586 /// If the 'type_name_regex' property of @ref type_suppression is
587 /// empty then this method returns nil.
588 const sptr_utils::regex_t_sptr
589 get_type_name_regex() const
591 if (!type_name_regex_)
593 if (!type_name_regex_str_.empty())
595 sptr_utils::regex_t_sptr r(new regex_t);
597 type_name_regex_str_.c_str(),
599 type_name_regex_ = r;
602 return type_name_regex_;
605 /// Setter for the type_name_regex object.
607 /// @param r the new type_name_regex object.
609 set_type_name_regex(sptr_utils::regex_t_sptr r)
610 {type_name_regex_ = r;}
612 friend class type_suppression;
613 }; // class type_suppression::priv
615 /// Constructor for @ref type_suppression.
617 /// @param label the label of the suppression. This is just a free
618 /// form comment explaining what the suppression is about.
620 /// @param type_name_regexp the regular expression describing the
621 /// types about which diff reports should be suppressed. If it's an
622 /// empty string, the parameter is ignored.
624 /// @param type_name the name of the type about which diff reports
625 /// should be suppressed. If it's an empty string, the parameter is
628 /// Note that parameter @p type_name_regexp and @p type_name_regexp
629 /// should not necessarily be populated. It usually is either one or
630 /// the other that the user wants.
631 type_suppression::type_suppression(const string& label,
632 const string& type_name_regexp,
633 const string& type_name)
634 : suppression_base(label),
635 priv_(new priv(type_name_regexp,
637 /*consider_type_kind=*/false,
638 /*type_kind=*/CLASS_TYPE_KIND,
639 /*consider_reach_kind=*/false,
640 /*reach_kind=*/DIRECT_REACH_KIND))
643 type_suppression::~type_suppression()
646 /// Setter for the "type_name_regex" property of the type suppression
649 /// This sets a regular expression that specifies the family of types
650 /// about which diff reports should be suppressed.
652 /// @param name_regex_str the new regular expression to set.
654 type_suppression::set_type_name_regex_str(const string& name_regex_str)
655 {priv_->type_name_regex_str_ = name_regex_str;}
657 /// Getter for the "type_name_regex" property of the type suppression
660 /// This returns a regular expression that specifies the family of
661 /// types about which diff reports should be suppressed.
663 /// @return the regular expression.
665 type_suppression::get_type_name_regex_str() const
666 {return priv_->type_name_regex_str_;}
668 /// Setter for the name of the type about which diff reports should be
671 /// @param name the new type name.
673 type_suppression::set_type_name(const string& name)
674 {priv_->type_name_ = name;}
676 /// Getter for the name of the type about which diff reports should be
679 /// @param return the type name.
681 type_suppression::get_type_name() const
682 {return priv_->type_name_;}
684 /// Getter of the property that says whether to consider the kind of
685 /// type this suppression is about.
687 /// @return the boolean value of the property.
689 type_suppression::get_consider_type_kind() const
690 {return priv_->consider_type_kind_;}
692 /// Setter of the property that says whether to consider the kind of
693 /// type this suppression is about.
695 /// @param f the new boolean value of the property.
697 type_suppression::set_consider_type_kind(bool f)
698 {priv_->consider_type_kind_ = f;}
701 /// Setter of the kind of type this suppression is about.
703 /// Note that this will be considered during evaluation of the
704 /// suppression only if type_suppression::get_consider_type_kind()
707 /// @param k the new kind of type this suppression is about.
709 type_suppression::set_type_kind(type_kind k)
710 {priv_->type_kind_ = k;}
712 /// Getter of the kind of type this suppression is about.
714 /// Note that this will be considered during evaluation of the
715 /// suppression only if type_suppression::get_consider_type_kind()
718 /// @return the kind of type this suppression is about.
719 type_suppression::type_kind
720 type_suppression::get_type_kind() const
721 {return priv_->type_kind_;}
723 /// Test if the current type suppression specification
724 /// suggests to consider how the matching diff node is reached.
726 /// @return true if the current type suppression specification
727 /// suggests to consider how the matching diff node is reached.
729 type_suppression::get_consider_reach_kind() const
730 {return priv_->consider_reach_kind_;}
732 /// Set a flag saying if the current type suppression specification
733 /// suggests to consider how the matching diff node is reached.
735 /// @param f the new value of the flag. It's true iff the current
736 /// type suppression specification suggests to consider how the
737 /// matching diff node is reached.
739 type_suppression::set_consider_reach_kind(bool f)
740 {priv_->consider_reach_kind_ = f;}
742 /// Getter of the way the diff node matching the current suppression
743 /// specification is to be reached.
745 /// @return the way the diff node matching the current suppression
746 /// specification is to be reached.
747 type_suppression::reach_kind
748 type_suppression::get_reach_kind() const
749 {return priv_->reach_kind_;}
751 /// Setter of the way the diff node matching the current suppression
752 /// specification is to be reached.
754 /// @param p the way the diff node matching the current suppression
755 /// specification is to be reached.
757 type_suppression::set_reach_kind(reach_kind k)
758 {priv_->reach_kind_ = k;}
760 /// Setter for the vector of data member insertion ranges that
761 /// specifies where a data member is inserted as far as this
762 /// suppression specification is concerned.
764 /// @param r the new insertion range vector.
766 type_suppression::set_data_member_insertion_ranges(const insertion_ranges& r)
767 {priv_->insertion_ranges_ = r;}
769 /// Getter for the vector of data member insertion range that
770 /// specifiers where a data member is inserted as far as this
771 /// suppression specification is concerned.
773 /// @return the vector of insertion ranges.
774 const type_suppression::insertion_ranges&
775 type_suppression::get_data_member_insertion_ranges() const
776 {return priv_->insertion_ranges_;}
778 /// Getter for the vector of data member insertion range that
779 /// specifiers where a data member is inserted as far as this
780 /// suppression specification is concerned.
782 /// @return the vector of insertion ranges.
783 type_suppression::insertion_ranges&
784 type_suppression::get_data_member_insertion_ranges()
785 {return priv_->insertion_ranges_;}
787 /// Evaluate this suppression specification on a given diff node and
788 /// say if the diff node should be suppressed or not.
790 /// @param diff the diff node to evaluate this suppression
791 /// specification against.
793 /// @return true if @p diff should be suppressed.
795 type_suppression::suppresses_diff(const diff* diff) const
797 const type_diff_base* d = is_type_diff(diff);
801 // If the suppression should consider the way the diff node has been
802 // reached, then do it now.
803 if (get_consider_reach_kind())
805 if (get_reach_kind() == POINTER_REACH_KIND)
807 if (const pointer_diff* ptr_diff = is_pointer_diff(diff))
809 d = is_type_diff(ptr_diff->underlying_type_diff().get());
815 else if (get_reach_kind() == REFERENCE_REACH_KIND)
817 if (const reference_diff* ref_diff = is_reference_diff(diff))
819 d = is_type_diff(ref_diff->underlying_type_diff().get());
825 else if (get_reach_kind() == REFERENCE_OR_POINTER_REACH_KIND)
827 if (const pointer_diff* ptr_diff = is_pointer_diff(diff))
829 d = is_type_diff(ptr_diff->underlying_type_diff().get());
832 else if (const reference_diff* ref_diff = is_reference_diff(diff))
834 d = is_type_diff(ref_diff->underlying_type_diff().get());
842 type_base_sptr ft, st;
843 ft = is_type(d->first_subject());
844 st = is_type(d->second_subject());
847 // If the suppression should consider type kind, then well, check
849 if (get_consider_type_kind())
851 type_kind k = get_type_kind();
854 case type_suppression::UNKNOWN_TYPE_KIND:
855 case type_suppression::CLASS_TYPE_KIND:
856 if (!is_class_type(ft) && !is_class_type(st))
859 case type_suppression::STRUCT_TYPE_KIND:
861 class_decl_sptr fc = is_class_type(ft), sc = is_class_type(st);
863 || (fc && !fc->is_struct() && sc && !sc->is_struct()))
867 case type_suppression::UNION_TYPE_KIND:
868 // We do not support unions yet. When we do, we should
869 // replace the abort here by a "break;" statement.
871 case type_suppression::ENUM_TYPE_KIND:
872 if (!is_enum_type(ft) && !is_enum_type(st))
875 case type_suppression::ARRAY_TYPE_KIND:
876 if (!is_array_type(ft) && !is_array_type(st))
879 case type_suppression::TYPEDEF_TYPE_KIND:
880 if (!is_typedef(ft) && !is_typedef(st))
883 case type_suppression::BUILTIN_TYPE_KIND:
884 if (!is_type_decl(ft) && !is_type_decl(st))
894 // Check if there is an exact type name match.
895 if (!get_type_name().empty())
897 if (get_type_name() != fn && get_type_name() != sn)
902 // So now check if there is a regular expression match.
904 // If none of the qualified name of the types that are being
905 // compared match the regular expression of the of the type name,
906 // then this suppression doesn't apply.
907 const sptr_utils::regex_t_sptr type_name_regex =
908 priv_->get_type_name_regex();
910 && (regexec(type_name_regex.get(), fn.c_str(),
912 && regexec(type_name_regex.get(), sn.c_str(),
917 const class_diff* klass_diff = dynamic_cast<const class_diff*>(diff);
918 if (// We are looking at a class diff ...
920 // ... that has inserted data members ...
921 && !get_data_member_insertion_ranges().empty()
922 // ... that has no deleted data members ...
923 && klass_diff->deleted_data_members().empty()
924 // ... and in which the class size hasn't shrunk (because, e.g,
925 // the base classes have changed).
926 && (klass_diff->first_class_decl()->get_size_in_bits()
927 <= klass_diff->second_class_decl()->get_size_in_bits()))
929 for (string_decl_base_sptr_map::const_iterator m =
930 klass_diff->inserted_data_members().begin();
931 m != klass_diff->inserted_data_members().end();
934 decl_base_sptr member = m->second;
935 size_t dm_offset = get_data_member_offset(member);
936 size_t first_type_size =
937 klass_diff->first_class_decl()->get_size_in_bits();
938 size_t second_type_size =
939 klass_diff->second_class_decl()->get_size_in_bits();
940 bool matched = false;
942 for (insertion_ranges::const_iterator i =
943 get_data_member_insertion_ranges().begin();
944 i != get_data_member_insertion_ranges().end();
947 type_suppression::insertion_range_sptr range = *i;
948 ssize_t range_begin_val = 0,range_end_val = 0;
949 if (!type_suppression::insertion_range::eval_boundary
951 klass_diff->first_class_decl(),
954 if (!type_suppression::insertion_range::eval_boundary
956 klass_diff->first_class_decl(),
961 unsigned range_begin =
962 (range_begin_val < 0) ? first_type_size : range_begin_val;
965 (range_end_val < 0) ? second_type_size : range_end_val;
967 if (range_begin > range_end)
970 if (range_begin_val < 0 || range_end_val < 0)
972 if (dm_offset < range_begin)
976 if (dm_offset < range_begin || dm_offset > range_end)
989 /// The private data of type_suppression::insertion_range
990 struct type_suppression::insertion_range::priv
992 boundary_sptr begin_;
998 priv(boundary_sptr begin, boundary_sptr end)
999 : begin_(begin), end_(end)
1001 }; // end struct type_suppression::insertion_range::priv
1003 /// Default Constructor of @ref type_suppression::insertion_range.
1004 type_suppression::insertion_range::insertion_range()
1008 /// Constructor of @ref type_suppression::insertion_range.
1010 /// @param begin the start of the range. A range boundary that is an
1011 /// instance of @ref interger_boundary with a negative value means the
1012 /// maximum possible value.
1014 /// @param end the end of the range. A range boundary that is an
1015 /// instance of @ref interger_boundary with a negative value means the
1016 /// maximum possible value.
1017 type_suppression::insertion_range::insertion_range(boundary_sptr begin,
1019 : priv_(new priv(begin, end))
1022 /// Getter for the beginning of the range.
1024 /// @return the beginning of the range. A range boundary that is an
1025 /// instance of @ref interger_boundary with a negative value means the
1026 /// maximum possible value.
1027 type_suppression::insertion_range::boundary_sptr
1028 type_suppression::insertion_range::begin() const
1029 {return priv_->begin_;}
1031 /// Getter for the end of the range.
1033 /// @return the end of the range. A range boundary that is an
1034 /// instance of @ref interger_boundary with a negative value means the
1035 /// maximum possible value.
1036 type_suppression::insertion_range::boundary_sptr
1037 type_suppression::insertion_range::end() const
1038 {return priv_->end_;}
1040 /// Create an integer boundary.
1042 /// The return value of this function is to be used as a boundary for
1043 /// an instance of @ref type_suppression::insertion_range. That
1044 /// boundary evaluates to an integer value.
1046 /// @param value the value of the integer boundary.
1048 /// @return the resulting integer boundary.
1049 type_suppression::insertion_range::integer_boundary_sptr
1050 type_suppression::insertion_range::create_integer_boundary(int value)
1051 {return integer_boundary_sptr(new integer_boundary(value));}
1054 /// Create a function call expression boundary.
1056 /// The return value of this function is to be used as a boundary for
1057 /// an instance of @ref type_suppression::insertion_range. The value
1058 /// of that boundary is actually a function call expression that
1059 /// itself evalutates to an integer value, in the context of a @ref
1062 /// @param expr the function call expression to create the boundary from.
1064 /// @return the resulting function call expression boundary.
1065 type_suppression::insertion_range::fn_call_expr_boundary_sptr
1066 type_suppression::insertion_range::create_fn_call_expr_boundary(ini::function_call_expr_sptr expr)
1067 {return fn_call_expr_boundary_sptr(new fn_call_expr_boundary(expr));}
1069 /// Create a function call expression boundary.
1071 /// The return value of this function is to be used as a boundary for
1072 /// an instance of @ref type_suppression::insertion_range. The value
1073 /// of that boundary is actually a function call expression that
1074 /// itself evalutates to an integer value, in the context of a @ref
1077 /// @param s a string representing the expression the function call
1078 /// expression to create the boundary from.
1080 /// @return the resulting function call expression boundary.
1081 type_suppression::insertion_range::fn_call_expr_boundary_sptr
1082 type_suppression::insertion_range::create_fn_call_expr_boundary(const string& s)
1084 fn_call_expr_boundary_sptr result, nil;
1085 ini::function_call_expr_sptr expr;
1086 if (ini::read_function_call_expr(s, expr) && expr)
1087 result.reset(new fn_call_expr_boundary(expr));
1091 /// Evaluate an insertion range boundary to get a resulting integer
1094 /// @param boundary the boundary to evaluate.
1096 /// @param context the context of evualuation. It's a @ref class_decl
1097 /// to take into account during the evaluation, if there is a need for
1100 /// @return true iff the evaluation was successful and @p value
1101 /// contains the resulting value.
1103 type_suppression::insertion_range::eval_boundary(boundary_sptr boundary,
1104 class_decl_sptr context,
1107 if (integer_boundary_sptr b = is_integer_boundary(boundary))
1109 value = b->as_integer();
1112 else if (fn_call_expr_boundary_sptr b = is_fn_call_expr_boundary(boundary))
1114 ini::function_call_expr_sptr fn_call = b->as_function_call_expr();
1115 if ((fn_call->get_name() == "offset_of"
1116 || fn_call->get_name() == "offset_after")
1117 && fn_call->get_arguments().size() == 1)
1119 string member_name = fn_call->get_arguments()[0];
1120 for (class_decl::data_members::const_iterator it =
1121 context->get_data_members().begin();
1122 it != context->get_data_members().end();
1125 if (!get_data_member_is_laid_out(**it))
1127 if ((*it)->get_name() == member_name)
1129 if (fn_call->get_name() == "offset_of")
1130 value = get_data_member_offset(*it);
1131 else if (fn_call->get_name() == "offset_after")
1132 value = get_data_member_offset(*it) +
1133 (*it)->get_type()->get_size_in_bits();
1135 // We should not reach this point.
1145 /// Tests if a given instance of @ref
1146 /// type_suppression::insertion_range::boundary is actually an integer boundary.
1148 /// @param b the boundary to test.
1150 /// @return a pointer to the instance of
1151 /// type_suppression::insertion_range::integer_boundary if @p b is
1152 /// actually an integer boundary. Otherwise, return a null pointer.
1153 type_suppression::insertion_range::integer_boundary_sptr
1154 is_integer_boundary(type_suppression::insertion_range::boundary_sptr b)
1155 {return dynamic_pointer_cast<type_suppression::insertion_range::integer_boundary>(b);}
1157 /// Tests if a given instance of @ref
1158 /// type_suppression::insertion_range::boundary is actually an function call expression boundary.
1160 /// @param b the boundary to test.
1162 /// @return a pointer to the instance of
1163 /// type_suppression::insertion_range::fn_call_expr_boundary if @p b
1164 /// is actually an function call expression boundary. Otherwise,
1165 /// return a null pointer.
1166 type_suppression::insertion_range::fn_call_expr_boundary_sptr
1167 is_fn_call_expr_boundary(type_suppression::insertion_range::boundary_sptr b)
1168 {return dynamic_pointer_cast<type_suppression::insertion_range::fn_call_expr_boundary>(b);}
1170 /// The private data type of @ref
1171 /// type_suppression::insertion_range::boundary.
1172 struct type_suppression::insertion_range::boundary::priv
1176 }; // end struct type_suppression::insertion_range::boundary::priv
1178 /// Default constructor of @ref
1179 /// type_suppression::insertion_range::boundary
1180 type_suppression::insertion_range::boundary::boundary()
1184 /// Destructor of @ref type_suppression::insertion_range::boundary.
1185 type_suppression::insertion_range::boundary::~boundary()
1188 /// Private data type for @ref
1189 /// type_suppression::insertion_range::integer_boundary.
1190 struct type_suppression::insertion_range::integer_boundary::priv
1201 }; // end type_suppression::insertion_range::integer_boundary::priv
1203 /// Converting constructor of
1204 /// type_suppression::insertion_range::integer_boundary.
1206 /// @param value the integer value of the newly created integer boundary.
1207 type_suppression::insertion_range::integer_boundary::integer_boundary(int value)
1208 : priv_(new priv(value))
1211 /// Return the integer value of the current inace of @ref
1212 /// type_suppression::insertion_range::integer_boundary.
1214 /// @return the integer value of the current boundary.
1216 type_suppression::insertion_range::integer_boundary::as_integer() const
1217 {return priv_->value_;}
1219 /// Converts the current boundary into an integer value.
1221 /// @return the integer value of the current boundary.
1222 type_suppression::insertion_range::integer_boundary::operator int() const
1223 {return as_integer();}
1225 /// Destructor of @ref type_suppression::insertion_range::integer_boundary.
1226 type_suppression::insertion_range::integer_boundary::~integer_boundary()
1229 /// Private data type of type @ref
1230 /// type_suppression::insertion_range::fn_call_expr_boundary.
1231 struct type_suppression::insertion_range::fn_call_expr_boundary::priv
1233 ini::function_call_expr_sptr expr_;
1238 priv(ini::function_call_expr_sptr expr)
1241 }; // end struct type_suppression::insertion_range::fn_call_expr_boundary::priv
1243 /// Converting constructor for @ref
1244 /// type_suppression::insertion_range::fn_call_expr_boundary.
1246 /// @param expr the function call expression to build this boundary
1248 type_suppression::insertion_range::fn_call_expr_boundary::
1249 fn_call_expr_boundary(ini::function_call_expr_sptr expr)
1250 : priv_(new priv(expr))
1253 /// Returns the function call expression value of the current boundary.
1255 /// @return the function call expression value of the current boundary;
1256 ini::function_call_expr_sptr
1257 type_suppression::insertion_range::fn_call_expr_boundary::as_function_call_expr() const
1258 {return priv_->expr_;}
1260 /// Converts the current boundary to its function call expression value.
1262 /// @return the function call expression value of the current boundary.
1263 type_suppression::insertion_range::fn_call_expr_boundary::operator ini::function_call_expr_sptr () const
1264 {return as_function_call_expr();}
1266 /// Destructor of @ref
1267 /// type_suppression::insertion_range::fn_call_expr_boundary.
1268 type_suppression::insertion_range::fn_call_expr_boundary::~fn_call_expr_boundary()
1271 // </type_suppression stuff>
1273 /// Parse the value of the "type_kind" property in the "suppress_type"
1276 /// @param input the input string representing the value of the
1277 /// "type_kind" property.
1279 /// @return the @ref type_kind enumerator parsed.
1280 static type_suppression::type_kind
1281 read_type_kind_string(const string& input)
1283 if (input == "class")
1284 return type_suppression::CLASS_TYPE_KIND;
1285 else if (input == "struct")
1286 return type_suppression::STRUCT_TYPE_KIND;
1287 else if (input == "union")
1288 return type_suppression::UNION_TYPE_KIND;
1289 else if (input == "enum")
1290 return type_suppression::ENUM_TYPE_KIND;
1291 else if (input == "array")
1292 return type_suppression::ARRAY_TYPE_KIND;
1293 else if (input == "typedef")
1294 return type_suppression::TYPEDEF_TYPE_KIND;
1295 else if (input == "builtin")
1296 return type_suppression::BUILTIN_TYPE_KIND;
1298 return type_suppression::UNKNOWN_TYPE_KIND;
1301 /// Parse the value of the "accessed_through" property in the
1302 /// "suppress_type" section.
1304 /// @param input the input string representing the value of the
1305 /// "accessed_through" property.
1307 /// @return the @ref type_suppression::reach_kind enumerator parsed.
1308 static type_suppression::reach_kind
1309 read_suppression_reach_kind(const string& input)
1311 if (input == "direct")
1312 return type_suppression::DIRECT_REACH_KIND;
1313 else if (input == "pointer")
1314 return type_suppression::POINTER_REACH_KIND;
1315 else if (input == "reference")
1316 return type_suppression::REFERENCE_REACH_KIND;
1317 else if (input == "reference-or-pointer")
1318 return type_suppression::REFERENCE_OR_POINTER_REACH_KIND;
1320 return type_suppression::DIRECT_REACH_KIND;
1323 /// Read a type suppression from an instance of ini::config::section
1324 /// and build a @ref type_suppression as a result.
1326 /// @param section the section of the ini config to read.
1328 /// @return the resulting @ref type_suppression upon successful
1329 /// parsing, or nil.
1330 static type_suppression_sptr
1331 read_type_suppression(const ini::config::section& section)
1333 type_suppression_sptr nil;
1335 if (section.get_name() != "suppress_type")
1338 ini::simple_property_sptr label =
1339 is_simple_property(section.find_property("label"));
1340 string label_str = label ? label->get_value()->as_string() : ":";
1342 ini::simple_property_sptr name_regex_prop =
1343 is_simple_property(section.find_property("name_regexp"));
1344 string name_regex_str = name_regex_prop
1345 ? name_regex_prop->get_value()->as_string()
1348 ini::simple_property_sptr name_prop =
1349 is_simple_property(section.find_property("name"));
1350 string name_str = name_prop
1351 ? name_prop->get_value()->as_string()
1354 bool consider_type_kind = false;
1355 type_suppression::type_kind type_kind = type_suppression::UNKNOWN_TYPE_KIND;
1356 if (ini::simple_property_sptr type_kind_prop =
1357 is_simple_property(section.find_property("type_kind")))
1359 consider_type_kind = true;
1361 read_type_kind_string(type_kind_prop->get_value()->as_string());
1364 bool consider_reach_kind = false;
1365 type_suppression::reach_kind reach_kind = type_suppression::DIRECT_REACH_KIND;
1366 if (ini::simple_property_sptr reach_kind_prop =
1367 is_simple_property(section.find_property("accessed_through")))
1369 consider_reach_kind = true;
1371 read_suppression_reach_kind(reach_kind_prop->get_value()->as_string());
1374 // Support has_data_member_inserted_at
1375 vector<type_suppression::insertion_range_sptr> insert_ranges;
1376 bool consider_data_member_insertion = false;
1377 if (ini::simple_property_sptr prop =
1378 is_simple_property(section.find_property("has_data_member_inserted_at")))
1380 // So this property has the form:
1381 // has_data_member_inserted_at = <one-string-property-value>
1382 string ins_point = prop->get_value()->as_string();
1383 type_suppression::insertion_range::boundary_sptr begin, end;
1384 if (ins_point == "end")
1385 begin = type_suppression::insertion_range::create_integer_boundary(-1);
1386 else if (isdigit(ins_point[0]))
1387 begin = type_suppression::insertion_range::create_integer_boundary
1388 (atoi(ins_point.c_str()));
1389 else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1390 type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(ins_point)))
1395 end = type_suppression::insertion_range::create_integer_boundary(-1);
1396 type_suppression::insertion_range_sptr insert_range
1397 (new type_suppression::insertion_range(begin, end));
1398 insert_ranges.push_back(insert_range);
1399 consider_data_member_insertion = true;
1402 // Support has_data_member_inserted_between
1403 if (ini::tuple_property_sptr prop =
1404 is_tuple_property(section.find_property
1405 ("has_data_member_inserted_between")))
1407 // ensures that this has the form:
1408 // has_data_member_inserted_between = {0 , end};
1409 // and not (for instance):
1410 // has_data_member_inserted_between = {{0 , end}, {1, foo}}
1411 type_suppression::insertion_range::boundary_sptr begin, end;
1412 if (prop->get_value()->get_value_items().size() == 2
1413 && is_string_property_value(prop->get_value()->get_value_items()[0])
1414 && is_string_property_value(prop->get_value()->get_value_items()[1]))
1416 string str = prop->get_value()->get_value_items()[0]->as_string();
1419 type_suppression::insertion_range::create_integer_boundary(-1);
1420 else if (isdigit(str[0]))
1421 begin = type_suppression::insertion_range::create_integer_boundary
1422 (atoi(str.c_str()));
1423 else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1424 type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1429 str = prop->get_value()->get_value_items()[1]->as_string();
1432 type_suppression::insertion_range::create_integer_boundary(-1);
1433 else if (isdigit(str[0]))
1434 end = type_suppression::insertion_range::create_integer_boundary
1435 (atoi(str.c_str()));
1436 else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1437 type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1442 type_suppression::insertion_range_sptr insert_range
1443 (new type_suppression::insertion_range(begin, end));
1444 insert_ranges.push_back(insert_range);
1445 consider_data_member_insertion = true;
1448 // the 'has_data_member_inserted_between' property has a wrong
1449 // value type, so let's discard the endire [suppress_type]
1454 // Support has_data_members_inserted_between
1455 if (ini::tuple_property_sptr prop =
1456 is_tuple_property(section.find_property
1457 ("has_data_members_inserted_between")))
1459 bool is_well_formed = true;
1460 for (vector<ini::property_value_sptr>::const_iterator i =
1461 prop->get_value()->get_value_items().begin();
1462 is_well_formed && i != prop->get_value()->get_value_items().end();
1465 ini::tuple_property_value_sptr tuple_value =
1466 is_tuple_property_value(*i);
1468 || tuple_value->get_value_items().size() != 2
1469 || !is_string_property_value(tuple_value->get_value_items()[0])
1470 || !is_string_property_value(tuple_value->get_value_items()[1]))
1471 is_well_formed = false;
1473 type_suppression::insertion_range::boundary_sptr begin, end;
1474 string str = tuple_value->get_value_items()[0]->as_string();
1477 type_suppression::insertion_range::create_integer_boundary(-1);
1478 else if (isdigit(str[0]))
1480 type_suppression::insertion_range::create_integer_boundary
1481 (atoi(str.c_str()));
1482 else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1483 type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1488 str = tuple_value->get_value_items()[1]->as_string();
1491 type_suppression::insertion_range::create_integer_boundary(-1);
1492 else if (isdigit(str[0]))
1493 end = type_suppression::insertion_range::create_integer_boundary
1494 (atoi(str.c_str()));
1495 else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1496 type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1501 type_suppression::insertion_range_sptr insert_range
1502 (new type_suppression::insertion_range(begin, end));
1503 insert_ranges.push_back(insert_range);
1504 consider_data_member_insertion = true;
1506 if (!is_well_formed)
1510 if ((!name_regex_prop || name_regex_prop->get_value()->as_string().empty())
1511 && (!name_prop || name_prop->get_value()->as_string().empty())
1512 && !consider_type_kind)
1515 type_suppression_sptr suppr(new type_suppression(label_str,
1518 if (consider_type_kind)
1520 suppr->set_consider_type_kind(true);
1521 suppr->set_type_kind(type_kind);
1524 if (consider_reach_kind)
1526 suppr->set_consider_reach_kind(true);
1527 suppr->set_reach_kind(reach_kind);
1530 if (consider_data_member_insertion)
1531 suppr->set_data_member_insertion_ranges(insert_ranges);
1536 // <function_suppression stuff>
1537 class function_suppression::parameter_spec::priv
1539 friend class function_suppression::parameter_spec;
1540 friend class function_suppression;
1544 string type_name_regex_str_;
1545 mutable sptr_utils::regex_t_sptr type_name_regex_;
1551 priv(size_t i, const string& tn)
1552 : index_(i), type_name_(tn)
1555 priv(size_t i, const string& tn, const string& tn_regex)
1556 : index_(i), type_name_(tn), type_name_regex_str_(tn_regex)
1559 const sptr_utils::regex_t_sptr
1560 get_type_name_regex() const
1562 if (!type_name_regex_ && !type_name_regex_str_.empty())
1564 sptr_utils::regex_t_sptr r(new regex_t);
1565 if (regcomp(r.get(),
1566 type_name_regex_str_.c_str(),
1568 type_name_regex_ = r;
1570 return type_name_regex_;
1572 }; // end class function_suppression::parameter_spec::priv
1574 /// Constructor for the @ref the function_suppression::parameter_spec
1577 /// @param i the index of the parameter designated by this specification.
1579 /// @param tn the type name of the parameter designated by this specification.
1581 /// @param tn_regex a regular expression that defines a set of type
1582 /// names for the parameter designated by this specification. Note
1583 /// that at evaluation time, this regular expression is taken in
1584 /// account only if the parameter @p tn is empty.
1585 function_suppression::parameter_spec::parameter_spec(size_t i,
1587 const string& tn_regex)
1588 : priv_(new priv(i, tn, tn_regex))
1591 /// Getter for the index of the parameter designated by this
1594 /// @return the index of the parameter designated by this
1597 function_suppression::parameter_spec::get_index() const
1598 {return priv_->index_;}
1600 /// Setter for the index of the parameter designated by this
1603 /// @param i the new index to set.
1605 function_suppression::parameter_spec::set_index(size_t i)
1606 {priv_->index_ = i;}
1608 /// Getter for the type name of the parameter designated by this specification.
1610 /// @return the type name of the parameter.
1612 function_suppression::parameter_spec::get_parameter_type_name() const
1613 {return priv_->type_name_;}
1615 /// Setter for the type name of the parameter designated by this
1618 /// @param tn new parameter type name to set.
1620 function_suppression::parameter_spec::set_parameter_type_name(const string& tn)
1621 {priv_->type_name_ = tn;}
1623 /// Getter for the regular expression that defines a set of type names
1624 /// for the parameter designated by this specification.
1626 /// Note that at evaluation time, this regular expression is taken in
1627 /// account only if the name of the parameter as returned by
1628 /// function_suppression::parameter_spec::get_parameter_type_name() is
1631 /// @return the regular expression or the parameter type name.
1633 function_suppression::parameter_spec::get_parameter_type_name_regex_str() const
1634 {return priv_->type_name_regex_str_;}
1636 /// Setter for the regular expression that defines a set of type names
1637 /// for the parameter designated by this specification.
1639 /// Note that at evaluation time, this regular expression is taken in
1640 /// account only if the name of the parameter as returned by
1641 /// function_suppression::parameter_spec::get_parameter_type_name() is
1644 /// @param type_name_regex_str the new type name regular expression to
1647 function_suppression::parameter_spec::set_parameter_type_name_regex_str
1648 (const string& type_name_regex_str)
1649 {priv_->type_name_regex_str_ = type_name_regex_str;}
1651 /// The type of the private data of the @ref function_suppression
1653 class function_suppression::priv
1655 friend class function_suppression;
1658 string name_regex_str_;
1659 mutable sptr_utils::regex_t_sptr name_regex_;
1660 string return_type_name_;
1661 string return_type_regex_str_;
1662 mutable sptr_utils::regex_t_sptr return_type_regex_;
1663 parameter_specs_type parm_specs_;
1664 string symbol_name_;
1665 string symbol_name_regex_str_;
1666 mutable sptr_utils::regex_t_sptr symbol_name_regex_;
1667 string symbol_version_;
1668 string symbol_version_regex_str_;
1669 mutable sptr_utils::regex_t_sptr symbol_version_regex_;
1671 priv(const string& name,
1672 const string& name_regex_str,
1673 const string& return_type_name,
1674 const string& return_type_regex_str,
1675 const parameter_specs_type& parm_specs,
1676 const string& symbol_name,
1677 const string& symbol_name_regex_str,
1678 const string& symbol_version,
1679 const string& symbol_version_regex_str)
1681 name_regex_str_(name_regex_str),
1682 return_type_name_(return_type_name),
1683 return_type_regex_str_(return_type_regex_str),
1684 parm_specs_(parm_specs),
1685 symbol_name_(symbol_name),
1686 symbol_name_regex_str_(symbol_name_regex_str),
1687 symbol_version_(symbol_version),
1688 symbol_version_regex_str_(symbol_version_regex_str)
1692 /// Getter for a pointer to a regular expression object built from
1693 /// the regular expression string
1694 /// function_suppression::priv::name_regex_str_.
1696 /// If that string is empty, then an empty regular expression object
1697 /// pointer is returned.
1699 /// @return a pointer to the regular expression object of
1700 /// function_suppression::priv::name_regex_str_..
1701 const sptr_utils::regex_t_sptr
1702 get_name_regex() const
1704 if (!name_regex_ && !name_regex_str_.empty())
1706 sptr_utils::regex_t_sptr r(new regex_t);
1707 if (regcomp(r.get(),
1708 name_regex_str_.c_str(),
1715 /// Getter for a pointer to a regular expression object built from
1716 /// the regular expression string
1717 /// function_suppression::priv::return_type_regex_str_.
1719 /// If that string is empty, then an empty regular expression object
1720 /// pointer is returned.
1722 /// @return a pointer to the regular expression object of
1723 /// function_suppression::priv::return_type_regex_str_.
1724 const sptr_utils::regex_t_sptr
1725 get_return_type_regex() const
1727 if (!return_type_regex_ && !return_type_regex_str_.empty())
1729 sptr_utils::regex_t_sptr r(new regex_t);
1730 if (regcomp(r.get(),
1731 return_type_regex_str_.c_str(),
1733 return_type_regex_ = r;
1735 return return_type_regex_;
1738 /// Getter for a pointer to a regular expression object built from
1739 /// the regular expression string
1740 /// function_suppression::priv::symbol_name_regex_str_.
1742 /// If that string is empty, then an empty regular expression object
1743 /// pointer is returned.
1745 /// @return a pointer to the regular expression object of
1746 /// function_suppression::priv::symbol_name_regex_str_.
1747 const sptr_utils::regex_t_sptr
1748 get_symbol_name_regex() const
1750 if (!symbol_name_regex_ && !symbol_name_regex_str_.empty())
1752 sptr_utils::regex_t_sptr r(new regex_t);
1753 if (regcomp(r.get(),
1754 symbol_name_regex_str_.c_str(),
1756 symbol_name_regex_ = r;
1758 return symbol_name_regex_;
1761 /// Getter for a pointer to a regular expression object built from
1762 /// the regular expression string
1763 /// function_suppression::priv::symbol_version_regex_str_.
1765 /// If that string is empty, then an empty regular expression object
1766 /// pointer is returned.
1768 /// @return a pointer to the regular expression object of
1769 /// function_suppression::priv::symbol_version_regex_str_.
1770 const sptr_utils::regex_t_sptr
1771 get_symbol_version_regex() const
1773 if (!symbol_version_regex_ && ! symbol_version_regex_str_.empty())
1775 sptr_utils::regex_t_sptr r(new regex_t);
1776 if (regcomp(r.get(),
1777 symbol_version_regex_str_.c_str(),
1779 symbol_version_regex_ = r;
1781 return symbol_version_regex_;
1783 }; // end class function_suppression::priv
1785 /// Constructor for the @ref function_suppression type.
1787 /// @param label an informative text string that the evalution code
1788 /// might use to designate this function suppression specification in
1789 /// error messages. This parameter might be empty, in which case it's
1790 /// ignored at evaluation time.
1792 /// @param the name of the function the user wants the current
1793 /// specification to designate. This parameter might be empty, in
1794 /// which case it's ignored at evaluation time.
1796 /// @param nr if @p name is empty this parameter is a regular
1797 /// expression for a family of names of functions the user wants the
1798 /// current specification to designate. If @p name is not empty, this
1799 /// parameter is ignored at specification evaluation time. This
1800 /// parameter might be empty, in which case it's ignored at evaluation
1803 /// @param ret_tn the name of the return type of the function the user
1804 /// wants this specification to designate. This parameter might be
1805 /// empty, in which case it's ignored at evaluation time.
1807 /// @param ret_tr if @p ret_tn is empty, then this is a regular
1808 /// expression for a family of return type names for functions the
1809 /// user wants the current specification to designate. If @p ret_tn
1810 /// is not empty, then this parameter is ignored at specification
1811 /// evaluation time. This parameter might be empty, in which case
1812 /// it's ignored at evaluation time.
1814 /// @param ps a vector of parameter specifications to specify
1815 /// properties of the parameters of the functions the user wants this
1816 /// specification to designate. This parameter might be empty, in
1817 /// which case it's ignored at evaluation time.
1819 /// @param sym_n the name of symbol of the function the user wants
1820 /// this specification to designate. This parameter might be empty,
1821 /// in which case it's ignored at evaluation time.
1823 /// @param sym_nr if the parameter @p sym_n is empty, then this
1824 /// parameter is a regular expression for a family of names of symbols
1825 /// of functions the user wants this specification to designate. If
1826 /// the parameter @p sym_n is not empty, then this parameter is
1827 /// ignored at specification evaluation time. This parameter might be
1828 /// empty, in which case it's ignored at evaluation time.
1830 /// @param sym_v the name of the version of the symbol of the function
1831 /// the user wants this specification to designate. This parameter
1832 /// might be empty, in which case it's ignored at evaluation time.
1834 /// @param sym_vr if the parameter @p sym_v is empty, then this
1835 /// parameter is a regular expression for a family of versions of
1836 /// symbols of functions the user wants the current specification to
1837 /// designate. If the parameter @p sym_v is non empty, then this
1838 /// parameter is ignored. This parameter might be empty, in which
1839 /// case it's ignored at evaluation time.
1840 function_suppression::function_suppression(const string& label,
1843 const string& ret_tn,
1844 const string& ret_tr,
1845 parameter_specs_type& ps,
1846 const string& sym_n,
1847 const string& sym_nr,
1848 const string& sym_v,
1849 const string& sym_vr)
1850 : suppression_base(label),
1851 priv_(new priv(name, nr, ret_tn, ret_tr, ps,
1852 sym_n, sym_nr, sym_v, sym_vr))
1855 function_suppression::~function_suppression()
1858 /// Getter for the name of the function the user wants the current
1859 /// specification to designate. This might be empty, in which case
1860 /// it's ignored at evaluation time.
1862 /// @return the name of the function.
1864 function_suppression::get_function_name() const
1865 {return priv_->name_;}
1867 /// Setter for the name of the function the user wants the current
1868 /// specification to designate. This might be empty, in which case
1869 /// it's ignored at evaluation time.
1871 /// @param n the new function name to set.
1873 function_suppression::set_function_name(const string& n)
1876 /// Getter for a regular expression for a family of names of functions
1877 /// the user wants the current specification to designate.
1879 /// If the function name as returned by
1880 /// function_suppression::get_function_name() is not empty, this
1881 /// property is ignored at specification evaluation time. This
1882 /// property might be empty, in which case it's ignored at evaluation
1885 /// @return the regular expression for the possible names of the
1888 function_suppression::get_function_name_regex_str() const
1889 {return priv_->name_regex_str_;}
1891 /// Setter for a regular expression for a family of names of functions
1892 /// the user wants the current specification to designate.
1894 /// If the function name as returned by
1895 /// function_suppression::get_function_name() is not empty, this
1896 /// property is ignored at specification evaluation time. This
1897 /// property might be empty, in which case it's ignored at evaluation
1900 /// @param r the new the regular expression for the possible names of
1901 /// the function(s).
1903 function_suppression::set_function_name_regex_str(const string& r)
1904 {priv_->name_regex_str_ = r;}
1906 /// Getter for the name of the return type of the function the user
1907 /// wants this specification to designate. This property might be
1908 /// empty, in which case it's ignored at evaluation time.
1910 /// @return the name of the return type of the function.
1912 function_suppression::get_return_type_name() const
1913 {return priv_->return_type_name_;}
1915 /// Setter for the name of the return type of the function the user
1916 /// wants this specification to designate. This property might be
1917 /// empty, in which case it's ignored at evaluation time.
1919 /// @param tr the new name of the return type of the function to set.
1921 function_suppression::set_return_type_name(const string& tr)
1922 {priv_->return_type_name_ = tr;}
1924 /// Getter for a regular expression for a family of return type names
1925 /// for functions the user wants the current specification to
1928 /// If the name of the return type of the function as returned by
1929 /// function_suppression::get_return_type_name() is not empty, then
1930 /// this property is ignored at specification evaluation time. This
1931 /// property might be empty, in which case it's ignored at evaluation
1934 /// @return the regular expression for the possible names of the
1935 /// return types of the function(s).
1937 function_suppression::get_return_type_regex_str() const
1938 {return priv_->return_type_regex_str_;}
1940 /// Setter for a regular expression for a family of return type names
1941 /// for functions the user wants the current specification to
1944 /// If the name of the return type of the function as returned by
1945 /// function_suppression::get_return_type_name() is not empty, then
1946 /// this property is ignored at specification evaluation time. This
1947 /// property might be empty, in which case it's ignored at evaluation
1950 /// @param r the new regular expression for the possible names of the
1951 /// return types of the function(s) to set.
1953 function_suppression::set_return_type_regex_str(const string& r)
1954 {priv_->return_type_regex_str_ = r;}
1956 /// Getter for a vector of parameter specifications to specify
1957 /// properties of the parameters of the functions the user wants this
1958 /// specification to designate.
1960 /// This property might be empty, in which case it's ignored at
1961 /// evaluation time.
1963 /// @return the specifications of the parameters of the function(s).
1964 const function_suppression::parameter_specs_type&
1965 function_suppression::get_parameter_specs() const
1966 {return priv_->parm_specs_;}
1968 /// Setter for a vector of parameter specifications to specify
1969 /// properties of the parameters of the functions the user wants this
1970 /// specification to designate.
1972 /// This property might be empty, in which case it's ignored at
1973 /// evaluation time.
1975 /// @param p the new specifications of the parameters of the
1976 /// function(s) to set.
1978 function_suppression::set_parameter_specs(parameter_specs_type& p)
1979 {priv_->parm_specs_ = p;}
1981 /// Append a specification of a parameter of the function specification.
1983 /// @param p the parameter specification to add.
1985 function_suppression::append_parameter_specs(const parameter_spec_sptr p)
1986 {priv_->parm_specs_.push_back(p);}
1988 /// Getter for the name of symbol of the function the user wants this
1989 /// specification to designate.
1991 /// This property might be empty, in which case it's ignored at
1992 /// evaluation time.
1994 /// @return name of the symbol of the function.
1996 function_suppression::get_symbol_name() const
1997 {return priv_->symbol_name_;}
1999 /// Setter for the name of symbol of the function the user wants this
2000 /// specification to designate.
2002 /// This property might be empty, in which case it's ignored at
2003 /// evaluation time.
2005 /// @return name of the symbol of the function.
2007 function_suppression::set_symbol_name(const string& n)
2008 {priv_->symbol_name_ = n;}
2010 /// Getter for a regular expression for a family of names of symbols
2011 /// of functions the user wants this specification to designate.
2013 /// If the symbol name as returned by
2014 /// function_suppression::get_symbol_name() is not empty, then this
2015 /// property is ignored at specification evaluation time.
2017 /// This property might be empty, in which case it's ignored at
2018 /// evaluation time.
2020 /// @return the regular expression for a family of names of symbols of
2021 /// functions to designate.
2023 function_suppression::get_symbol_name_regex_str() const
2024 {return priv_->symbol_name_regex_str_;}
2026 /// Setter for a regular expression for a family of names of symbols
2027 /// of functions the user wants this specification to designate.
2029 /// If the symbol name as returned by
2030 /// function_suppression::get_symbol_name() is not empty, then this
2031 /// property is ignored at specification evaluation time.
2033 /// This property might be empty, in which case it's ignored at
2034 /// evaluation time.
2036 /// @param r the new regular expression for a family of names of
2037 /// symbols of functions to set.
2039 function_suppression::set_symbol_name_regex_str(const string& r)
2040 {priv_->symbol_name_regex_str_ = r;}
2042 /// Getter for the name of the version of the symbol of the function
2043 /// the user wants this specification to designate.
2045 /// This property might be empty, in which case it's ignored at
2046 /// evaluation time.
2048 /// @return the symbol version of the function.
2050 function_suppression::get_symbol_version() const
2051 {return priv_->symbol_version_;}
2053 /// Setter for the name of the version of the symbol of the function
2054 /// the user wants this specification to designate.
2056 /// This property might be empty, in which case it's ignored at
2057 /// evaluation time.
2059 /// @param v the new symbol version of the function.
2061 function_suppression::set_symbol_version(const string& v)
2062 {priv_->symbol_version_ = v;}
2064 /// Getter for a regular expression for a family of versions of
2065 /// symbols of functions the user wants the current specification to
2068 /// If the symbol version as returned by
2069 /// function_suppression::get_symbol_version() is non empty, then this
2070 /// property is ignored. This property might be empty, in which case
2071 /// it's ignored at evaluation time.
2073 /// @return the regular expression for the versions of symbols of
2074 /// functions to designate.
2076 function_suppression::get_symbol_version_regex_str() const
2077 {return priv_->symbol_version_regex_str_;}
2079 /// Setter for a regular expression for a family of versions of
2080 /// symbols of functions the user wants the current specification to
2083 /// If the symbol version as returned by
2084 /// function_suppression::get_symbol_version() is non empty, then this
2085 /// property is ignored. This property might be empty, in which case
2086 /// it's ignored at evaluation time.
2088 /// @param the new regular expression for the versions of symbols of
2089 /// functions to designate.
2091 function_suppression::set_symbol_version_regex_str(const string& r)
2092 {priv_->symbol_version_regex_str_ = r;}
2094 /// Evaluate this suppression specification on a given diff node and
2095 /// say if the diff node should be suppressed or not.
2097 /// @param diff the diff node to evaluate this suppression
2098 /// specification against.
2100 /// @return true if @p diff should be suppressed.
2102 function_suppression::suppresses_diff(const diff* diff) const
2104 const function_decl_diff* d = is_function_decl_diff(diff);
2108 function_decl_sptr ff = is_function_decl(d->first_function_decl()),
2109 sf = is_function_decl(d->second_function_decl());
2112 string ff_name = ff->get_qualified_name(), sf_name = sf->get_qualified_name();
2114 // Check if the "name" property matches.
2115 if (!get_function_name().empty())
2117 string n = get_function_name();
2118 if (n != ff->get_qualified_name()
2119 && n != sf->get_qualified_name())
2123 // Check if the "name_regexp" property matches.
2124 const sptr_utils::regex_t_sptr name_regex = priv_->get_name_regex();
2126 && (regexec(name_regex.get(), ff_name.c_str(), 0, NULL, 0) != 0
2127 && regexec(name_regex.get(), sf_name.c_str(), 0, NULL, 0) != 0))
2130 // Check if the "return_type_name" or "return_type_regexp"
2131 // properties matches.
2133 string ff_return_type_name = ff->get_type()->get_return_type()
2134 ? (get_type_declaration(ff->get_type()->get_return_type())
2135 ->get_qualified_name())
2137 string sf_return_type_name = sf->get_type()->get_return_type()
2138 ? (get_type_declaration(sf->get_type()->get_return_type())
2139 ->get_qualified_name())
2142 if (!get_return_type_name().empty())
2144 if (ff_return_type_name != get_return_type_name()
2145 && sf_return_type_name != get_return_type_name())
2150 const sptr_utils::regex_t_sptr return_type_regex =
2151 priv_->get_return_type_regex();
2152 if (return_type_regex
2153 && (regexec(return_type_regex.get(),
2154 ff_return_type_name.c_str(),
2156 && regexec(return_type_regex.get(),
2157 sf_return_type_name.c_str(),
2162 // Check if the "symbol_name" and "symbol_name_regexp" properties
2165 string ff_sym_name, ff_sym_version, sf_sym_name, sf_sym_version;
2166 if (ff->get_symbol())
2168 ff_sym_name = ff->get_symbol()->get_name();
2169 ff_sym_version = ff->get_symbol()->get_version().str();
2171 if (sf->get_symbol())
2173 sf_sym_name = sf->get_symbol()->get_name();
2174 sf_sym_version = sf->get_symbol()->get_version().str();
2177 if (!get_symbol_name().empty())
2179 if (ff_sym_name != get_symbol_name()
2180 && sf_sym_name != get_symbol_name())
2185 const sptr_utils::regex_t_sptr symbol_name_regex =
2186 priv_->get_symbol_name_regex();
2187 if (symbol_name_regex
2188 && (regexec(symbol_name_regex.get(),
2189 ff_sym_name.c_str(),
2191 && regexec(symbol_name_regex.get(),
2192 sf_sym_name.c_str(),
2197 // Check if the "symbol_version" and "symbol_version_regexp"
2198 // properties match.
2199 if (!get_symbol_version().empty())
2201 if (ff_sym_version != get_symbol_version()
2202 && sf_sym_name != get_symbol_version())
2207 const sptr_utils::regex_t_sptr symbol_version_regex =
2208 priv_->get_symbol_version_regex();
2209 if (symbol_version_regex
2210 && (regexec(symbol_version_regex.get(),
2211 ff_sym_version.c_str(),
2213 && regexec(symbol_version_regex.get(),
2214 sf_sym_version.c_str(),
2219 if (!get_parameter_specs().empty())
2221 function_type_sptr ff_type = ff->get_type();
2222 function_type_sptr sf_type = sf->get_type();
2223 type_base_sptr parm_type;
2225 for (parameter_specs_type::const_iterator p =
2226 get_parameter_specs().begin();
2227 p != get_parameter_specs().end();
2230 size_t index = (*p)->get_index();
2231 function_decl::parameter_sptr ff_parm =
2232 ff_type->get_parm_at_index_from_first_non_implicit_parm(index);
2233 function_decl::parameter_sptr sf_parm =
2234 sf_type->get_parm_at_index_from_first_non_implicit_parm(index);
2235 if (!ff_parm && ! sf_parm)
2238 string ff_parm_type_qualified_name, sf_parm_type_qualified_name;
2241 parm_type = ff_parm->get_type();
2242 ff_parm_type_qualified_name =
2243 get_type_declaration(parm_type)->get_qualified_name();
2248 parm_type = sf_parm->get_type();
2249 sf_parm_type_qualified_name =
2250 get_type_declaration(parm_type)->get_qualified_name();
2253 const string& tn = (*p)->get_parameter_type_name();
2256 if (tn != ff_parm_type_qualified_name
2257 && tn != sf_parm_type_qualified_name)
2262 const sptr_utils::regex_t_sptr parm_type_name_regex =
2263 (*p)->priv_->get_type_name_regex();
2264 if (parm_type_name_regex)
2266 if ((regexec(parm_type_name_regex.get(),
2267 ff_parm_type_qualified_name.c_str(),
2269 && regexec(parm_type_name_regex.get(),
2270 sf_parm_type_qualified_name.c_str(),
2281 /// Parse a string containing a parameter spec, build an instance of
2282 /// function_suppression::parameter_spec from it and return a pointer
2285 /// @return a shared pointer pointer to the newly built instance of
2286 /// function_suppression::parameter_spec. If the parameter
2287 /// specification could not be parsed, return a nil object.
2288 static function_suppression::parameter_spec_sptr
2289 read_parameter_spec_from_string(const string& str)
2291 string::size_type cur = 0;
2292 function_suppression::parameter_spec_sptr result;
2294 // skip leading white spaces.
2295 for (; cur < str.size(); ++cur)
2296 if (!isspace(str[cur]))
2299 // look for the parameter index
2301 if (str[cur] == '\'')
2304 for (; cur < str.size(); ++cur)
2305 if (!isdigit(str[cur]))
2308 index_str += str[cur];
2311 // skip white spaces.
2312 for (; cur < str.size(); ++cur)
2313 if (!isspace(str[cur]))
2316 bool is_regex = false;
2317 if (str[cur] == '/')
2323 // look for the type name (regex)
2325 for (; cur < str.size(); ++cur)
2326 if (!isspace(str[cur]))
2328 if (is_regex && str[cur] == '/')
2330 type_name += str[cur];
2333 if (is_regex && str[cur] == '/')
2336 if (!index_str.empty() || !type_name.empty())
2338 function_suppression::parameter_spec* p;
2340 p = new function_suppression::parameter_spec(atoi(index_str.c_str()),
2343 p = new function_suppression::parameter_spec(atoi(index_str.c_str()),
2351 /// Parse function suppression specification, build a resulting @ref
2352 /// function_suppression type and return a shared pointer to that
2355 /// @return a shared pointer to the newly built @ref
2356 /// function_suppression. If the function suppression specification
2357 /// could not be parsed then a nil shared pointer is returned.
2358 static function_suppression_sptr
2359 read_function_suppression(const ini::config::section& section)
2361 function_suppression_sptr nil;
2363 if (section.get_name() != "suppress_function")
2366 ini::simple_property_sptr label_prop =
2367 is_simple_property(section.find_property("label"));
2368 string label_str = label_prop
2369 ? label_prop->get_value()->as_string()
2372 ini::simple_property_sptr name_prop =
2373 is_simple_property(section.find_property("name"));
2374 string name = name_prop
2375 ? name_prop->get_value()->as_string()
2378 ini::simple_property_sptr name_regex_prop =
2379 is_simple_property(section.find_property("name_regexp"));
2380 string name_regex_str = name_regex_prop
2381 ? name_regex_prop->get_value()->as_string()
2384 ini::simple_property_sptr return_type_name_prop =
2385 is_simple_property(section.find_property("return_type_name"));
2386 string return_type_name = return_type_name_prop
2387 ? return_type_name_prop->get_value()->as_string()
2390 ini::simple_property_sptr return_type_regex_prop =
2391 is_simple_property(section.find_property("return_type_regexp"));
2392 string return_type_regex_str = return_type_regex_prop
2393 ? return_type_regex_prop->get_value()->as_string()
2396 ini::simple_property_sptr sym_name_prop =
2397 is_simple_property(section.find_property("symbol_name"));
2398 string sym_name = sym_name_prop
2399 ? sym_name_prop->get_value()->as_string()
2402 ini::simple_property_sptr sym_name_regex_prop =
2403 is_simple_property(section.find_property("symbol_name_regexp"));
2404 string sym_name_regex_str = sym_name_regex_prop
2405 ? sym_name_regex_prop->get_value()->as_string()
2408 ini::simple_property_sptr sym_ver_prop =
2409 is_simple_property(section.find_property("symbol_version"));
2410 string sym_version = sym_ver_prop
2411 ? sym_ver_prop->get_value()->as_string()
2414 ini::simple_property_sptr sym_ver_regex_prop =
2415 is_simple_property(section.find_property("symbol_version_regexp"));
2416 string sym_ver_regex_str = sym_ver_regex_prop
2417 ? sym_ver_regex_prop->get_value()->as_string()
2420 function_suppression::parameter_spec_sptr parm;
2421 function_suppression::parameter_specs_type parms;
2422 for (ini::config::property_vector::const_iterator p =
2423 section.get_properties().begin();
2424 p != section.get_properties().end();
2426 if ((*p)->get_name() == "parameter")
2428 ini::simple_property_sptr prop = is_simple_property(*p);
2430 if (parm = read_parameter_spec_from_string
2431 (prop->get_value()->as_string()))
2432 parms.push_back(parm);
2435 function_suppression_sptr result;
2436 if (!label_str.empty()
2438 || !name_regex_str.empty()
2439 || !return_type_name.empty()
2440 || !return_type_regex_str.empty()
2441 || !sym_name.empty()
2442 || !sym_name_regex_str.empty()
2443 || !sym_version.empty()
2444 || !sym_ver_regex_str.empty()
2446 result.reset(new function_suppression(label_str, name,
2449 return_type_regex_str,
2454 sym_ver_regex_str));
2459 // </function_suppression stuff>
2461 // <variable_suppression stuff>
2463 /// The type of the private data of the @ref variable_suppression
2465 class variable_suppression::priv
2467 friend class variable_suppression;
2470 string name_regex_str_;
2471 mutable sptr_utils::regex_t_sptr name_regex_;
2472 string symbol_name_;
2473 string symbol_name_regex_str_;
2474 mutable sptr_utils::regex_t_sptr symbol_name_regex_;
2475 string symbol_version_;
2476 string symbol_version_regex_str_;
2477 mutable sptr_utils::regex_t_sptr symbol_version_regex_;
2479 string type_name_regex_str_;
2480 mutable sptr_utils::regex_t_sptr type_name_regex_;
2482 priv(const string& name,
2483 const string& name_regex_str,
2484 const string& symbol_name,
2485 const string& symbol_name_regex_str,
2486 const string& symbol_version,
2487 const string& symbol_version_regex_str,
2488 const string& type_name,
2489 const string& type_name_regex_str)
2491 name_regex_str_(name_regex_str),
2492 symbol_name_(symbol_name),
2493 symbol_name_regex_str_(symbol_name_regex_str),
2494 symbol_version_(symbol_version),
2495 symbol_version_regex_str_(symbol_version_regex_str),
2496 type_name_(type_name),
2497 type_name_regex_str_(type_name_regex_str)
2500 /// Getter for a pointer to a regular expression object built from
2501 /// the regular expression string
2502 /// variable_suppression::priv::name_regex_str_.
2504 /// If that string is empty, then an empty regular expression object
2505 /// pointer is returned.
2507 /// @return a pointer to the regular expression object of
2508 /// variable_suppression::priv::name_regex_str_.
2509 const sptr_utils::regex_t_sptr
2510 get_name_regex() const
2512 if (!name_regex_ && !name_regex_str_.empty())
2514 sptr_utils::regex_t_sptr r(new regex_t);
2515 if (regcomp(r.get(),
2516 name_regex_str_.c_str(),
2523 /// Getter for a pointer to a regular expression object built from
2524 /// the regular expression string
2525 /// variable_suppression::priv::symbol_name_regex_str_.
2527 /// If that string is empty, then an empty regular expression object
2528 /// pointer is returned.
2530 /// @return a pointer to the regular expression object of
2531 /// variable_suppression::priv::symbol_name_regex_str_.
2532 const sptr_utils::regex_t_sptr
2533 get_symbol_name_regex() const
2535 if (!symbol_name_regex_ && !symbol_name_regex_str_.empty())
2537 sptr_utils::regex_t_sptr r(new regex_t);
2538 if (regcomp(r.get(),
2539 symbol_name_regex_str_.c_str(),
2541 symbol_name_regex_ = r;
2543 return symbol_name_regex_;
2546 /// Getter for a pointer to a regular expression object built from
2547 /// the regular expression string
2548 /// variable_suppression::priv::symbol_version_regex_str_.
2550 /// If that string is empty, then an empty regular expression object
2551 /// pointer is returned.
2553 /// @return a pointer to the regular expression object of
2554 /// variable_suppression::priv::symbol_version_regex_str_.
2555 const sptr_utils::regex_t_sptr
2556 get_symbol_version_regex() const
2558 if (!symbol_version_regex_ && !symbol_version_regex_str_.empty())
2560 sptr_utils::regex_t_sptr r(new regex_t);
2561 if (regcomp(r.get(),
2562 symbol_version_regex_str_.c_str(),
2564 symbol_version_regex_ = r;
2566 return symbol_version_regex_;
2569 /// Getter for a pointer to a regular expression object built from
2570 /// the regular expression string
2571 /// variable_suppression::priv::type_name_regex_str_.
2573 /// If that string is empty, then an empty regular expression object
2574 /// pointer is returned.
2576 /// @return a pointer to the regular expression object of
2577 /// variable_suppression::priv::type_name_regex_str_.
2578 const sptr_utils::regex_t_sptr
2579 get_type_name_regex() const
2581 if (!type_name_regex_ && !type_name_regex_str_.empty())
2583 sptr_utils::regex_t_sptr r(new regex_t);
2584 if (regcomp(r.get(),
2585 type_name_regex_str_.c_str(),
2587 type_name_regex_ = r;
2589 return type_name_regex_;
2591 };// end class variable_supppression::priv
2593 /// Constructor for the @ref variable_suppression type.
2595 /// @param label an informative text string that the evalution code
2596 /// might use to designate this variable suppression specification in
2597 /// error messages. This parameter might be empty, in which case it's
2598 /// ignored at evaluation time.
2600 /// @param name the name of the variable the user wants the current
2601 /// specification to designate. This parameter might be empty, in
2602 /// which case it's ignored at evaluation time.
2604 /// @param name_regex_str if @p name is empty, this parameter is a
2605 /// regular expression for a family of names of variables the user
2606 /// wants the current specification to designate. If @p name is not
2607 /// empty, then this parameter is ignored at evaluation time. This
2608 /// parameter might be empty, in which case it's ignored at evaluation
2611 /// @param symbol_name the name of the symbol of the variable the user
2612 /// wants the current specification to designate. This parameter
2613 /// might be empty, in which case it's ignored at evaluation time.
2615 /// @param symbol_name_str if @p symbol_name is empty, this parameter
2616 /// is a regular expression for a family of names of symbols of
2617 /// variables the user wants the current specification to designate.
2618 /// If @p symbol_name is not empty, then this parameter is ignored at
2619 /// evaluation time. This parameter might be empty, in which case
2620 /// it's ignored at evaluation time.
2622 /// @param symbol_version the version of the symbol of the variable
2623 /// the user wants the current specification to designate. This
2624 /// parameter might be empty, in which case it's ignored at evaluation
2627 /// @param symbol_version_regex if @p symbol_version is empty, then
2628 /// this parameter is a regular expression for a family of versions of
2629 /// symbol for the variables the user wants the current specification
2630 /// to designate. If @p symbol_version is not empty, then this
2631 /// parameter is ignored at evaluation time. This parameter might be
2632 /// empty, in which case it's ignored at evaluation time.
2634 /// @param type_name the name of the type of the variable the user
2635 /// wants the current specification to designate. This parameter
2636 /// might be empty, in which case it's ignored at evaluation time.
2638 /// @param type_name_regex_str if @p type_name is empty, then this
2639 /// parameter is a regular expression for a family of type names of
2640 /// variables the user wants the current specification to designate.
2641 /// If @p type_name is not empty, then this parameter is ignored at
2642 /// evluation time. This parameter might be empty, in which case it's
2643 /// ignored at evaluation time.
2644 variable_suppression::variable_suppression(const string& label,
2646 const string& name_regex_str,
2647 const string& symbol_name,
2648 const string& symbol_name_regex_str,
2649 const string& symbol_version,
2650 const string& symbol_version_regex,
2651 const string& type_name,
2652 const string& type_name_regex_str)
2653 : suppression_base(label),
2654 priv_(new priv(name, name_regex_str,
2655 symbol_name, symbol_name_regex_str,
2656 symbol_version, symbol_version_regex,
2657 type_name, type_name_regex_str))
2660 /// Virtual destructor for the @erf variable_suppression type.
2661 /// variable_suppression type.
2662 variable_suppression::~variable_suppression()
2665 /// Getter for the name of the variable the user wants the current
2666 /// specification to designate. This property might be empty, in
2667 /// which case it's ignored at evaluation time.
2669 /// @return the name of the variable.
2671 variable_suppression::get_name() const
2672 {return priv_->name_;}
2674 /// Setter for the name of the variable the user wants the current
2675 /// specification to designate. This property might be empty, in
2676 /// which case it's ignored at evaluation time.
2678 /// @param n the new name of the variable to set.
2680 variable_suppression::set_name(const string& n)
2683 /// Getter for the regular expression for a family of names of
2684 /// variables the user wants the current specification to designate.
2685 /// If the variable name as returned by
2686 /// variable_suppression::get_name() is not empty, then this property
2687 /// is ignored at evaluation time. This property might be empty, in
2688 /// which case it's ignored at evaluation time.
2690 /// @return the regular expression for the variable name.
2692 variable_suppression::get_name_regex_str() const
2693 {return priv_->name_regex_str_;}
2695 /// Setter for the regular expression for a family of names of
2696 /// variables the user wants the current specification to designate.
2697 /// If the variable name as returned by
2698 /// variable_suppression::get_name() is not empty, then this property
2699 /// is ignored at evaluation time. This property might be empty, in
2700 /// which case it's ignored at evaluation time.
2702 /// @param r the new regular expression for the variable name.
2704 variable_suppression::set_name_regex_str(const string& r)
2705 {priv_->name_regex_str_ = r;}
2707 /// Getter for the name of the symbol of the variable the user wants
2708 /// the current specification to designate.
2710 /// This property might be empty, in which case it is ignored at
2711 /// evaluation time.
2713 /// @return the name of the symbol of the variable.
2715 variable_suppression::get_symbol_name() const
2716 {return priv_->symbol_name_;}
2718 /// Setter for the name of the symbol of the variable the user wants
2719 /// the current specification to designate.
2721 /// This property might be empty, in which case it is ignored at
2722 /// evaluation time.
2724 /// @param n the new name of the symbol of the variable.
2726 variable_suppression::set_symbol_name(const string& n)
2727 {priv_->symbol_name_ = n;}
2729 /// Getter of the regular expression for a family of symbol names of
2730 /// the variables this specification is about to designate.
2732 /// This property might be empty, in which case it's ignored at
2733 /// evaluation time. Otherwise, it is taken in account iff the
2734 /// property returned by variable_suppression::get_symbol_name() is
2737 /// @return the regular expression for a symbol name of the variable.
2739 variable_suppression::get_symbol_name_regex_str() const
2740 {return priv_->symbol_name_regex_str_;}
2742 /// Setter of the regular expression for a family of symbol names of
2743 /// the variables this specification is about to designate.
2745 /// This property might be empty, in which case it's ignored at
2746 /// evaluation time. Otherwise, it is taken in account iff the
2747 /// property returned by variable_suppression::get_symbol_name() is
2750 /// @param r the regular expression for a symbol name of the variable.
2752 variable_suppression::set_symbol_name_regex_str(const string& r)
2753 {priv_->symbol_name_regex_str_ = r;}
2755 /// Getter for the version of the symbol of the variable the user
2756 /// wants the current specification to designate. This property might
2757 /// be empty, in which case it's ignored at evaluation time.
2759 /// @return the symbol version of the variable.
2761 variable_suppression::get_symbol_version() const
2762 {return priv_->symbol_version_;}
2764 /// Setter for the version of the symbol of the variable the user
2765 /// wants the current specification to designate. This property might
2766 /// be empty, in which case it's ignored at evaluation time.
2768 /// @return the new symbol version of the variable.
2770 variable_suppression::set_symbol_version(const string& v)
2771 {priv_->symbol_version_ = v;}
2773 /// Getter of the regular expression for a family of versions of
2774 /// symbol for the variables the user wants the current specification
2775 /// to designate. If @p symbol_version is not empty, then this
2776 /// property is ignored at evaluation time. This property might be
2777 /// empty, in which case it's ignored at evaluation time.
2779 /// @return the regular expression of the symbol version of the
2782 variable_suppression::get_symbol_version_regex_str() const
2783 {return priv_->symbol_version_regex_str_;}
2785 /// Setter of the regular expression for a family of versions of
2786 /// symbol for the variables the user wants the current specification
2787 /// to designate. If @p symbol_version is not empty, then this
2788 /// property is ignored at evaluation time. This property might be
2789 /// empty, in which case it's ignored at evaluation time.
2791 /// @param v the new regular expression of the symbol version of the
2794 variable_suppression::set_symbol_version_regex_str(const string& r)
2795 {priv_->symbol_version_regex_str_ = r;}
2797 /// Getter for the name of the type of the variable the user wants the
2798 /// current specification to designate.
2800 /// This property might be empty, in which case it's ignored at
2801 /// evaluation time.
2803 /// @return the name of the variable type.
2805 variable_suppression::get_type_name() const
2806 {return priv_->type_name_;}
2808 /// Setter for the name of the type of the variable the user wants the
2809 /// current specification to designate.
2811 /// This property might be empty, in which case it's ignored at
2812 /// evaluation time.
2814 /// @param n the new name of the variable type.
2816 variable_suppression::set_type_name(const string& n)
2817 {priv_->type_name_ = n;}
2819 /// Getter for the regular expression for a family of type names of
2820 /// variables the user wants the current specification to designate.
2822 /// If the type name as returned by
2823 /// variable_suppression::get_type_name() is not empty, then this
2824 /// property is ignored at evaluation time. This property might be
2825 /// empty, in which case it's ignored at evaluation time.
2827 /// @return the regular expression of the variable type name.
2829 variable_suppression::get_type_name_regex_str() const
2830 {return priv_->type_name_regex_str_;}
2832 /// Setter for the regular expression for a family of type names of
2833 /// variables the user wants the current specification to designate.
2835 /// If the type name as returned by
2836 /// variable_suppression::get_type_name() is not empty, then this
2837 /// property is ignored at evaluation time. This property might be
2838 /// empty, in which case it's ignored at evaluation time.
2840 /// @param r the regular expression of the variable type name.
2842 variable_suppression::set_type_name_regex_str(const string& r)
2843 {priv_->type_name_regex_str_ = r;}
2845 /// Evaluate this suppression specification on a given diff node and
2846 /// say if the diff node should be suppressed or not.
2848 /// @param diff the diff node to evaluate this suppression
2849 /// specification against.
2851 /// @return true if @p diff should be suppressed.
2853 variable_suppression::suppresses_diff(const diff* diff) const
2855 const var_diff* d = is_var_diff(diff);
2859 var_decl_sptr fv = is_var_decl(is_decl(d->first_subject())),
2860 sv = is_var_decl(is_decl(d->second_subject()));
2864 string fv_name = fv->get_name(), sv_name = sv->get_name();
2866 // Check for "name" property match.
2867 if (!get_name().empty())
2869 if (get_name() != fv_name && get_name () != sv_name)
2874 // If the "name" property is empty, then consider checking for the
2875 // "name_regex" property match
2876 if (get_name().empty())
2878 const sptr_utils::regex_t_sptr name_regex = priv_->get_name_regex();
2880 && (regexec(name_regex.get(), fv_name.c_str(),
2882 && regexec(name_regex.get(), sv_name.c_str(),
2888 // Check for the symbol_name property match.
2889 string fv_sym_name = fv->get_symbol() ? fv->get_symbol()->get_name() : "";
2890 string sv_sym_name = sv->get_symbol() ? sv->get_symbol()->get_name() : "";
2891 if (!get_symbol_name().empty())
2893 if (get_symbol_name() != fv_sym_name && get_symbol_name() != sv_sym_name)
2898 const sptr_utils::regex_t_sptr sym_name_regex =
2899 priv_->get_symbol_name_regex();
2901 && (regexec(sym_name_regex.get(), fv_sym_name.c_str(),
2903 && regexec(sym_name_regex.get(), sv_sym_name.c_str(),
2908 // Check for symbol_version and symbol_version_regexp property match
2909 string fv_sym_version =
2910 fv->get_symbol() ? fv->get_symbol()->get_version().str() : "";
2911 string sv_sym_version =
2912 sv->get_symbol() ? fv->get_symbol()->get_version().str() : "";
2913 if (!get_symbol_version().empty())
2915 if (get_symbol_version() != fv_sym_version
2916 && get_symbol_version() != sv_sym_version)
2921 const sptr_utils::regex_t_sptr symbol_version_regex =
2922 priv_->get_symbol_version_regex();
2923 if (symbol_version_regex
2924 && (regexec(symbol_version_regex.get(),
2925 fv_sym_version.c_str(),
2927 && regexec(symbol_version_regex.get(),
2928 sv_sym_version.c_str(),
2933 string fv_type_name =
2934 get_type_declaration(fv->get_type())->get_qualified_name();
2935 string sv_type_name =
2936 get_type_declaration(sv->get_type())->get_qualified_name();
2938 // Check for the "type_name" and tye_name_regex properties match.
2939 if (!get_type_name().empty())
2941 if (get_type_name() != fv_type_name && get_type_name() != sv_type_name)
2946 if (get_type_name().empty())
2948 const sptr_utils::regex_t_sptr type_name_regex =
2949 priv_->get_type_name_regex();
2951 && (regexec(type_name_regex.get(), fv_type_name.c_str(),
2953 && regexec(type_name_regex.get(), sv_type_name.c_str(),
2962 /// Parse variable suppression specification, build a resulting @ref
2963 /// variable_suppression type and return a shared pointer to that
2966 /// @return a shared pointer to the newly built @ref
2967 /// variable_suppression. If the variable suppression specification
2968 /// could not be parsed then a nil shared pointer is returned.
2969 static variable_suppression_sptr
2970 read_variable_suppression(const ini::config::section& section)
2972 variable_suppression_sptr result;
2974 if (section.get_name() != "suppress_variable")
2977 ini::simple_property_sptr label_prop =
2978 is_simple_property(section.find_property("label"));
2979 string label_str = (label_prop
2980 ? label_prop->get_value()->as_string()
2983 ini::simple_property_sptr name_prop =
2984 is_simple_property(section.find_property("name"));
2985 string name_str = (name_prop
2986 ? name_prop->get_value()->as_string()
2989 ini::simple_property_sptr name_regex_prop =
2990 is_simple_property(section.find_property("name_regexp"));
2991 string name_regex_str = (name_regex_prop
2992 ? name_regex_prop->get_value()->as_string()
2995 ini::simple_property_sptr sym_name_prop =
2996 is_simple_property(section.find_property("symbol_name"));
2997 string symbol_name = (sym_name_prop
2998 ? sym_name_prop->get_value()->as_string()
3001 ini::simple_property_sptr sym_name_regex_prop =
3002 is_simple_property(section.find_property("symbol_name_regexp"));
3003 string symbol_name_regex_str = sym_name_regex_prop
3004 ? sym_name_regex_prop->get_value()->as_string()
3007 ini::simple_property_sptr sym_version_prop =
3008 is_simple_property(section.find_property("symbol_version"));
3009 string symbol_version = sym_version_prop
3010 ? sym_version_prop->get_value()->as_string()
3013 ini::simple_property_sptr sym_version_regex_prop =
3014 is_simple_property(section.find_property("symbol_version_regexp"));
3015 string symbol_version_regex_str = sym_version_regex_prop
3016 ? sym_version_regex_prop->get_value()->as_string()
3019 ini::simple_property_sptr type_name_prop =
3020 is_simple_property(section.find_property("type_name"));
3021 string type_name_str = type_name_prop
3022 ? type_name_prop->get_value()->as_string()
3025 ini::simple_property_sptr type_name_regex_prop =
3026 is_simple_property(section.find_property("type_name_regexp"));
3027 string type_name_regex_str = type_name_regex_prop
3028 ? type_name_regex_prop->get_value()->as_string()
3031 if (label_str.empty()
3033 && name_regex_str.empty()
3034 && symbol_name.empty()
3035 && symbol_name_regex_str.empty()
3036 && symbol_version.empty()
3037 && symbol_version_regex_str.empty()
3038 && type_name_str.empty()
3039 && type_name_regex_str.empty())
3042 result.reset(new variable_suppression(label_str, name_str, name_regex_str,
3043 symbol_name, symbol_name_regex_str,
3044 symbol_version, symbol_version_regex_str,
3045 type_name_str, type_name_regex_str));
3049 // </variable_suppression stuff>
3051 /// The private member (pimpl) for @ref diff_context.
3052 struct diff_context::priv
3054 diff_category allowed_category_;
3055 types_or_decls_diff_map_type types_or_decls_diff_map;
3056 vector<diff_sptr> canonical_diffs;
3057 vector<filtering::filter_base_sptr> filters_;
3058 suppressions_type suppressions_;
3059 pointer_map visited_diff_nodes_;
3060 // This is the last visited diff node, per class of equivalence.
3061 // It's set during the redundant diff node marking process.
3062 pointer_map last_visited_diff_node_;
3063 corpus_sptr first_corpus_;
3064 corpus_sptr second_corpus_;
3065 ostream* default_output_stream_;
3066 ostream* error_output_stream_;
3067 bool forbid_visiting_a_node_twice_;
3068 bool show_stats_only_;
3069 bool show_soname_change_;
3070 bool show_architecture_change_;
3071 bool show_deleted_fns_;
3072 bool show_changed_fns_;
3073 bool show_added_fns_;
3074 bool show_deleted_vars_;
3075 bool show_changed_vars_;
3076 bool show_added_vars_;
3077 bool show_linkage_names_;
3078 bool show_redundant_changes_;
3079 bool show_syms_unreferenced_by_di_;
3080 bool show_added_syms_unreferenced_by_di_;
3081 bool dump_diff_tree_;
3084 : allowed_category_(EVERYTHING_CATEGORY),
3085 default_output_stream_(),
3086 error_output_stream_(),
3087 forbid_visiting_a_node_twice_(true),
3088 show_stats_only_(false),
3089 show_soname_change_(true),
3090 show_architecture_change_(true),
3091 show_deleted_fns_(true),
3092 show_changed_fns_(true),
3093 show_added_fns_(true),
3094 show_deleted_vars_(true),
3095 show_changed_vars_(true),
3096 show_added_vars_(true),
3097 show_linkage_names_(false),
3098 show_redundant_changes_(true),
3099 show_syms_unreferenced_by_di_(true),
3100 show_added_syms_unreferenced_by_di_(true),
3103 };// end struct diff_context::priv
3105 diff_context::diff_context()
3106 : priv_(new diff_context::priv)
3108 // Setup all the diff output filters we have.
3109 filtering::filter_base_sptr f;
3111 f.reset(new filtering::harmless_filter);
3114 f.reset(new filtering::harmful_filter);
3118 /// Set the corpora that are being compared into the context, so that
3119 /// some lower-level routines can have a chance to have access to
3122 /// @param corp1 the first corpus involved in the comparison.
3124 /// @param corp2 the second corpus involved in the comparison.
3126 diff_context::set_corpora(const corpus_sptr corp1,
3127 const corpus_sptr corp2)
3129 priv_->first_corpus_ = corp1;
3130 priv_->second_corpus_ = corp2;
3133 /// Get the first corpus of the comparison, from the current context.
3135 /// @return the first corpus of the comparison.
3137 diff_context::get_first_corpus() const
3138 {return priv_->first_corpus_;}
3140 /// Get the second corpus of the comparison, from the current context.
3142 /// @return the second corpus of the comparison, from the current
3145 diff_context::get_second_corpus() const
3146 {return priv_->second_corpus_;}
3148 /// Tests if the current diff context already has a diff for two decls.
3150 /// @param first the first decl to consider.
3152 /// @param second the second decl to consider.
3154 /// @return a pointer to the diff for @p first @p second if found,
3157 diff_context::has_diff_for(const type_or_decl_base_sptr first,
3158 const type_or_decl_base_sptr second) const
3160 types_or_decls_diff_map_type::const_iterator i =
3161 priv_->types_or_decls_diff_map.find(std::make_pair(first, second));
3162 if (i != priv_->types_or_decls_diff_map.end())
3167 /// Tests if the current diff context already has a diff for two types.
3169 /// @param first the first type to consider.
3171 /// @param second the second type to consider.
3173 /// @return a pointer to the diff for @p first @p second if found,
3176 diff_context::has_diff_for_types(const type_base_sptr first,
3177 const type_base_sptr second) const
3178 {return has_diff_for(first, second);}
3180 /// Tests if the current diff context already has a given diff.
3182 ///@param d the diff to consider.
3184 /// @return a pointer to the diff found for @p d
3186 diff_context::has_diff_for(const diff* d) const
3187 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
3189 /// Tests if the current diff context already has a given diff.
3191 ///@param d the diff to consider.
3193 /// @return a pointer to the diff found for @p d
3195 diff_context::has_diff_for(const diff_sptr d) const
3196 {return has_diff_for(d->first_subject(), d->second_subject());}
3198 /// Getter for the bitmap that represents the set of categories that
3199 /// the user wants to see reported.
3201 /// @return a bitmap that represents the set of categories that the
3202 /// user wants to see reported.
3204 diff_context::get_allowed_category() const
3205 {return priv_->allowed_category_;}
3207 /// Setter for the bitmap that represents the set of categories that
3208 /// the user wants to see reported.
3210 /// @param c a bitmap that represents the set of categories that the
3211 /// user wants to see represented.
3213 diff_context::set_allowed_category(diff_category c)
3214 {priv_->allowed_category_ = c;}
3216 /// Setter for the bitmap that represents the set of categories that
3217 /// the user wants to see reported
3219 /// This function perform a bitwise or between the new set of
3220 /// categories and the current ones, and then sets the current
3221 /// categories to the result of the or.
3223 /// @param c a bitmap that represents the set of categories that the
3224 /// user wants to see represented.
3226 diff_context::switch_categories_on(diff_category c)
3227 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
3229 /// Setter for the bitmap that represents the set of categories that
3230 /// the user wants to see reported
3232 /// This function actually unsets bits from the current categories.
3234 /// @param c a bitmap that represents the set of categories to unset
3235 /// from the current categories.
3237 diff_context::switch_categories_off(diff_category c)
3238 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
3240 /// Add a diff for two decls to the cache of the current diff_context
3242 /// @param first the first decl to consider.
3244 /// @param second the second decl to consider.
3246 /// @param the diff to add.
3248 diff_context::add_diff(type_or_decl_base_sptr first,
3249 type_or_decl_base_sptr second,
3251 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
3253 /// Add a diff tree node to the cache of the current diff_context
3255 /// @param d the diff tree node to add.
3257 diff_context::add_diff(const diff* d)
3261 diff_sptr dif(const_cast<diff*>(d), noop_deleter());
3262 add_diff(d->first_subject(), d->second_subject(), dif);
3266 /// Add a diff tree node to the cache of the current diff_context
3268 /// @param d the diff tree node to add.
3270 diff_context::add_diff(const diff_sptr d)
3273 add_diff(d->first_subject(), d->second_subject(), d);
3276 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
3277 /// @ref diff represented by their two subjects.
3279 /// @param first the first subject of the diff.
3281 /// @param second the second subject of the diff.
3283 /// @return the canonical diff for the diff node represented by the
3284 /// two diff subjects @p first and @p second. If no canonical diff
3285 /// node was registered for these subjects, then a nil node is
3288 diff_context::get_canonical_diff_for(const type_or_decl_base_sptr first,
3289 const type_or_decl_base_sptr second) const
3290 {return has_diff_for(first, second);}
3292 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
3293 /// @ref diff represented by the two subjects of a given diff node.
3295 /// @param d the diff node to get the canonical node for.
3297 /// @return the canonical diff for the diff node represented by the
3298 /// two diff subjects of @p d. If no canonical diff node was
3299 /// registered for these subjects, then a nil node is returned.
3301 diff_context::get_canonical_diff_for(const diff_sptr d) const
3302 {return has_diff_for(d);}
3304 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
3305 /// @ref diff represented by their two subjects.
3307 /// @param first the first subject of the diff.
3309 /// @param second the second subject of the diff.
3311 /// @param d the new canonical diff.
3313 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
3314 const type_or_decl_base_sptr second,
3318 if (!has_diff_for(first, second))
3320 add_diff(first, second, d);
3321 priv_->canonical_diffs.push_back(d);
3325 /// If there is is a @ref CanonicalDiff "canonical diff node"
3326 /// registered for two diff subjects, return it. Otherwise, register
3327 /// a canonical diff node for these two diff subjects and return it.
3329 /// @param first the first subject of the diff.
3331 /// @param second the second subject of the diff.
3333 /// @param d the new canonical diff node.
3335 /// @return the canonical diff node.
3337 diff_context::set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
3338 const type_or_decl_base_sptr second,
3339 const diff_sptr canonical_diff)
3341 assert(canonical_diff);
3343 diff_sptr canonical = get_canonical_diff_for(first, second);
3346 canonical = canonical_diff;
3347 set_canonical_diff_for(first, second, canonical);
3352 /// Set the canonical diff node property of a given diff node
3355 /// For a given diff node that has no canonical diff node, retrieve
3356 /// the canonical diff node (by looking at its diff subjects and at
3357 /// the current context) and set the canonical diff node property of
3358 /// the diff node to that canonical diff node. If no canonical diff
3359 /// node has been registered to the diff context for the subjects of
3360 /// the diff node then, register the canonical diff node as being the
3361 /// diff node itself; and set its canonical diff node property as
3362 /// such. Otherwise, if the diff node already has a canonical diff
3363 /// node, do nothing.
3365 /// @param diff the diff node to initialize the canonical diff node
3368 diff_context::initialize_canonical_diff(const diff_sptr diff)
3370 if (diff->get_canonical_diff() == 0)
3372 diff_sptr canonical =
3373 set_or_get_canonical_diff_for(diff->first_subject(),
3374 diff->second_subject(),
3376 diff->set_canonical_diff(canonical.get());
3380 /// Test if a diff node has been traversed.
3382 /// @param d the diff node to consider.
3384 /// @return the first diff node against which @p d is redundant.
3386 diff_context::diff_has_been_visited(const diff* d) const
3388 const diff* canonical = d->get_canonical_diff();
3391 size_t ptr_value = reinterpret_cast<size_t>(canonical);
3392 pointer_map::iterator it = priv_->visited_diff_nodes_.find(ptr_value);
3393 if (it != priv_->visited_diff_nodes_.end())
3394 return reinterpret_cast<diff*>(it->second);
3399 /// Test if a diff node has been traversed.
3401 /// @param d the diff node to consider.
3403 /// @return the first diff node against which @p d is redundant.
3405 diff_context::diff_has_been_visited(const diff_sptr d) const
3407 diff_sptr diff(diff_has_been_visited(d.get()));
3411 /// Mark a diff node as traversed by a traversing algorithm.
3413 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
3414 /// node that is marked as traversed.
3416 /// Subsequent invocations of diff_has_been_visited() on the diff node
3417 /// will yield true.
3419 diff_context::mark_diff_as_visited(const diff* d)
3421 if(diff_has_been_visited(d))
3424 const diff* canonical = d->get_canonical_diff();
3427 size_t canonical_ptr_value = reinterpret_cast<size_t>(canonical);
3428 size_t diff_ptr_value = reinterpret_cast<size_t>(d);;
3429 priv_->visited_diff_nodes_[canonical_ptr_value] = diff_ptr_value;
3432 /// Unmark all the diff nodes that were marked as being traversed.
3434 diff_context::forget_visited_diffs()
3435 {priv_->visited_diff_nodes_.clear();}
3437 /// Mark a given diff node as being the last one that has been visited
3438 /// in its class of equivalence.
3440 /// @param d the diff node to mark.
3442 diff_context::mark_last_diff_visited_per_class_of_equivalence(const diff* d)
3444 if (!d->get_canonical_diff())
3447 size_t v0 = reinterpret_cast<size_t>(d->get_canonical_diff());
3448 size_t v1 = reinterpret_cast<size_t>(d);
3449 priv_->last_visited_diff_node_[v0]= v1;
3452 /// Clear the marking about the diff diff nodes in a given class of
3455 diff_context::clear_last_diffs_visited_per_class_of_equivalence()
3456 {priv_->last_visited_diff_node_.clear();}
3458 /// Return the last diff node visited in the class of equivalence of
3459 /// a given diff node.
3461 /// @param d the diff node which class of equivalence to consider.
3463 /// @return the last diff node visited in the class of equivalence of
3464 /// the diff node @p d.
3466 diff_context::get_last_visited_diff_of_class_of_equivalence(const diff* d)
3468 size_t v0 = reinterpret_cast<size_t>(d);
3470 pointer_map::const_iterator it = priv_->last_visited_diff_node_.find(v0);
3471 if (it != priv_->last_visited_diff_node_.end())
3472 return reinterpret_cast<const diff*>(it->second);
3476 /// This sets a flag that, if it's true, then during the traversing of
3477 /// a diff nodes tree each node is visited at most once.
3479 /// @param f if true then during the traversing of a diff nodes tree
3480 /// each node is visited at most once.
3482 diff_context::forbid_visiting_a_node_twice(bool f)
3483 {priv_->forbid_visiting_a_node_twice_ = f;}
3485 /// Return a flag that, if true, then during the traversing of a diff
3486 /// nodes tree each node is visited at most once.
3488 /// @return the boolean flag.
3490 diff_context::visiting_a_node_twice_is_forbidden() const
3491 {return priv_->forbid_visiting_a_node_twice_;}
3493 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
3495 /// @return the vector of tree filters to apply to diff sub-trees.
3496 const filtering::filters&
3497 diff_context::diff_filters() const
3498 {return priv_->filters_;}
3500 /// Setter for the diff filters to apply to a given diff sub-tree.
3502 /// @param f the new diff filter to add to the vector of diff filters
3503 /// to apply to diff sub-trees.
3505 diff_context::add_diff_filter(filtering::filter_base_sptr f)
3506 {priv_->filters_.push_back(f);}
3508 /// Apply the diff filters to a given diff sub-tree.
3510 /// If the current context is instructed to filter out some categories
3511 /// then this function walks the given sub-tree and categorizes its
3512 /// nodes by using the filters held by the context.
3514 /// @param diff the diff sub-tree to apply the filters to.
3516 diff_context::maybe_apply_filters(diff_sptr diff)
3521 if (get_allowed_category() == EVERYTHING_CATEGORY)
3524 if (!diff->has_changes())
3527 for (filtering::filters::const_iterator i = diff_filters().begin();
3528 i != diff_filters().end();
3531 filtering::apply_filter(*i, diff);
3532 propagate_categories(diff);
3537 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
3540 /// If the current context is instructed to filter out some categories
3541 /// then this function walks the diff tree and categorizes its nodes
3542 /// by using the filters held by the context.
3544 /// @param diff the corpus diff to apply the filters to.
3546 diff_context::maybe_apply_filters(corpus_diff_sptr diff)
3549 if (!diff || !diff->has_changes())
3552 for (filtering::filters::const_iterator i = diff_filters().begin();
3553 i != diff_filters().end();
3556 filtering::apply_filter(**i, diff);
3557 propagate_categories(diff);
3561 /// Getter for the vector of suppressions that specify which diff node
3562 /// reports should be dropped on the floor.
3564 /// @return the set of suppressions.
3566 diff_context::suppressions() const
3567 {return priv_->suppressions_;}
3569 /// Add a new suppression specification that specifies which diff node
3570 /// reports should be dropped on the floor.
3572 /// @param suppr the new suppression specification to add to the
3573 /// existing set of suppressions specifications of the diff context.
3575 diff_context::add_suppression(const suppression_sptr suppr)
3576 {priv_->suppressions_.push_back(suppr);}
3578 /// Add new suppression specifications that specify which diff node
3579 /// reports should be dropped on the floor.
3581 /// @param supprs the new suppression specifications to add to the
3582 /// existing set of suppression specifications of the diff context.
3584 diff_context::add_suppressions(const suppressions_type& supprs)
3586 priv_->suppressions_.insert(priv_->suppressions_.end(),
3587 supprs.begin(), supprs.end());
3590 /// Set a flag saying if the comparison module should only show the
3593 /// @param f the flag to set.
3595 diff_context::show_stats_only(bool f)
3596 {priv_->show_stats_only_ = f;}
3598 /// Test if the comparison module should only show the diff stats.
3600 /// @return true if the comparison module should only show the diff
3601 /// stats, false otherwise.
3603 diff_context::show_stats_only() const
3604 {return priv_->show_stats_only_;}
3606 /// Setter for the property that says if the comparison module should
3607 /// show the soname changes in its report.
3609 /// @param f the new value of the property.
3611 diff_context::show_soname_change(bool f)
3612 {priv_->show_soname_change_ = f;}
3614 /// Getter for the property that says if the comparison module should
3615 /// show the soname changes in its report.
3617 /// @return the value of the property.
3619 diff_context::show_soname_change() const
3620 {return priv_->show_soname_change_;}
3622 /// Setter for the property that says if the comparison module should
3623 /// show the architecture changes in its report.
3625 /// @param f the new value of the property.
3627 diff_context::show_architecture_change(bool f)
3628 {priv_->show_architecture_change_ = f;}
3630 /// Getter for the property that says if the comparison module should
3631 /// show the architecture changes in its report.
3633 /// @return the value of the property.
3635 diff_context::show_architecture_change() const
3636 {return priv_->show_architecture_change_;}
3638 /// Set a flag saying to show the deleted functions.
3640 /// @param f true to show deleted functions.
3642 diff_context::show_deleted_fns(bool f)
3643 {priv_->show_deleted_fns_ = f;}
3645 /// @return true if we want to show the deleted functions, false
3648 diff_context::show_deleted_fns() const
3649 {return priv_->show_deleted_fns_;}
3651 /// Set a flag saying to show the changed functions.
3653 /// @param f true to show the changed functions.
3655 diff_context::show_changed_fns(bool f)
3656 {priv_->show_changed_fns_ = f;}
3658 /// @return true if we want to show the changed functions, false otherwise.
3660 diff_context::show_changed_fns() const
3661 {return priv_->show_changed_fns_;}
3663 /// Set a flag saying to show the added functions.
3665 /// @param f true to show the added functions.
3667 diff_context::show_added_fns(bool f)
3668 {priv_->show_added_fns_ = f;}
3670 /// @return true if we want to show the added functions, false
3673 diff_context::show_added_fns() const
3674 {return priv_->show_added_fns_;}
3676 /// Set a flag saying to show the deleted variables.
3678 /// @param f true to show the deleted variables.
3680 diff_context::show_deleted_vars(bool f)
3681 {priv_->show_deleted_vars_ = f;}
3683 /// @return true if we want to show the deleted variables, false
3686 diff_context::show_deleted_vars() const
3687 {return priv_->show_deleted_vars_;}
3689 /// Set a flag saying to show the changed variables.
3691 /// @param f true to show the changed variables.
3693 diff_context::show_changed_vars(bool f)
3694 {priv_->show_changed_vars_ = f;}
3696 /// @return true if we want to show the changed variables, false otherwise.
3698 diff_context::show_changed_vars() const
3699 {return priv_->show_changed_vars_;}
3701 /// Set a flag saying to show the added variables.
3703 /// @param f true to show the added variables.
3705 diff_context::show_added_vars(bool f)
3706 {priv_->show_added_vars_ = f;}
3708 /// @return true if we want to show the added variables, false
3711 diff_context::show_added_vars() const
3712 {return priv_->show_added_vars_;}
3715 diff_context::show_linkage_names() const
3716 {return priv_->show_linkage_names_;}
3719 diff_context::show_linkage_names(bool f)
3720 {priv_->show_linkage_names_= f;}
3722 /// A getter for the flag that says if we should report about
3723 /// functions or variables diff nodes that have *exclusively*
3724 /// redundant diff tree children nodes.
3726 /// @return the flag.
3728 diff_context::show_redundant_changes() const
3729 {return priv_->show_redundant_changes_;}
3731 /// A setter for the flag that says if we should report about
3732 /// functions or variables diff nodes that have *exclusively*
3733 /// redundant diff tree children nodes.
3735 /// @param f the flag to set.
3737 diff_context::show_redundant_changes(bool f)
3738 {priv_->show_redundant_changes_ = f;}
3740 /// Getter for the flag that indicates if symbols not referenced by
3741 /// any debug info are to be compared and reported about.
3743 /// @return the boolean flag.
3745 diff_context::show_symbols_unreferenced_by_debug_info() const
3746 {return priv_->show_syms_unreferenced_by_di_;}
3748 /// Setter for the flag that indicates if symbols not referenced by
3749 /// any debug info are to be compared and reported about.
3751 /// @param f the new flag to set.
3753 diff_context::show_symbols_unreferenced_by_debug_info(bool f)
3754 {priv_->show_syms_unreferenced_by_di_ = f;}
3756 /// Getter for the flag that indicates if symbols not referenced by
3757 /// any debug info and that got added are to be reported about.
3759 /// @return true iff symbols not referenced by any debug info and that
3760 /// got added are to be reported about.
3762 diff_context::show_added_symbols_unreferenced_by_debug_info() const
3763 {return priv_->show_added_syms_unreferenced_by_di_;}
3765 /// Setter for the flag that indicates if symbols not referenced by
3766 /// any debug info and that got added are to be reported about.
3768 /// @param f the new flag that says if symbols not referenced by any
3769 /// debug info and that got added are to be reported about.
3771 diff_context::show_added_symbols_unreferenced_by_debug_info(bool f)
3772 {priv_->show_added_syms_unreferenced_by_di_ = f;}
3774 /// Setter for the default output stream used by code of the
3775 /// comparison engine. By default the default output stream is a NULL
3778 /// @param o a pointer to the default output stream.
3780 diff_context::default_output_stream(ostream* o)
3781 {priv_->default_output_stream_ = o;}
3783 /// Getter for the default output stream used by code of the
3784 /// comparison engine. By default the default output stream is a NULL
3787 /// @return a pointer to the default output stream.
3789 diff_context::default_output_stream()
3790 {return priv_->default_output_stream_;}
3792 /// Setter for the errror output stream used by code of the comparison
3793 /// engine. By default the error output stream is a NULL pointer.
3795 /// @param o a pointer to the error output stream.
3797 diff_context::error_output_stream(ostream* o)
3798 {priv_->error_output_stream_ = o;}
3800 /// Getter for the errror output stream used by code of the comparison
3801 /// engine. By default the error output stream is a NULL pointer.
3803 /// @return a pointer to the error output stream.
3805 diff_context::error_output_stream() const
3806 {return priv_->error_output_stream_;}
3808 /// Test if the comparison engine should dump the diff tree for the
3809 /// changed functions and variables it has.
3811 /// @return true if after the comparison, the engine should dump the
3812 /// diff tree for the changed functions and variables it has.
3814 diff_context::dump_diff_tree() const
3815 {return priv_->dump_diff_tree_;}
3817 /// Set if the comparison engine should dump the diff tree for the
3818 /// changed functions and variables it has.
3820 /// @param f true if after the comparison, the engine should dump the
3821 /// diff tree for the changed functions and variables it has.
3823 diff_context::dump_diff_tree(bool f)
3824 {priv_->dump_diff_tree_ = f;}
3826 /// Emit a textual representation of a diff tree to the error output
3827 /// stream of the current context, for debugging purposes.
3829 /// @param d the diff tree to serialize to the error output associated
3830 /// to the current instance of @ref diff_context.
3832 diff_context::do_dump_diff_tree(const diff_sptr d) const
3834 if (error_output_stream())
3835 print_diff_tree(d, *error_output_stream());
3838 /// Emit a textual representation of a @ref corpus_diff tree to the error
3839 /// output stream of the current context, for debugging purposes.
3841 /// @param d the @ref corpus_diff tree to serialize to the error
3842 /// output associated to the current instance of @ref diff_context.
3844 diff_context::do_dump_diff_tree(const corpus_diff_sptr d) const
3846 if (error_output_stream())
3847 print_diff_tree(d, *error_output_stream());
3849 // </diff_context stuff>
3853 /// Private data for the @ref diff type.
3858 type_or_decl_base_sptr first_subject_;
3859 type_or_decl_base_sptr second_subject_;
3860 vector<diff_sptr> children_;
3862 diff* canonical_diff_;
3863 diff_context_sptr ctxt_;
3864 diff_category local_category_;
3865 diff_category category_;
3866 mutable bool reported_once_;
3867 mutable bool currently_reporting_;
3868 mutable string pretty_representation_;
3874 priv(type_or_decl_base_sptr first_subject,
3875 type_or_decl_base_sptr second_subject,
3876 diff_context_sptr ctxt,
3877 diff_category category,
3879 bool currently_reporting)
3882 first_subject_(first_subject),
3883 second_subject_(second_subject),
3887 local_category_(category),
3888 category_(category),
3889 reported_once_(reported_once),
3890 currently_reporting_(currently_reporting)
3893 /// Check if a given categorization of a diff node should make it be
3896 /// @param category the categorization to take into account.
3898 is_filtered_out(diff_category category)
3900 if (ctxt_->get_allowed_category() == EVERYTHING_CATEGORY)
3903 /// We don't want to display nodes suppressed by a user-provided
3904 /// suppression specification.
3905 if (category & SUPPRESSED_CATEGORY)
3908 // We don't want to display redundant diff nodes, when the user
3909 // asked to avoid seeing redundant diff nodes.
3910 if (!ctxt_->show_redundant_changes()
3911 && (category & REDUNDANT_CATEGORY))
3914 if (category == NO_CHANGE_CATEGORY)
3917 // Ignore the REDUNDANT_CATEGORY bit when comparing allowed
3918 // categories and the current set of categories.
3919 return !((category & ~REDUNDANT_CATEGORY)
3920 & (ctxt_->get_allowed_category()
3921 & ~REDUNDANT_CATEGORY));
3923 };// end class diff::priv
3925 /// A functor to compare two instances of @ref diff_sptr.
3926 struct diff_less_than_functor
3928 /// An operator that takes two instances of @ref diff_sptr returns
3929 /// true if its first operand compares less than its second operand.
3931 /// @param l the first operand to consider.
3933 /// @param r the second operand to consider.
3935 /// @return true if @p l compares less than @p r.
3937 operator()(const diff_sptr l, const diff_sptr r) const
3939 if (!l || !r || !l->first_subject() || !r->first_subject())
3942 string l_qn = get_name(l->first_subject());
3943 string r_qn = get_name(r->first_subject());
3949 /// Constructor for the @ref diff type.
3951 /// This constructs a diff between two subjects that are actually
3952 /// declarations; the first and the second one.
3954 /// @param first_subject the first decl (subject) of the diff.
3956 /// @param second_subject the second decl (subject) of the diff.
3957 diff::diff(type_or_decl_base_sptr first_subject,
3958 type_or_decl_base_sptr second_subject)
3959 : priv_(new priv(first_subject, second_subject,
3960 diff_context_sptr(),
3962 /*reported_once=*/false,
3963 /*currently_reporting=*/false))
3966 /// Constructor for the @ref diff type.
3968 /// This constructs a diff between two subjects that are actually
3969 /// declarations; the first and the second one.
3971 /// @param first_subject the first decl (subject) of the diff.
3973 /// @param second_subject the second decl (subject) of the diff.
3975 /// @param ctxt the context of the diff.
3976 diff::diff(type_or_decl_base_sptr first_subject,
3977 type_or_decl_base_sptr second_subject,
3978 diff_context_sptr ctxt)
3979 : priv_(new priv(first_subject, second_subject,
3980 ctxt, NO_CHANGE_CATEGORY,
3981 /*reported_once=*/false,
3982 /*currently_reporting=*/false))
3985 /// Flag a given diff node as being traversed.
3987 /// For certain diff nodes like @ref class_diff, it's important to
3988 /// avoid traversing the node again while it's already being
3989 /// traversed; otherwise this leads to infinite loops. So the
3990 /// diff::begin_traversing() and diff::end_traversing() methods flag a
3991 /// given node as being traversed (or not), so that
3992 /// diff::is_traversing() can tell if the node is being traversed.
3994 /// Note that traversing a node means visiting it *and* visiting its
3997 /// The canonical node is marked as being traversed too.
3999 /// These functions are called by the traversing code.
4001 diff::begin_traversing()
4003 assert(!is_traversing());
4004 if (priv_->canonical_diff_)
4005 priv_->canonical_diff_->priv_->traversing_ = true;
4006 priv_->traversing_ = true;
4009 /// Tell if a given node is being traversed or not.
4011 /// Note that traversing a node means visiting it *and* visiting its
4014 /// It's the canonical node which is looked at, actually.
4016 /// Please read the comments for the diff::begin_traversing() for mode
4019 /// @return true if the current instance of @diff is being traversed.
4021 diff::is_traversing() const
4023 if (priv_->canonical_diff_)
4024 return priv_->canonical_diff_->priv_->traversing_;
4025 return priv_->traversing_;
4028 /// Flag a given diff node as not being traversed anymore.
4030 /// Note that traversing a node means visiting it *and* visiting its
4033 /// Please read the comments of the function diff::begin_traversing()
4034 /// for mode context.
4036 diff::end_traversing()
4038 assert(is_traversing());
4039 if (priv_->canonical_diff_)
4040 priv_->canonical_diff_->priv_->traversing_ = false;
4041 priv_->traversing_ = false;
4044 /// Finish the building of a given kind of a diff tree node.
4046 /// For instance, certain kinds of diff tree node have specific
4047 /// children nodes that are populated after the constructor of the
4048 /// diff tree node has been called. In that case, calling overloads
4049 /// of this method ensures that these children nodes are properly
4050 /// gathered and setup.
4052 diff::finish_diff_type()
4056 /// Getter of the first subject of the diff.
4058 /// @return the first subject of the diff.
4059 type_or_decl_base_sptr
4060 diff::first_subject() const
4061 {return dynamic_pointer_cast<type_or_decl_base>(priv_->first_subject_);}
4063 /// Getter of the second subject of the diff.
4065 /// @return the second subject of the diff.
4066 type_or_decl_base_sptr
4067 diff::second_subject() const
4068 {return dynamic_pointer_cast<type_or_decl_base>(priv_->second_subject_);}
4070 /// Getter for the children nodes of the current @ref diff node.
4072 /// @return a vector of the children nodes.
4073 const vector<diff_sptr>&
4074 diff::children_nodes() const
4075 {return priv_->children_;}
4077 /// Getter for the parent node of the current @ref diff node.
4079 /// @return the parent node of the current @ref diff node.
4081 diff::parent_node() const
4082 {return priv_->parent_;}
4084 /// Getter for the canonical diff of the current instance of @ref
4087 /// Note that the canonical diff node for the current instanc eof diff
4088 /// node must have been set by invoking
4089 /// class_diff::initialize_canonical_diff() on the current instance of
4092 /// @return the canonical diff node or null if none was set.
4094 diff::get_canonical_diff() const
4095 {return priv_->canonical_diff_;}
4097 /// Setter for the canonical diff of the current instance of @ref
4100 /// @param d the new canonical node to set.
4102 diff::set_canonical_diff(diff * d)
4103 {priv_->canonical_diff_ = d;}
4105 /// Add a new child node to the vector of children nodes for the
4106 /// current @ref diff node.
4108 /// @param d the new child node to add to the children nodes.
4110 diff::append_child_node(diff_sptr d)
4113 priv_->children_.push_back(d);
4115 diff_less_than_functor comp;
4116 std::sort(priv_->children_.begin(),
4117 priv_->children_.end(),
4120 d->priv_->parent_ = this;
4123 /// Getter of the context of the current diff.
4125 /// @return the context of the current diff.
4126 const diff_context_sptr
4127 diff::context() const
4128 {return priv_->ctxt_;}
4130 /// Setter of the context of the current diff.
4132 /// @param c the new context to set.
4134 diff::context(diff_context_sptr c)
4137 /// Tests if we are currently in the middle of emitting a report for
4140 /// @return true if we are currently emitting a report for the
4141 /// current diff, false otherwise.
4143 diff::currently_reporting() const
4145 if (priv_->canonical_diff_)
4146 return priv_->canonical_diff_->priv_->currently_reporting_;
4147 return priv_->currently_reporting_;
4150 /// Sets a flag saying if we are currently in the middle of emitting
4151 /// a report for this diff.
4153 /// @param f true if we are currently emitting a report for the
4154 /// current diff, false otherwise.
4156 diff::currently_reporting(bool f) const
4158 if (priv_->canonical_diff_)
4159 priv_->canonical_diff_->priv_->currently_reporting_ = f;
4160 priv_->currently_reporting_ = f;
4163 /// Tests if a report has already been emitted for the current diff.
4165 /// @return true if a report has already been emitted for the
4166 /// current diff, false otherwise.
4168 diff::reported_once() const
4170 assert(priv_->canonical_diff_);
4171 return priv_->canonical_diff_->priv_->reported_once_;
4174 /// The generic traversing code that walks a given diff sub-tree.
4176 /// Note that there is a difference between traversing a diff node and
4177 /// visiting it. Basically, traversing a diff node means visiting it
4178 /// and visiting its children nodes too. So one can visit a node
4179 /// without traversing it. But traversing a node without visiting it
4180 /// is not possible.
4182 /// Note that by default this traversing code visits a given class of
4183 /// equivalence of a diff node only once. This behaviour can been
4184 /// changed by calling
4185 /// diff_context::visiting_a_node_twice_is_forbidden(), but this is
4186 /// very risky as it might create endless loops while visiting a diff
4187 /// tree graph that has changes that refer to themselves; that is,
4188 /// diff tree graphs with cycles.
4190 /// When a diff node is encountered, the
4191 /// diff_node_visitor::visit_begin() method is invoked on the diff
4194 /// If the diff node has already been visited, then
4195 /// node_visitor::visit_end() is called on it and the node traversing
4196 /// is done; the children of the diff node are not visited in this
4199 /// If the diff node has *NOT* been visited yet, then the
4200 /// diff_node_visitor::visit() method is invoked with it's 'pre'
4201 /// argument set to true. Then if the diff_node_visitor::visit()
4202 /// returns true, then the children nodes of the diff node are
4203 /// visited. Otherwise, no children nodes of the diff node is
4204 /// visited and the diff_node_visitor::visit_end() is called.
4206 /// After the children nodes are visited (and only if they are
4207 /// visited) the diff_node_visitor::visit() method is invoked with
4208 /// it's 'pre' argument set to false. And then the
4209 /// diff_node_visitor::visit_end() is called.
4211 /// @param v the entity that visits each node of the diff sub-tree.
4213 /// @return true to tell the caller that all of the sub-tree could be
4214 /// walked. This instructs the caller to keep walking the rest of the
4215 /// tree. Return false otherwise.
4217 diff::traverse(diff_node_visitor& v)
4221 v.visit_begin(this);
4223 bool already_visited = false;
4224 if (context()->visiting_a_node_twice_is_forbidden()
4225 && context()->diff_has_been_visited(this))
4226 already_visited = true;
4228 bool mark_visited_nodes_as_traversed =
4229 !(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_VISITED);
4231 if (!already_visited && !v.visit(this, /*pre=*/true))
4234 if (mark_visited_nodes_as_traversed)
4235 context()->mark_diff_as_visited(this);
4239 if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND)
4241 && !already_visited)
4244 for (vector<diff_sptr>::const_iterator i = children_nodes().begin();
4245 i != children_nodes().end();
4248 if (!(*i)->traverse(v))
4251 if (mark_visited_nodes_as_traversed)
4252 context()->mark_diff_as_visited(this);
4260 if (!v.visit(this, /*pref=*/false))
4263 if (mark_visited_nodes_as_traversed)
4264 context()->mark_diff_as_visited(this);
4269 if (!already_visited && mark_visited_nodes_as_traversed)
4270 context()->mark_diff_as_visited(this);
4275 /// Sets a flag saying if a report has already been emitted for the
4278 /// @param f true if a report has already been emitted for the
4279 /// current diff, false otherwise.
4281 diff::reported_once(bool f) const
4283 assert(priv_->canonical_diff_);
4284 priv_->canonical_diff_->priv_->reported_once_ = f;
4285 priv_->reported_once_ = f;
4288 /// Getter for the local category of the current diff tree node.
4290 /// The local category represents the set of categories of a diff
4291 /// node, not taking in account the categories inherited from its
4294 /// @return the local category of the current diff tree node.
4296 diff::get_local_category() const
4297 {return priv_->local_category_;}
4299 /// Getter for the category of the current diff tree node.
4301 /// This category represents the union of the local category and the
4302 /// categories inherited from the children diff nodes.
4304 /// @return the category of the current diff tree node.
4306 diff::get_category() const
4307 {return priv_->category_;}
4309 /// Adds the current diff tree node to an additional set of
4310 /// categories. Note that the categories include thoses inherited
4311 /// from the children nodes of this diff node.
4313 /// @param c a bit-map representing the set of categories to add the
4314 /// current diff tree node to.
4316 /// @return the resulting bit-map representing the categories this
4317 /// current diff tree node belongs to, including those inherited from
4318 /// its children nodes.
4320 diff::add_to_category(diff_category c)
4322 priv_->category_ = priv_->category_ | c;
4323 return priv_->category_;
4326 /// Adds the current diff tree node to the categories resulting from
4327 /// the local changes of the current diff node.
4329 /// @param c a bit-map representing the set of categories to add the
4330 /// current diff tree node to.
4332 /// @return the resulting bit-map representing the categories this
4333 /// current diff tree node belongs to.
4335 diff::add_to_local_category(diff_category c)
4337 priv_->local_category_ = priv_->local_category_ | c;
4338 return priv_->local_category_;
4341 /// Adds the current diff tree node to the categories resulting from
4342 /// the local and inherited changes of the current diff node.
4344 /// @param c a bit-map representing the set of categories to add the
4345 /// current diff tree node to.
4347 diff::add_to_local_and_inherited_categories(diff_category c)
4349 add_to_local_category(c);
4353 /// Remove the current diff tree node from an a existing sef of
4354 /// categories. The categories include those inherited from the
4355 /// children nodes of the current diff node.
4357 /// @param c a bit-map representing the set of categories to add the
4358 /// current diff tree node to.
4360 /// @return the resulting bit-map representing the categories this
4361 /// current diff tree onde belongs to, including the categories
4362 /// inherited from the children nodes of the current diff node.
4364 diff::remove_from_category(diff_category c)
4366 priv_->category_ = priv_->category_ & ~c;
4367 return priv_->category_;
4370 /// Remove the current diff tree node from the categories resulting
4371 /// from the local changes.
4373 /// @param c a bit-map representing the set of categories to add the
4374 /// current diff tree node to.
4376 /// @return the resulting bit-map representing the categories this
4377 /// current diff tree onde belongs to.
4379 diff::remove_from_local_category(diff_category c)
4381 priv_->local_category_ = priv_->local_category_ & ~c;
4382 return priv_->local_category_;
4385 /// Set the category of the current @ref diff node. This category
4386 /// includes the categories inherited from the children nodes of the
4387 /// current diff node.
4389 /// @param c the new category for the current diff node.
4391 diff::set_category(diff_category c)
4392 {priv_->category_ = c;}
4394 /// Set the local category of the current @ref diff node.
4396 /// @param c the new category for the current diff node.
4398 diff::set_local_category(diff_category c)
4399 {priv_->local_category_ = c;}
4401 /// Test if this diff tree node is to be filtered out for reporting
4404 /// The function tests if the categories of the diff tree node are
4405 /// "forbidden" by the context or not.
4407 /// @return true iff the current diff node should NOT be reported.
4409 diff::is_filtered_out() const
4410 {return priv_->is_filtered_out(get_category());}
4412 /// Test if this diff tree node is to be filtered out for reporting
4413 /// purposes, but by considering only the categories that were *NOT*
4414 /// inherited from its children nodes.
4416 /// The function tests if the local categories of the diff tree node
4417 /// are "forbidden" by the context or not.
4419 /// @return true iff the current diff node should NOT be reported,
4420 /// with respect to its local categories.
4422 diff::is_filtered_out_wrt_non_inherited_categories() const
4423 {return priv_->is_filtered_out(get_local_category());}
4425 /// Test if the current diff node has been suppressed by a
4426 /// user-provided suppression specification.
4428 /// @return true if the current diff node has been suppressed by a
4429 /// user-provided suppression list.
4431 diff::is_suppressed() const
4433 const suppressions_type& suppressions = context()->suppressions();
4434 for (suppressions_type::const_iterator i = suppressions.begin();
4435 i != suppressions.end();
4437 if ((*i)->suppresses_diff(this))
4442 /// Test if this diff tree node should be reported.
4444 /// @return true iff the current node should be reported.
4446 diff::to_be_reported() const
4448 if (has_changes() && !is_filtered_out())
4453 /// Test if this diff tree node should be reported when considering
4454 /// the categories that were *NOT* inherited from its children nodes.
4456 /// @return true iff the current node should be reported.
4458 diff::has_local_changes_to_be_reported() const
4460 if (has_local_changes()
4461 && !is_filtered_out_wrt_non_inherited_categories())
4466 /// Get a pretty representation of the current @ref diff node.
4468 /// This is suitable for e.g. emitting debugging traces for the diff
4471 /// @return the pretty representation of the diff node.
4473 diff::get_pretty_representation() const
4475 if (priv_->pretty_representation_.empty())
4476 priv_->pretty_representation_ = "empty_diff";
4477 return priv_->pretty_representation_;
4480 /// Default implementation of the hierachy chaining virtual function.
4482 /// There are several types of diff nodes that have logical children
4483 /// nodes; for instance, a typedef_diff has the diff of the underlying
4484 /// type as a child node. A var_diff has the diff of the types of the
4485 /// variables as a child node, etc.
4487 /// But because the @ref diff base has a generic representation for
4488 /// children nodes of the all the types of @ref diff nodes (regardless
4489 /// of the specific most-derived type of diff node) that one can get
4490 /// using the method diff::children_nodes(), one need to populate that
4491 /// vector of children node.
4493 /// Populating that vector of children node is done by this function;
4494 /// it must be overloaded by each most-derived type of diff node that
4495 /// extends the @ref diff type.
4497 diff::chain_into_hierarchy()
4503 report_size_and_alignment_changes(type_or_decl_base_sptr first,
4504 type_or_decl_base_sptr second,
4505 diff_context_sptr ctxt,
4507 const string& indent,
4510 // <type_diff_base stuff>
4511 class type_diff_base::priv
4514 friend class type_diff_base;
4515 }; // end class type_diff_base
4517 type_diff_base::type_diff_base(type_base_sptr first_subject,
4518 type_base_sptr second_subject,
4519 diff_context_sptr ctxt)
4520 : diff(first_subject, second_subject, ctxt),
4524 type_diff_base::~type_diff_base()
4526 // </type_diff_base stuff>
4528 // <decl_diff_base stuff>
4529 class decl_diff_base::priv
4532 friend class decl_diff_base;
4535 decl_diff_base::decl_diff_base(decl_base_sptr first_subject,
4536 decl_base_sptr second_subject,
4537 diff_context_sptr ctxt)
4538 : diff(first_subject, second_subject, ctxt),
4542 decl_diff_base::~decl_diff_base()
4545 // </decl_diff_base stuff>
4546 // <distinct_diff stuff>
4548 /// The private data structure for @ref distinct_diff.
4549 struct distinct_diff::priv
4551 diff_sptr compatible_child_diff;
4552 };// end struct distinct_diff
4554 /// @return a pretty representation for the @ref distinct_diff node.
4556 distinct_diff::get_pretty_representation() const
4558 if (diff::priv_->pretty_representation_.empty())
4560 std::ostringstream o;
4561 o << "distinct_diff[";
4562 if (first_subject())
4563 o << first_subject()->get_pretty_representation();
4567 if (second_subject())
4568 o << second_subject()->get_pretty_representation() ;
4572 diff::priv_->pretty_representation_ = o.str();
4574 return diff::priv_->pretty_representation_;
4577 /// Populate the vector of children node of the @ref diff base type
4578 /// sub-object of this instance of @distinct_diff.
4580 /// The children nodes can then later be retrieved using
4581 /// diff::children_nodes().
4583 distinct_diff::chain_into_hierarchy()
4585 assert(entities_are_of_distinct_kinds(first(), second()));
4587 if (diff_sptr d = compatible_child_diff())
4588 append_child_node(d);
4591 /// Constructor for @ref distinct_diff.
4593 /// Note that the two entities considered for the diff (and passed in
4594 /// parameter) must be of different kinds.
4596 /// @param first the first entity to consider for the diff.
4598 /// @param second the second entity to consider for the diff.
4600 /// @param ctxt the context of the diff.
4601 distinct_diff::distinct_diff(type_or_decl_base_sptr first,
4602 type_or_decl_base_sptr second,
4603 diff_context_sptr ctxt)
4604 : diff(first, second, ctxt),
4606 {assert(entities_are_of_distinct_kinds(first, second));}
4608 /// Finish building the current instance of @ref distinct_diff.
4610 distinct_diff::finish_diff_type()
4612 if (diff::priv_->finished_)
4615 chain_into_hierarchy();
4616 diff::priv_->finished_ = true;
4619 /// Getter for the first subject of the diff.
4621 /// @return the first subject of the diff.
4622 const type_or_decl_base_sptr
4623 distinct_diff::first() const
4624 {return first_subject();}
4626 /// Getter for the second subject of the diff.
4628 /// @return the second subject of the diff.
4629 const type_or_decl_base_sptr
4630 distinct_diff::second() const
4631 {return second_subject();}
4633 /// Getter for the child diff of this distinct_diff instance.
4635 /// When a distinct_diff has two subjects that are different but
4636 /// compatible, then the distinct_diff instance has a child diff node
4637 /// (named the compatible child diff) that is the diff between the two
4638 /// subjects stripped from their typedefs. Otherwise, the compatible
4639 /// child diff is nul.
4641 /// Note that two diff subjects (that compare different) are
4642 /// considered compatible if stripping typedefs out of them makes them
4643 /// comparing equal.
4645 /// @return the compatible child diff node, if any. Otherwise, null.
4647 distinct_diff::compatible_child_diff() const
4649 if (!priv_->compatible_child_diff)
4651 type_base_sptr fs = strip_typedef(is_type(first())),
4652 ss = strip_typedef(is_type(second()));
4655 && !entities_are_of_distinct_kinds(get_type_declaration(fs),
4656 get_type_declaration(ss)))
4657 priv_->compatible_child_diff = compute_diff(get_type_declaration(fs),
4658 get_type_declaration(ss),
4661 return priv_->compatible_child_diff;
4664 /// Test if the two arguments are of different kind, or that are both
4667 /// @param first the first argument to test for similarity in kind.
4669 /// @param second the second argument to test for similarity in kind.
4671 /// @return true iff the two arguments are of different kind.
4673 distinct_diff::entities_are_of_distinct_kinds(type_or_decl_base_sptr first,
4674 type_or_decl_base_sptr second)
4676 if (!!first != !!second)
4678 if (!first && !second)
4679 // We do consider diffs of two empty decls as a diff of distinct
4682 if (first == second)
4685 return typeid(*first.get()) != typeid(*second.get());
4688 /// @return true if the two subjects of the diff are different, false
4691 distinct_diff::has_changes() const
4692 {return first() != second();}
4694 /// @return true iff the current diff node carries local changes.
4696 distinct_diff::has_local_changes() const
4698 // The changes on a distinct_diff are all local.
4704 /// Emit a report about the current diff instance.
4706 /// @param out the output stream to send the diff report to.
4708 /// @param indent the indentation string to use in the report.
4710 distinct_diff::report(ostream& out, const string& indent) const
4712 if (!to_be_reported())
4715 type_or_decl_base_sptr f = first(), s = second();
4717 string f_repr = f ? f->get_pretty_representation() : "'void'";
4718 string s_repr = s ? s->get_pretty_representation() : "'void'";
4720 diff_sptr diff = compatible_child_diff();
4725 << "entity changed from '" << f_repr
4726 << "' to compatible type '" << s_repr << "'\n";
4731 << "entity changed from '" << f_repr
4732 << "' to '" << s_repr << "'\n";
4735 type_base_sptr fs = strip_typedef(is_type(f)),
4736 ss = strip_typedef(is_type(s));
4738 if (diff_sptr diff = compatible_child_diff())
4739 diff->report(out, indent + " ");
4741 if (report_size_and_alignment_changes(f, s, context(), out, indent,
4742 /*start_with_new_line=*/false))
4746 /// Try to diff entities that are of distinct kinds.
4748 /// @param first the first entity to consider for the diff.
4750 /// @param second the second entity to consider for the diff.
4752 /// @param ctxt the context of the diff.
4754 /// @return a non-null diff if a diff object could be built, null
4757 compute_diff_for_distinct_kinds(const decl_base_sptr first,
4758 const decl_base_sptr second,
4759 diff_context_sptr ctxt)
4761 if (!distinct_diff::entities_are_of_distinct_kinds(first, second))
4762 return distinct_diff_sptr();
4764 distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
4766 ctxt->initialize_canonical_diff(result);
4771 /// </distinct_diff stuff>
4773 /// Try to compute a diff on two instances of DiffType representation.
4775 /// The function template performs the diff if and only if the decl
4776 /// representations are of a DiffType.
4778 /// @tparm DiffType the type of instances to diff.
4780 /// @param first the first representation of decl to consider in the
4781 /// diff computation.
4783 /// @param second the second representation of decl to consider in the
4784 /// diff computation.
4786 /// @param ctxt the diff context to use.
4788 ///@return the diff of the two types @p first and @p second if and
4789 ///only if they represent the parametrized type DiffType. Otherwise,
4790 ///returns a NULL pointer value.
4791 template<typename DiffType>
4793 try_to_diff(const decl_base_sptr first,
4794 const decl_base_sptr second,
4795 diff_context_sptr ctxt)
4797 if (shared_ptr<DiffType> f =
4798 dynamic_pointer_cast<DiffType>(first))
4800 shared_ptr<DiffType> s =
4801 dynamic_pointer_cast<DiffType>(second);
4804 return compute_diff(f, s, ctxt);
4810 /// This is a specialization of @ref try_to_diff() template to diff
4811 /// instances of @ref class_decl.
4813 /// @param first the first representation of decl to consider in the
4814 /// diff computation.
4816 /// @param second the second representation of decl to consider in the
4817 /// diff computation.
4819 /// @param ctxt the diff context to use.
4822 try_to_diff<class_decl>(const decl_base_sptr first,
4823 const decl_base_sptr second,
4824 diff_context_sptr ctxt)
4826 if (class_decl_sptr f =
4827 dynamic_pointer_cast<class_decl>(first))
4829 class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
4833 if (f->get_is_declaration_only())
4835 class_decl_sptr f2 = f->get_definition_of_declaration();
4839 if (s->get_is_declaration_only())
4841 class_decl_sptr s2 = s->get_definition_of_declaration();
4845 return compute_diff(f, s, ctxt);
4850 /// Try to diff entities that are of distinct kinds.
4852 /// @param first the first entity to consider for the diff.
4854 /// @param second the second entity to consider for the diff.
4856 /// @param ctxt the context of the diff.
4858 /// @return a non-null diff if a diff object could be built, null
4861 try_to_diff_distinct_kinds(const decl_base_sptr first,
4862 const decl_base_sptr second,
4863 diff_context_sptr ctxt)
4864 {return compute_diff_for_distinct_kinds(first, second, ctxt);}
4866 /// Compute the difference between two types.
4868 /// The function considers every possible types known to libabigail
4869 /// and runs the appropriate diff function on them.
4871 /// Whenever a new kind of type decl is supported by abigail, if we
4872 /// want to be able to diff two instances of it, we need to update
4873 /// this function to support it.
4875 /// @param first the first type decl to consider for the diff
4877 /// @param second the second type decl to consider for the diff.
4879 /// @param ctxt the diff context to use.
4881 /// @return the resulting diff. It's a pointer to a descendent of
4882 /// abigail::comparison::diff.
4884 compute_diff_for_types(const decl_base_sptr first,
4885 const decl_base_sptr second,
4886 diff_context_sptr ctxt)
4890 const decl_base_sptr f = first;
4891 const decl_base_sptr s = second;
4893 ((d = try_to_diff<type_decl>(f, s, ctxt))
4894 ||(d = try_to_diff<enum_type_decl>(f, s, ctxt))
4895 ||(d = try_to_diff<class_decl>(f, s,ctxt))
4896 ||(d = try_to_diff<pointer_type_def>(f, s, ctxt))
4897 ||(d = try_to_diff<reference_type_def>(f, s, ctxt))
4898 ||(d = try_to_diff<array_type_def>(f, s, ctxt))
4899 ||(d = try_to_diff<qualified_type_def>(f, s, ctxt))
4900 ||(d = try_to_diff<typedef_decl>(f, s, ctxt))
4901 ||(d = try_to_diff<function_type>(f, s, ctxt))
4902 ||(d = try_to_diff_distinct_kinds(f, s, ctxt)));
4910 operator|(diff_category c1, diff_category c2)
4911 {return static_cast<diff_category>(static_cast<unsigned>(c1)
4912 | static_cast<unsigned>(c2));}
4915 operator|=(diff_category& c1, diff_category c2)
4922 operator&=(diff_category& c1, diff_category c2)
4929 operator^(diff_category c1, diff_category c2)
4930 {return static_cast<diff_category>(static_cast<unsigned>(c1)
4931 ^ static_cast<unsigned>(c2));}
4934 operator&(diff_category c1, diff_category c2)
4935 {return static_cast<diff_category>(static_cast<unsigned>(c1)
4936 & static_cast<unsigned>(c2));}
4939 operator~(diff_category c)
4940 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
4942 /// Serialize an instance of @ref diff_category to an output stream.
4944 /// @param o the output stream to serialize @p c to.
4946 /// @param c the instance of diff_category to serialize.
4948 /// @return the output stream to serialize @p c to.
4950 operator<<(ostream& o, diff_category c)
4952 bool emitted_a_category = false;
4954 if (c == NO_CHANGE_CATEGORY)
4956 o << "NO_CHANGE_CATEGORY";
4957 emitted_a_category = true;
4960 if (c & ACCESS_CHANGE_CATEGORY)
4962 if (emitted_a_category)
4964 o << "ACCESS_CHANGE_CATEGORY";
4965 emitted_a_category |= true;
4968 if (c & COMPATIBLE_TYPE_CHANGE_CATEGORY)
4970 if (emitted_a_category)
4972 o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
4973 emitted_a_category |= true;
4976 if (c & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
4978 if (emitted_a_category)
4980 o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
4981 emitted_a_category |= true;
4984 if (c & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
4986 if (emitted_a_category)
4988 o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
4989 emitted_a_category |= true;
4992 if (c & STATIC_DATA_MEMBER_CHANGE_CATEGORY)
4994 if (emitted_a_category)
4996 o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
4997 emitted_a_category |= true;
4999 else if (c & HARMLESS_ENUM_CHANGE_CATEGORY)
5001 if (emitted_a_category)
5003 o << "HARMLESS_ENUM_CHANGE_CATEGORY";
5004 emitted_a_category |= true;
5007 if (c & HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY)
5009 if (emitted_a_category)
5011 o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY";
5012 emitted_a_category |= true;
5015 if (c & SIZE_OR_OFFSET_CHANGE_CATEGORY)
5017 if (emitted_a_category)
5019 o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
5020 emitted_a_category |= true;
5023 if (c & VIRTUAL_MEMBER_CHANGE_CATEGORY)
5025 if (emitted_a_category)
5027 o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
5028 emitted_a_category |= true;
5031 if (c & REDUNDANT_CATEGORY)
5033 if (emitted_a_category)
5035 o << "REDUNDANT_CATEGORY";
5036 emitted_a_category |= true;
5039 if (c & SUPPRESSED_CATEGORY)
5041 if (emitted_a_category)
5043 o << "SUPPRESSED_CATEGORY";
5044 emitted_a_category |= true;
5050 /// Compute the difference between two types.
5052 /// The function considers every possible types known to libabigail
5053 /// and runs the appropriate diff function on them.
5055 /// @param first the first construct to consider for the diff
5057 /// @param second the second construct to consider for the diff.
5059 /// @param ctxt the diff context to use.
5061 /// @return the resulting diff. It's a pointer to a descendent of
5062 /// abigail::comparison::diff.
5064 compute_diff_for_types(const type_base_sptr first,
5065 const type_base_sptr second,
5066 diff_context_sptr ctxt)
5070 decl_base_sptr f = dynamic_pointer_cast<decl_base>(first);
5071 decl_base_sptr s = dynamic_pointer_cast<decl_base>(second);
5073 d = compute_diff_for_types(f, s, ctxt);
5078 /// Compute the difference between two decls.
5080 /// The function consider every possible decls known to libabigail and
5081 /// runs the appropriate diff function on them.
5083 /// Whenever a new kind of non-type decl is supported by abigail, if
5084 /// we want to be able to diff two instances of it, we need to update
5085 /// this function to support it.
5087 /// @param first the first decl to consider for the diff
5089 /// @param second the second decl to consider for the diff.
5091 /// @param ctxt the diff context to use.
5093 /// @return the resulting diff.
5095 compute_diff_for_decls(const decl_base_sptr first,
5096 const decl_base_sptr second,
5097 diff_context_sptr ctxt)
5102 ((d = try_to_diff<function_decl>(first, second, ctxt))
5103 || (d = try_to_diff<var_decl>(first, second, ctxt))
5104 || (d = try_to_diff_distinct_kinds(first, second, ctxt)));
5111 /// Compute the difference between two decls. The decls can represent
5112 /// either type declarations, or non-type declaration.
5114 /// @param first the first decl to consider.
5116 /// @param second the second decl to consider.
5118 /// @param ctxt the diff context to use.
5120 /// @return the resulting diff, or NULL if the diff could not be
5123 compute_diff(const decl_base_sptr first,
5124 const decl_base_sptr second,
5125 diff_context_sptr ctxt)
5127 if (!first || !second)
5131 if (is_type(first) && is_type(second))
5132 d = compute_diff_for_types(first, second, ctxt);
5134 d = compute_diff_for_decls(first, second, ctxt);
5139 /// Compute the difference between two types.
5141 /// @param first the first type to consider.
5143 /// @param second the second type to consider.
5145 /// @param ctxt the diff context to use.
5147 /// @return the resulting diff, or NULL if the diff couldn't be
5150 compute_diff(const type_base_sptr first,
5151 const type_base_sptr second,
5152 diff_context_sptr ctxt)
5154 assert(first && second);
5156 decl_base_sptr f = get_type_declaration(first),
5157 s = get_type_declaration(second);
5158 diff_sptr d = compute_diff_for_types(f,s, ctxt);
5163 /// Get a copy of the pretty representation of a diff node.
5165 /// @param d the diff node to consider.
5167 /// @return the pretty representation string.
5169 get_pretty_representation(diff* d)
5173 string prefix= "diff of ";
5174 return prefix + get_pretty_representation(d->first_subject());
5178 maybe_report_diff_for_member(decl_base_sptr decl1,
5179 decl_base_sptr decl2,
5180 diff_context_sptr ctxt,
5182 const string& indent);
5184 /// Stream a string representation for a member function.
5186 /// @param ctxt the current diff context.
5188 /// @param mem_fn the member function to stream
5190 /// @param out the output stream to send the representation to
5192 represent(diff_context& ctxt,
5193 class_decl::method_decl_sptr mem_fn,
5196 if (!mem_fn || !is_member_function(mem_fn))
5199 class_decl::method_decl_sptr meth =
5200 dynamic_pointer_cast<class_decl::method_decl>(mem_fn);
5203 out << "'" << mem_fn->get_pretty_representation() << "'";
5204 if (get_member_function_is_virtual(mem_fn))
5205 out << ", virtual at voffset "
5206 << get_member_function_vtable_offset(mem_fn)
5208 << meth->get_type()->get_class_type()->get_virtual_mem_fns().size();
5210 if (ctxt.show_linkage_names()
5211 && (mem_fn->get_symbol()))
5214 << mem_fn->get_symbol()->get_id_string()
5220 /// Stream a string representation for a data member.
5222 /// @param d the data member to stream
5224 /// @param out the output stream to send the representation to
5226 represent_data_member(var_decl_sptr d, ostream& out)
5228 if (!is_data_member(d)
5229 || (!get_member_is_static(d) && !get_data_member_is_laid_out(d)))
5232 out << "'" << d->get_pretty_representation() << "'";
5233 if (!get_member_is_static(d))
5234 out << ", at offset "
5235 << get_data_member_offset(d)
5239 /// Represent the changes carried by an instance of @ref var_diff that
5240 /// represent a difference between two class data members.
5242 /// @param diff diff the diff node to represent.
5244 /// @param ctxt the diff context to use.
5246 /// @param out the output stream to send the representation to.
5248 /// @param indent the indentation string to use for the change report.
5250 represent(var_diff_sptr diff,
5251 diff_context_sptr ctxt,
5253 const string& indent = "")
5255 if (!diff->to_be_reported())
5258 var_decl_sptr o = diff->first_var();
5259 var_decl_sptr n = diff->second_var();
5261 bool emitted = false;
5262 bool begin_with_and = false;
5263 string name1 = o->get_qualified_name();
5264 string name2 = n->get_qualified_name();
5265 string pretty_representation = o->get_pretty_representation();
5267 if (diff_sptr d = diff->type_diff())
5269 if (d->to_be_reported())
5272 << "type of '" << pretty_representation << "' changed:\n";
5273 if (d->currently_reporting())
5274 out << indent << " details are being reported\n";
5275 else if (d->reported_once())
5276 out << indent << " details were reported earlier\n";
5278 d->report(out, indent + " ");
5279 begin_with_and = true;
5285 if (filtering::has_harmless_name_change(o, n)
5286 && !(ctxt->get_allowed_category()
5287 & HARMLESS_DECL_NAME_CHANGE_CATEGORY))
5295 begin_with_and = false;
5297 out << "name of '" << name1 << "' changed to '" << name2 << "'";
5302 if (get_data_member_is_laid_out(o)
5303 != get_data_member_is_laid_out(n))
5307 out << indent << "and ";
5308 begin_with_and = false;
5311 out << indent << "'" << pretty_representation << "' ";
5314 if (get_data_member_is_laid_out(o))
5315 out << "is no more laid out";
5317 out << "now becomes laid out";
5320 if ((ctxt->get_allowed_category() & SIZE_OR_OFFSET_CHANGE_CATEGORY)
5321 && (get_data_member_offset(o)
5322 != get_data_member_offset(n)))
5326 out << indent << "and ";
5327 begin_with_and = false;
5330 out << indent << "'" << pretty_representation << "' ";
5333 out << "offset changed from "
5334 << get_data_member_offset(o)
5335 << " to " << get_data_member_offset(n)
5339 if (o->get_binding() != n->get_binding())
5343 out << indent << "and ";
5344 begin_with_and = false;
5347 out << indent << "'" << pretty_representation << "' ";
5350 out << "elf binding changed from " << o->get_binding()
5351 << " to " << n->get_binding();
5354 if (o->get_visibility() != n->get_visibility())
5358 out << indent << "and ";
5359 begin_with_and = false;
5362 out << indent << "'" << pretty_representation << "' ";
5365 out << "visibility changed from " << o->get_visibility()
5366 << " to " << n->get_visibility();
5368 if ((ctxt->get_allowed_category() & ACCESS_CHANGE_CATEGORY)
5369 && (get_member_access_specifier(o)
5370 != get_member_access_specifier(n)))
5374 out << indent << "and ";
5375 begin_with_and = false;
5378 out << indent << "'" << pretty_representation << "' ";
5382 out << "access changed from '"
5383 << get_member_access_specifier(o)
5385 << get_member_access_specifier(n) << "'";
5388 if (get_member_is_static(o)
5389 != get_member_is_static(n))
5393 out << indent << "and ";
5394 begin_with_and = false;
5397 out << indent << "'" << pretty_representation << "' ";
5401 if (get_member_is_static(o))
5402 out << "is no more static";
5404 out << "now becomes static";
5408 /// Report the size and alignment changes of a type.
5410 /// @param first the first type to consider.
5412 /// @param second the second type to consider.
5414 /// @param ctxt the content of the current diff.
5416 /// @param out the output stream to report the change to.
5418 /// @param indent the string to use for indentation.
5420 /// @param nl whether to start the first report line with a new line.
5422 /// @return true iff something was reported.
5424 report_size_and_alignment_changes(type_or_decl_base_sptr first,
5425 type_or_decl_base_sptr second,
5426 diff_context_sptr ctxt,
5428 const string& indent,
5431 type_base_sptr f = dynamic_pointer_cast<type_base>(first),
5432 s = dynamic_pointer_cast<type_base>(second);
5438 unsigned fs = f->get_size_in_bits(), ss = s->get_size_in_bits(),
5439 fa = f->get_alignment_in_bits(), sa = s->get_alignment_in_bits();
5440 array_type_def_sptr first_array = is_array_type(is_type(first)),
5441 second_array = is_array_type(is_type(second));
5442 unsigned fdc = first_array ? first_array->get_dimension_count(): 0,
5443 sdc = second_array ? second_array->get_dimension_count(): 0;
5448 if ((ctxt->get_allowed_category() & SIZE_OR_OFFSET_CHANGE_CATEGORY)
5449 && (fs != ss || fdc != sdc))
5451 if (first_array && second_array)
5453 // We are looking at size or alignment changes between two
5455 out << indent << "array type size changed from ";
5456 if (first_array->is_infinite())
5459 out << first_array->get_size_in_bits();
5461 if (second_array->is_infinite())
5464 out << second_array->get_size_in_bits();
5470 << "number of dimensions changed from "
5476 array_type_def::subranges_type::const_iterator i, j;
5477 for (i = first_array->get_subranges().begin(),
5478 j = second_array->get_subranges().begin();
5479 (i != first_array->get_subranges().end()
5480 && j != second_array->get_subranges().end());
5483 if ((*i)->get_length() != (*j)->get_length())
5486 << "array type subrange "
5487 << i - first_array->get_subranges().begin() + 1
5488 << " changed length from ";
5490 if ((*i)->is_infinite())
5493 out << (*i)->get_length();
5497 if ((*j)->is_infinite())
5500 out << (*j)->get_length();
5508 << "type size changed from " << fs << " to " << ss << " bits";
5512 if ((ctxt->get_allowed_category() & SIZE_OR_OFFSET_CHANGE_CATEGORY)
5518 << "type alignment changed from " << fa << " to " << sa << " bits";
5527 /// Report the name, size and alignment changes of a type.
5529 /// @param first the first type to consider.
5531 /// @param second the second type to consider.
5533 /// @param ctxt the content of the current diff.
5535 /// @param out the output stream to report the change to.
5537 /// @param indent the string to use for indentation.
5539 /// @param nl whether to start the first report line with a new line.
5541 /// @return true iff something was reported.
5543 report_name_size_and_alignment_changes(decl_base_sptr first,
5544 decl_base_sptr second,
5545 diff_context_sptr ctxt,
5547 const string& indent,
5550 string fn = first->get_qualified_name(),
5551 sn = second->get_qualified_name();
5555 if (!(ctxt->get_allowed_category() & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
5556 && filtering::has_harmless_name_change(first, second))
5557 // This is a harmless name change. but then
5558 // HARMLESS_DECL_NAME_CHANGE_CATEGORY doesn't seem allowed.
5568 out << "declaration";
5569 out << " name changed from '" << fn << "' to '" << sn << "'";
5574 nl |= report_size_and_alignment_changes(first, second, ctxt,
5579 /// Represent the kind of difference we want report_mem_header() to
5585 subtype_change_kind,
5589 /// Output the header preceding the the report for
5590 /// insertion/deletion/change of a part of a class. This is a
5591 /// subroutine of class_diff::report.
5593 /// @param out the output stream to output the report to.
5595 /// @param number the number of insertion/deletion to refer to in the
5598 /// @param k the kind of diff (insertion/deletion/change) we want the
5599 /// head to introduce.
5601 /// @param section_name the name of the sub-part of the class to
5604 /// @param indent the string to use as indentation prefix in the
5607 report_mem_header(ostream& out,
5609 size_t num_filtered,
5611 const string& section_name,
5612 const string& indent)
5614 size_t net_number = number - num_filtered;
5616 char colon_or_semi_colon = ':';
5621 change = (number > 1) ? "deletions" : "deletion";
5624 change = (number > 1) ? "insertions" : "insertion";
5626 case subtype_change_kind:
5628 change = (number > 1) ? "changes" : "change";
5632 if (net_number == 0)
5634 out << indent << "no " << section_name << " " << change;
5635 colon_or_semi_colon = ';';
5637 else if (net_number == 1)
5638 out << indent << "1 " << section_name << " " << change;
5640 out << indent << net_number << " " << section_name
5644 out << " (" << num_filtered << " filtered)";
5645 out << colon_or_semi_colon << '\n';
5650 /// The internal type for the impl idiom implementation of @ref
5652 struct var_diff::priv
5654 diff_sptr type_diff_;
5655 };//end struct var_diff
5657 /// Populate the vector of children node of the @ref diff base type
5658 /// sub-object of this instance of @ref var_diff.
5660 /// The children node can then later be retrieved using
5661 /// diff::children_node().
5663 var_diff::chain_into_hierarchy()
5664 {append_child_node(type_diff());}
5666 /// @return the pretty representation for this current instance of
5669 var_diff::get_pretty_representation() const
5671 if (diff::priv_->pretty_representation_.empty())
5673 std::ostringstream o;
5675 << first_subject()->get_pretty_representation()
5677 << second_subject()->get_pretty_representation()
5679 diff::priv_->pretty_representation_ = o.str();
5681 return diff::priv_->pretty_representation_;
5683 /// Constructor for @ref var_diff.
5685 /// @param first the first instance of @ref var_decl to consider in
5688 /// @param second the second instance of @ref var_decl to consider in
5691 /// @param type_diff the diff between types of the instances of
5694 /// @param ctxt the diff context to use.
5695 var_diff::var_diff(var_decl_sptr first,
5696 var_decl_sptr second,
5697 diff_sptr type_diff,
5698 diff_context_sptr ctxt)
5699 : decl_diff_base(first, second, ctxt),
5701 {priv_->type_diff_ = type_diff;}
5703 /// Finish building the current instance of @ref var_diff.
5705 var_diff::finish_diff_type()
5707 if (diff::priv_->finished_)
5709 chain_into_hierarchy();
5710 diff::priv_->finished_ = true;
5713 /// Getter for the first @ref var_decl of the diff.
5715 /// @return the first @ref var_decl of the diff.
5717 var_diff::first_var() const
5718 {return dynamic_pointer_cast<var_decl>(first_subject());}
5720 /// Getter for the second @ref var_decl of the diff.
5722 /// @return the second @ref var_decl of the diff.
5724 var_diff::second_var() const
5725 {return dynamic_pointer_cast<var_decl>(second_subject());}
5727 /// Getter for the diff of the types of the instances of @ref
5730 /// @return the diff of the types of the instances of @ref var_decl.
5732 var_diff::type_diff() const
5734 if (!priv_->type_diff_)
5735 priv_->type_diff_ = compute_diff(first_var()->get_type(),
5736 second_var()->get_type(),
5738 return priv_->type_diff_;
5741 /// Return true iff the diff node has a change.
5743 /// @return true iff the diff node has a change.
5745 var_diff::has_changes() const
5747 if (!!first_var() != !!second_var())
5750 if (first_var().get() == second_var().get())
5753 if (first_var()->get_hash() && second_var()->get_hash()
5754 && first_var()->get_hash() != second_var()->get_hash())
5757 return *first_var() != *second_var();
5760 /// @return true iff the current diff node carries local changes.
5762 var_diff::has_local_changes() const
5764 ir::change_kind k = ir::NO_CHANGE_KIND;
5765 if (!equals(*first_var(), *second_var(), &k))
5766 return k & LOCAL_CHANGE_KIND;
5770 /// Report the diff in a serialized form.
5772 /// @param out the stream to serialize the diff to.
5774 /// @param indent the prefix to use for the indentation of this
5777 var_diff::report(ostream& out, const string& indent) const
5779 if (!to_be_reported())
5782 decl_base_sptr first = first_var(), second = second_var();
5783 string n = first->get_pretty_representation();
5785 if (report_name_size_and_alignment_changes(first, second,
5788 /*start_with_new_line=*/false))
5791 maybe_report_diff_for_member(first, second, context(), out, indent);
5793 if (diff_sptr d = type_diff())
5795 if (d->to_be_reported())
5797 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(d, "type");
5798 out << indent << "type of variable changed:\n";
5799 d->report(out, indent + " ");
5804 /// Compute the diff between two instances of @ref var_decl.
5806 /// @param first the first @ref var_decl to consider for the diff.
5808 /// @param second the second @ref var_decl to consider for the diff.
5810 /// @param ctxt the diff context to use.
5812 /// @return the resulting diff between the two @ref var_decl.
5814 compute_diff(const var_decl_sptr first,
5815 const var_decl_sptr second,
5816 diff_context_sptr ctxt)
5818 var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
5819 ctxt->initialize_canonical_diff(d);
5823 // </var_diff stuff>
5825 /// Report the differences in access specifiers and static-ness for
5828 /// @param decl1 the first class member to consider.
5830 /// @param decl2 the second class member to consider.
5832 /// @param out the output stream to send the report to.
5834 /// @param indent the indentation string to use for the report.
5836 /// @return true if something was reported, false otherwise.
5838 maybe_report_diff_for_member(decl_base_sptr decl1,
5839 decl_base_sptr decl2,
5840 diff_context_sptr ctxt,
5842 const string& indent)
5845 bool reported = false;
5846 if (!is_member_decl(decl1) || !is_member_decl(decl2))
5849 string decl1_repr = decl1->get_pretty_representation(),
5850 decl2_repr = decl2->get_pretty_representation();
5852 if (get_member_is_static(decl1) != get_member_is_static(decl2))
5854 bool lost = get_member_is_static(decl1);
5855 out << indent << "'" << decl1_repr << "' ";
5857 out << "became non-static";
5859 out << "became static";
5863 if ((ctxt->get_allowed_category() & ACCESS_CHANGE_CATEGORY)
5864 && (get_member_access_specifier(decl1)
5865 != get_member_access_specifier(decl2)))
5867 out << indent << "'" << decl1_repr << "' access changed from '"
5868 << get_member_access_specifier(decl1)
5870 << get_member_access_specifier(decl2)
5877 // <pointer_type_def stuff>
5878 struct pointer_diff::priv
5880 diff_sptr underlying_type_diff_;
5883 : underlying_type_diff_(ud)
5885 };//end struct pointer_diff::priv
5888 /// Populate the vector of children node of the @ref diff base type
5889 /// sub-object of this instance of @ref pointer_diff.
5891 /// The children node can then later be retrieved using
5892 /// diff::children_node().
5894 pointer_diff::chain_into_hierarchy()
5895 {append_child_node(underlying_type_diff());}
5897 /// Constructor for a pointer_diff.
5899 /// @param first the first pointer to consider for the diff.
5901 /// @param second the secon pointer to consider for the diff.
5903 /// @param ctxt the diff context to use.
5904 pointer_diff::pointer_diff(pointer_type_def_sptr first,
5905 pointer_type_def_sptr second,
5906 diff_sptr underlying,
5907 diff_context_sptr ctxt)
5908 : type_diff_base(first, second, ctxt),
5909 priv_(new priv(underlying))
5912 /// Finish building the current instance of @ref pointer_diff.
5914 pointer_diff::finish_diff_type()
5916 if (diff::priv_->finished_)
5918 chain_into_hierarchy();
5919 diff::priv_->finished_ = true;
5922 /// Getter for the first subject of a pointer diff
5924 /// @return the first pointer considered in this pointer diff.
5925 const pointer_type_def_sptr
5926 pointer_diff::first_pointer() const
5927 {return dynamic_pointer_cast<pointer_type_def>(first_subject());}
5929 /// Getter for the second subject of a pointer diff
5931 /// @return the second pointer considered in this pointer diff.
5932 const pointer_type_def_sptr
5933 pointer_diff::second_pointer() const
5934 {return dynamic_pointer_cast<pointer_type_def>(second_subject());}
5936 /// @return the pretty represenation for the current instance of @ref
5939 pointer_diff::get_pretty_representation() const
5941 if (diff::priv_->pretty_representation_.empty())
5943 std::ostringstream o;
5944 o << "pointer_diff["
5945 << first_subject()->get_pretty_representation()
5947 << second_subject()->get_pretty_representation()
5949 diff::priv_->pretty_representation_ = o.str();
5951 return diff::priv_->pretty_representation_;
5954 /// Return true iff the current diff node carries a change.
5956 /// @return true iff the current diff node carries a change.
5958 pointer_diff::has_changes() const
5960 return underlying_type_diff()
5961 ? underlying_type_diff()->has_changes()
5965 /// @return true iff the current diff node carries local changes.
5967 pointer_diff::has_local_changes() const
5969 ir::change_kind k = ir::NO_CHANGE_KIND;
5970 if (!equals(*first_pointer(), *second_pointer(), &k))
5971 return k & LOCAL_CHANGE_KIND;
5975 /// Getter for the diff between the pointed-to types of the pointers
5978 /// @return the diff between the pointed-to types.
5980 pointer_diff::underlying_type_diff() const
5981 {return priv_->underlying_type_diff_;}
5983 /// Setter for the diff between the pointed-to types of the pointers
5986 /// @param d the new diff between the pointed-to types of the pointers
5989 pointer_diff::underlying_type_diff(const diff_sptr d)
5990 {priv_->underlying_type_diff_ = d;}
5992 /// Report the diff in a serialized form.
5994 /// @param out the stream to serialize the diff to.
5996 /// @param indent the prefix to use for the indentation of this
5999 pointer_diff::report(ostream& out, const string& indent) const
6001 if (!to_be_reported())
6004 if (diff_sptr d = underlying_type_diff())
6006 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(d, "pointed to type");
6007 string repr = d->first_subject()
6008 ? d->first_subject()->get_pretty_representation()
6012 << "in pointed to type '" << repr << "':\n";
6013 d->report(out, indent + " ");
6017 /// Compute the diff between between two pointers.
6019 /// @param first the pointer to consider for the diff.
6021 /// @param second the pointer to consider for the diff.
6023 /// @return the resulting diff between the two pointers.
6025 /// @param ctxt the diff context to use.
6027 compute_diff(pointer_type_def_sptr first,
6028 pointer_type_def_sptr second,
6029 diff_context_sptr ctxt)
6031 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
6032 second->get_pointed_to_type(),
6034 pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
6035 ctxt->initialize_canonical_diff(result);
6040 // </pointer_type_def>
6043 struct array_diff::priv
6045 /// The diff between the two array element types.
6046 diff_sptr element_type_diff_;
6048 priv(diff_sptr element_type_diff)
6049 : element_type_diff_(element_type_diff)
6051 };//end struct array_diff::priv
6053 /// Populate the vector of children node of the @ref diff base type
6054 /// sub-object of this instance of @ref array_diff.
6056 /// The children node can then later be retrieved using
6057 /// diff::children_node().
6059 array_diff::chain_into_hierarchy()
6060 {append_child_node(element_type_diff());}
6062 /// Constructor for array_diff
6064 /// @param first the first array_type of the diff.
6066 /// @param second the second array_type of the diff.
6068 /// @param element_type_diff the diff between the two array element
6071 /// @param ctxt the diff context to use.
6072 array_diff::array_diff(const array_type_def_sptr first,
6073 const array_type_def_sptr second,
6074 diff_sptr element_type_diff,
6075 diff_context_sptr ctxt)
6076 : type_diff_base(first, second, ctxt),
6077 priv_(new priv(element_type_diff))
6080 /// Finish building the current instance of @ref array_diff.
6082 array_diff::finish_diff_type()
6084 if (diff::priv_->finished_)
6086 chain_into_hierarchy();
6087 diff::priv_->finished_ = true;
6090 /// Getter for the first array of the diff.
6092 /// @return the first array of the diff.
6093 const array_type_def_sptr
6094 array_diff::first_array() const
6095 {return dynamic_pointer_cast<array_type_def>(first_subject());}
6097 /// Getter for the second array of the diff.
6099 /// @return for the second array of the diff.
6100 const array_type_def_sptr
6101 array_diff::second_array() const
6102 {return dynamic_pointer_cast<array_type_def>(second_subject());}
6104 /// Getter for the diff between the two types of array elements.
6106 /// @return the diff between the two types of array elements.
6108 array_diff::element_type_diff() const
6109 {return priv_->element_type_diff_;}
6111 /// Setter for the diff between the two array element types.
6113 /// @param d the new diff betweend the two array element types.
6115 array_diff::element_type_diff(diff_sptr d)
6116 {priv_->element_type_diff_ = d;}
6118 /// @return the pretty representation for the current instance of @ref
6121 array_diff::get_pretty_representation() const
6123 if (diff::priv_->pretty_representation_.empty())
6125 std::ostringstream o;
6127 << first_subject()->get_pretty_representation()
6129 << second_subject()->get_pretty_representation()
6131 diff::priv_->pretty_representation_ = o.str();
6133 return diff::priv_->pretty_representation_;
6136 /// Return true iff the current diff node carries a change.
6138 /// @return true iff the current diff node carries a change.
6140 array_diff::has_changes() const
6144 // the array element types match check for differing dimensions
6147 f = dynamic_pointer_cast<array_type_def>(first_subject()),
6148 s = dynamic_pointer_cast<array_type_def>(second_subject());
6150 if (f->get_name() != s->get_name())
6152 if (f->get_size_in_bits() != s->get_size_in_bits())
6154 if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
6157 l |= element_type_diff()
6158 ? element_type_diff()->has_changes()
6164 /// @return true iff the current diff node carries local changes.
6166 array_diff::has_local_changes() const
6168 ir::change_kind k = ir::NO_CHANGE_KIND;
6169 if (!equals(*first_array(), *second_array(), &k))
6170 return k & LOCAL_CHANGE_KIND;
6174 /// Report the diff in a serialized form.
6176 /// @param out the output stream to serialize the dif to.
6178 /// @param indent the string to use for indenting the report.
6180 array_diff::report(ostream& out, const string& indent) const
6182 if (!to_be_reported())
6185 string name = first_array()->get_pretty_representation();
6186 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(first_array(),
6190 diff_sptr d = element_type_diff();
6191 if (d->to_be_reported())
6193 string fn = ir::get_pretty_representation(is_type(d->first_subject()));
6194 // report array element type changes
6195 out << indent << "array element type '"
6196 << fn << "' changed: \n";
6197 d->report(out, indent + " ");
6200 report_name_size_and_alignment_changes(first_array(),
6204 /*new line=*/false);
6207 /// Compute the diff between two arrays.
6209 /// @param first the first array to consider for the diff.
6211 /// @param second the second array to consider for the diff.
6213 /// @param ctxt the diff context to use.
6215 compute_diff(array_type_def_sptr first,
6216 array_type_def_sptr second,
6217 diff_context_sptr ctxt)
6219 diff_sptr d = compute_diff_for_types(first->get_element_type(),
6220 second->get_element_type(),
6222 array_diff_sptr result(new array_diff(first, second, d, ctxt));
6223 ctxt->initialize_canonical_diff(result);
6226 // </array_type_def>
6228 // <reference_type_def>
6229 struct reference_diff::priv
6231 diff_sptr underlying_type_diff_;
6232 priv(diff_sptr underlying)
6233 : underlying_type_diff_(underlying)
6235 };//end struct reference_diff::priv
6237 /// Populate the vector of children node of the @ref diff base type
6238 /// sub-object of this instance of @ref reference_diff.
6240 /// The children node can then later be retrieved using
6241 /// diff::children_node().
6243 reference_diff::chain_into_hierarchy()
6244 {append_child_node(underlying_type_diff());}
6246 /// Constructor for reference_diff
6248 /// @param first the first reference_type of the diff.
6250 /// @param second the second reference_type of the diff.
6252 /// @param ctxt the diff context to use.
6253 reference_diff::reference_diff(const reference_type_def_sptr first,
6254 const reference_type_def_sptr second,
6255 diff_sptr underlying,
6256 diff_context_sptr ctxt)
6257 : type_diff_base(first, second, ctxt),
6258 priv_(new priv(underlying))
6261 /// Finish building the current instance of @ref reference_diff.
6263 reference_diff::finish_diff_type()
6265 if (diff::priv_->finished_)
6267 chain_into_hierarchy();
6268 diff::priv_->finished_ = true;
6271 /// Getter for the first reference of the diff.
6273 /// @return the first reference of the diff.
6274 reference_type_def_sptr
6275 reference_diff::first_reference() const
6276 {return dynamic_pointer_cast<reference_type_def>(first_subject());}
6278 /// Getter for the second reference of the diff.
6280 /// @return for the second reference of the diff.
6281 reference_type_def_sptr
6282 reference_diff::second_reference() const
6283 {return dynamic_pointer_cast<reference_type_def>(second_subject());}
6286 /// Getter for the diff between the two referred-to types.
6288 /// @return the diff between the two referred-to types.
6290 reference_diff::underlying_type_diff() const
6291 {return priv_->underlying_type_diff_;}
6293 /// Setter for the diff between the two referred-to types.
6295 /// @param d the new diff betweend the two referred-to types.
6297 reference_diff::underlying_type_diff(diff_sptr d)
6299 priv_->underlying_type_diff_ = d;
6300 return priv_->underlying_type_diff_;
6303 /// @return the pretty representation for the current instance of @ref
6306 reference_diff::get_pretty_representation() const
6308 if (diff::priv_->pretty_representation_.empty())
6310 std::ostringstream o;
6311 o << "reference_diff["
6312 << first_subject()->get_pretty_representation()
6314 << second_subject()->get_pretty_representation()
6316 diff::priv_->pretty_representation_ = o.str();
6318 return diff::priv_->pretty_representation_;
6321 /// Return true iff the current diff node carries a change.
6323 /// @return true iff the current diff node carries a change.
6325 reference_diff::has_changes() const
6327 return underlying_type_diff()
6328 ? underlying_type_diff()->has_changes()
6332 /// @return true iff the current diff node carries local changes.
6334 reference_diff::has_local_changes() const
6336 ir::change_kind k = ir::NO_CHANGE_KIND;
6337 if (!equals(*first_reference(), *second_reference(), &k))
6338 return k & LOCAL_CHANGE_KIND;
6342 /// Report the diff in a serialized form.
6344 /// @param out the output stream to serialize the dif to.
6346 /// @param indent the string to use for indenting the report.
6348 reference_diff::report(ostream& out, const string& indent) const
6350 if (!to_be_reported())
6353 if (diff_sptr d = underlying_type_diff())
6355 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(d, "referenced type");
6357 << "in referenced type '"
6358 << d->first_subject()->get_pretty_representation()
6360 d->report(out, indent + " ");
6364 /// Compute the diff between two references.
6366 /// @param first the first reference to consider for the diff.
6368 /// @param second the second reference to consider for the diff.
6370 /// @param ctxt the diff context to use.
6372 compute_diff(reference_type_def_sptr first,
6373 reference_type_def_sptr second,
6374 diff_context_sptr ctxt)
6376 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
6377 second->get_pointed_to_type(),
6379 reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
6380 ctxt->initialize_canonical_diff(result);
6383 // </reference_type_def>
6385 // <qualified_type_diff stuff>
6387 struct qualified_type_diff::priv
6389 diff_sptr underlying_type_diff;
6390 mutable diff_sptr leaf_underlying_type_diff;
6392 priv(diff_sptr underlying)
6393 : underlying_type_diff(underlying)
6395 };// end struct qualified_type_diff::priv
6397 /// Populate the vector of children node of the @ref diff base type
6398 /// sub-object of this instance of @ref qualified_type_diff.
6400 /// The children node can then later be retrieved using
6401 /// diff::children_node().
6403 qualified_type_diff::chain_into_hierarchy()
6404 {append_child_node(leaf_underlying_type_diff());}
6406 /// Constructor for qualified_type_diff.
6408 /// @param first the first qualified type of the diff.
6410 /// @param second the second qualified type of the diff.
6412 /// @param ctxt the diff context to use.
6413 qualified_type_diff::qualified_type_diff(qualified_type_def_sptr first,
6414 qualified_type_def_sptr second,
6416 diff_context_sptr ctxt)
6417 : type_diff_base(first, second, ctxt),
6418 priv_(new priv(under))
6421 /// Finish building the current instance of @ref qualified_type_diff.
6423 qualified_type_diff::finish_diff_type()
6425 if (diff::priv_->finished_)
6427 chain_into_hierarchy();
6428 diff::priv_->finished_ = true;
6431 /// Getter for the first qualified type of the diff.
6433 /// @return the first qualified type of the diff.
6434 const qualified_type_def_sptr
6435 qualified_type_diff::first_qualified_type() const
6436 {return dynamic_pointer_cast<qualified_type_def>(first_subject());}
6438 /// Getter for the second qualified type of the diff.
6440 /// @return the second qualified type of the diff.
6441 const qualified_type_def_sptr
6442 qualified_type_diff::second_qualified_type() const
6443 {return dynamic_pointer_cast<qualified_type_def>(second_subject());}
6445 /// Getter for the diff between the underlying types of the two
6446 /// qualified types.
6448 /// @return the diff between the underlying types of the two qualified
6451 qualified_type_diff::underlying_type_diff() const
6452 {return priv_->underlying_type_diff;}
6454 /// Getter for the diff between the most underlying non-qualified
6455 /// types of two qualified types.
6457 /// @return the diff between the most underlying non-qualified types
6458 /// of two qualified types.
6460 qualified_type_diff::leaf_underlying_type_diff() const
6462 if (!priv_->leaf_underlying_type_diff)
6463 priv_->leaf_underlying_type_diff
6464 = compute_diff_for_types(get_leaf_type(first_qualified_type()),
6465 get_leaf_type(second_qualified_type()),
6468 return priv_->leaf_underlying_type_diff;
6471 /// Setter for the diff between the underlying types of the two
6472 /// qualified types.
6474 /// @return the diff between the underlying types of the two qualified
6477 qualified_type_diff::underlying_type_diff(const diff_sptr d)
6478 {priv_->underlying_type_diff = d;}
6480 /// @return the pretty representation of the current instance of @ref
6481 /// qualified_type_diff.
6483 qualified_type_diff::get_pretty_representation() const
6485 if (diff::priv_->pretty_representation_.empty())
6487 std::ostringstream o;
6488 o << "qualified_type_diff["
6489 << first_subject()->get_pretty_representation()
6491 << second_subject()->get_pretty_representation()
6493 diff::priv_->pretty_representation_ = o.str();
6495 return diff::priv_->pretty_representation_;
6498 /// Return true iff the current diff node carries a change.
6500 /// @return true iff the current diff node carries a change.
6502 qualified_type_diff::has_changes() const
6505 char fcv = first_qualified_type()->get_cv_quals(),
6506 scv = second_qualified_type()->get_cv_quals();
6510 if ((fcv & qualified_type_def::CV_CONST)
6511 != (scv & qualified_type_def::CV_CONST))
6513 if ((fcv & qualified_type_def::CV_VOLATILE)
6514 != (scv & qualified_type_def::CV_RESTRICT))
6516 if ((fcv & qualified_type_def::CV_RESTRICT)
6517 != (scv & qualified_type_def::CV_RESTRICT))
6521 return (underlying_type_diff()
6522 ? underlying_type_diff()->has_changes() || l
6526 /// @return true iff the current diff node carries local changes.
6528 qualified_type_diff::has_local_changes() const
6530 ir::change_kind k = ir::NO_CHANGE_KIND;
6531 if (!equals(*first_qualified_type(), *second_qualified_type(), &k))
6532 return k & LOCAL_CHANGE_KIND;
6536 /// Return the first underlying type that is not a qualified type.
6537 /// @param t the qualified type to consider.
6539 /// @return the first underlying type that is not a qualified type, or
6540 /// NULL if t is NULL.
6541 static type_base_sptr
6542 get_leaf_type(qualified_type_def_sptr t)
6545 return type_base_sptr();
6547 type_base_sptr ut = t->get_underlying_type();
6548 qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
6552 return get_leaf_type(qut);
6555 /// Report the diff in a serialized form.
6557 /// @param out the output stream to serialize to.
6559 /// @param indent the string to use to indent the lines of the report.
6561 qualified_type_diff::report(ostream& out, const string& indent) const
6563 if (!to_be_reported())
6566 string fname = first_qualified_type()->get_pretty_representation(),
6567 sname = second_qualified_type()->get_pretty_representation();
6569 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(first_qualified_type(),
6570 second_qualified_type());
6574 out << indent << "'" << fname << "' changed to '" << sname << "'\n";
6578 diff_sptr d = leaf_underlying_type_diff();
6580 assert(d->to_be_reported());
6581 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(d,
6585 string fltname = d->first_subject()->get_pretty_representation();
6586 out << indent << "in unqualified underlying type '" << fltname << "':\n";
6587 d->report(out, indent + " ");
6590 /// Compute the diff between two qualified types.
6592 /// @param first the first qualified type to consider for the diff.
6594 /// @param second the second qualified type to consider for the diff.
6596 /// @param ctxt the diff context to use.
6597 qualified_type_diff_sptr
6598 compute_diff(const qualified_type_def_sptr first,
6599 const qualified_type_def_sptr second,
6600 diff_context_sptr ctxt)
6602 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
6603 second->get_underlying_type(),
6605 qualified_type_diff_sptr result(new qualified_type_diff(first, second,
6607 ctxt->initialize_canonical_diff(result);
6611 // </qualified_type_diff stuff>
6613 // <enum_diff stuff>
6614 struct enum_diff::priv
6616 diff_sptr underlying_type_diff_;
6617 edit_script enumerators_changes_;
6618 string_enumerator_map deleted_enumerators_;
6619 string_enumerator_map inserted_enumerators_;
6620 string_changed_enumerator_map changed_enumerators_;
6622 priv(diff_sptr underlying)
6623 : underlying_type_diff_(underlying)
6625 };//end struct enum_diff::priv
6627 /// Clear the lookup tables useful for reporting an enum_diff.
6629 /// This function must be updated each time a lookup table is added or
6630 /// removed from the class_diff::priv.
6632 enum_diff::clear_lookup_tables()
6634 priv_->deleted_enumerators_.clear();
6635 priv_->inserted_enumerators_.clear();
6636 priv_->changed_enumerators_.clear();
6639 /// Tests if the lookup tables are empty.
6641 /// @return true if the lookup tables are empty, false otherwise.
6643 enum_diff::lookup_tables_empty() const
6645 return (priv_->deleted_enumerators_.empty()
6646 && priv_->inserted_enumerators_.empty()
6647 && priv_->changed_enumerators_.empty());
6650 /// If the lookup tables are not yet built, walk the differences and
6651 /// fill the lookup tables.
6653 enum_diff::ensure_lookup_tables_populated()
6655 if (!lookup_tables_empty())
6659 edit_script e = priv_->enumerators_changes_;
6661 for (vector<deletion>::const_iterator it = e.deletions().begin();
6662 it != e.deletions().end();
6665 unsigned i = it->index();
6666 const enum_type_decl::enumerator& n =
6667 first_enum()->get_enumerators()[i];
6668 const string& name = n.get_name();
6669 assert(priv_->deleted_enumerators_.find(n.get_name())
6670 == priv_->deleted_enumerators_.end());
6671 priv_->deleted_enumerators_[name] = n;
6674 for (vector<insertion>::const_iterator it = e.insertions().begin();
6675 it != e.insertions().end();
6678 for (vector<unsigned>::const_iterator iit =
6679 it->inserted_indexes().begin();
6680 iit != it->inserted_indexes().end();
6684 const enum_type_decl::enumerator& n =
6685 second_enum()->get_enumerators()[i];
6686 const string& name = n.get_name();
6687 assert(priv_->inserted_enumerators_.find(n.get_name())
6688 == priv_->inserted_enumerators_.end());
6689 string_enumerator_map::const_iterator j =
6690 priv_->deleted_enumerators_.find(name);
6691 if (j == priv_->deleted_enumerators_.end())
6692 priv_->inserted_enumerators_[name] = n;
6696 priv_->changed_enumerators_[j->first] =
6697 std::make_pair(j->second, n);
6698 priv_->deleted_enumerators_.erase(j);
6705 /// Populate the vector of children node of the @ref diff base type
6706 /// sub-object of this instance of @ref enum_diff.
6708 /// The children node can then later be retrieved using
6709 /// diff::children_node().
6711 enum_diff::chain_into_hierarchy()
6712 {append_child_node(underlying_type_diff());}
6714 /// Constructor for enum_diff.
6716 /// @param first the first enum type of the diff.
6718 /// @param second the second enum type of the diff.
6720 /// @param underlying_type_diff the diff of the two underlying types
6721 /// of the two enum types.
6723 /// @param ctxt the diff context to use.
6724 enum_diff::enum_diff(const enum_type_decl_sptr first,
6725 const enum_type_decl_sptr second,
6726 const diff_sptr underlying_type_diff,
6727 const diff_context_sptr ctxt)
6728 : type_diff_base(first, second,ctxt),
6729 priv_(new priv(underlying_type_diff))
6732 /// Finish building the current instance of @ref enum_diff.
6734 enum_diff::finish_diff_type()
6736 if (diff::priv_->finished_)
6738 chain_into_hierarchy();
6739 diff::priv_->finished_ = true;
6742 /// @return the first enum of the diff.
6743 const enum_type_decl_sptr
6744 enum_diff::first_enum() const
6745 {return dynamic_pointer_cast<enum_type_decl>(first_subject());}
6747 /// @return the second enum of the diff.
6748 const enum_type_decl_sptr
6749 enum_diff::second_enum() const
6750 {return dynamic_pointer_cast<enum_type_decl>(second_subject());}
6752 /// @return the diff of the two underlying enum types.
6754 enum_diff::underlying_type_diff() const
6755 {return priv_->underlying_type_diff_;}
6757 /// @return a map of the enumerators that were deleted.
6758 const string_enumerator_map&
6759 enum_diff::deleted_enumerators() const
6760 {return priv_->deleted_enumerators_;}
6762 /// @return a map of the enumerators that were inserted
6763 const string_enumerator_map&
6764 enum_diff::inserted_enumerators() const
6765 {return priv_->inserted_enumerators_;}
6767 /// @return a map the enumerators that were changed
6768 const string_changed_enumerator_map&
6769 enum_diff::changed_enumerators() const
6770 {return priv_->changed_enumerators_;}
6772 /// @return the pretty representation of the current instance of @ref
6775 enum_diff::get_pretty_representation() const
6777 if (diff::priv_->pretty_representation_.empty())
6779 std::ostringstream o;
6781 << first_subject()->get_pretty_representation()
6783 << second_subject()->get_pretty_representation()
6785 diff::priv_->pretty_representation_ = o.str();
6787 return diff::priv_->pretty_representation_;
6790 /// Return true iff the current diff node carries a change.
6792 /// @return true iff the current diff node carries a change.
6794 enum_diff::has_changes() const
6795 {return first_enum() != second_enum();}
6797 /// @return true iff the current diff node carries local changes.
6799 enum_diff::has_local_changes() const
6801 ir::change_kind k = ir::NO_CHANGE_KIND;
6802 if (!equals(*first_enum(), *second_enum(), &k))
6803 return k & LOCAL_CHANGE_KIND;
6807 /// A functor to compare two enumerators based on their value. This
6808 /// implements the "less than" operator.
6809 struct enumerator_value_comp
6812 operator()(const enum_type_decl::enumerator& f,
6813 const enum_type_decl::enumerator& s) const
6814 {return f.get_value() < s.get_value();}
6815 };//end struct enumerator_value_comp
6817 /// Sort a map of enumerators by their value.
6819 /// @param enumerators_map the map to sort.
6821 /// @param sorted the resulting vector of sorted enumerators.
6823 sort_enumerators(const string_enumerator_map& enumerators_map,
6824 enum_type_decl::enumerators& sorted)
6826 for (string_enumerator_map::const_iterator i = enumerators_map.begin();
6827 i != enumerators_map.end();
6829 sorted.push_back(i->second);
6830 enumerator_value_comp comp;
6831 std::sort(sorted.begin(), sorted.end(), comp);
6834 /// A functor to compare two changed enumerators, based on their
6836 struct changed_enumerator_comp
6839 operator()(const changed_enumerator& f,
6840 const changed_enumerator& s) const
6841 {return f.first.get_value() < s.first.get_value();}
6842 };// end struct changed_enumerator_comp.
6844 /// Sort a map of changed enumerators.
6846 /// @param enumerators_map the map to sort.
6848 ///@param output parameter. The resulting sorted enumerators.
6850 sort_changed_enumerators(const string_changed_enumerator_map& enumerators_map,
6851 changed_enumerators_type& sorted)
6853 for (string_changed_enumerator_map::const_iterator i =
6854 enumerators_map.begin();
6855 i != enumerators_map.end();
6857 sorted.push_back(i->second);
6859 changed_enumerator_comp comp;
6860 std::sort(sorted.begin(), sorted.end(), comp);
6863 /// Report the differences between the two enums.
6865 /// @param out the output stream to send the report to.
6867 /// @param indent the string to use for indentation.
6869 enum_diff::report(ostream& out, const string& indent) const
6871 if (!to_be_reported())
6874 string name = first_enum()->get_pretty_representation();
6876 enum_type_decl_sptr first = first_enum(), second = second_enum();
6878 if (report_name_size_and_alignment_changes(first, second, context(),
6880 /*start_with_num_line=*/false))
6882 maybe_report_diff_for_member(first, second, context(), out, indent);
6885 underlying_type_diff()->report(out, indent);
6887 //report deletions/insertions/change of enumerators
6888 unsigned numdels = deleted_enumerators().size();
6889 unsigned numins = inserted_enumerators().size();
6890 unsigned numchanges = changed_enumerators().size();
6894 report_mem_header(out, numdels, 0, del_kind, "enumerator", indent);
6895 enum_type_decl::enumerators sorted_deleted_enumerators;
6896 sort_enumerators(deleted_enumerators(), sorted_deleted_enumerators);
6897 for (enum_type_decl::enumerators::const_iterator i =
6898 sorted_deleted_enumerators.begin();
6899 i != sorted_deleted_enumerators.end();
6902 if (i != sorted_deleted_enumerators.begin())
6906 << i->get_qualified_name()
6915 report_mem_header(out, numins, 0, ins_kind, "enumerator", indent);
6916 enum_type_decl::enumerators sorted_inserted_enumerators;
6917 sort_enumerators(inserted_enumerators(), sorted_inserted_enumerators);
6918 for (enum_type_decl::enumerators::const_iterator i =
6919 sorted_inserted_enumerators.begin();
6920 i != sorted_inserted_enumerators.end();
6923 if (i != sorted_inserted_enumerators.begin())
6927 << i->get_qualified_name()
6936 report_mem_header(out, numchanges, 0, change_kind, "enumerator", indent);
6937 changed_enumerators_type sorted_changed_enumerators;
6938 sort_changed_enumerators(changed_enumerators(),
6939 sorted_changed_enumerators);
6940 for (changed_enumerators_type::const_iterator i =
6941 sorted_changed_enumerators.begin();
6942 i != sorted_changed_enumerators.end();
6945 if (i != sorted_changed_enumerators.begin())
6949 << i->first.get_qualified_name()
6951 << i->first.get_value() << "' to '"
6952 << i->second.get_value() << "'";
6958 /// Compute the set of changes between two instances of @ref
6961 /// @param first a pointer to the first enum_type_decl to consider.
6963 /// @param second a pointer to the second enum_type_decl to consider.
6965 /// @return the resulting diff of the two enums @p first and @p
6968 /// @param ctxt the diff context to use.
6970 compute_diff(const enum_type_decl_sptr first,
6971 const enum_type_decl_sptr second,
6972 diff_context_sptr ctxt)
6974 diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
6975 second->get_underlying_type(),
6977 enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
6979 compute_diff(first->get_enumerators().begin(),
6980 first->get_enumerators().end(),
6981 second->get_enumerators().begin(),
6982 second->get_enumerators().end(),
6983 d->priv_->enumerators_changes_);
6985 d->ensure_lookup_tables_populated();
6987 ctxt->initialize_canonical_diff(d);
6991 // </enum_diff stuff>
6993 //<class_diff stuff>
6995 struct class_diff::priv
6997 edit_script base_changes_;
6998 edit_script member_types_changes_;
6999 edit_script data_members_changes_;
7000 edit_script member_fns_changes_;
7001 edit_script member_fn_tmpls_changes_;
7002 edit_script member_class_tmpls_changes_;
7004 string_base_sptr_map deleted_bases_;
7005 string_base_sptr_map inserted_bases_;
7006 string_base_diff_sptr_map changed_bases_;
7007 base_diff_sptrs_type sorted_changed_bases_;
7008 string_decl_base_sptr_map deleted_member_types_;
7009 string_decl_base_sptr_map inserted_member_types_;
7010 string_diff_sptr_map changed_member_types_;
7011 diff_sptrs_type sorted_changed_member_types_;
7012 string_decl_base_sptr_map deleted_data_members_;
7013 unsigned_decl_base_sptr_map deleted_dm_by_offset_;
7014 string_decl_base_sptr_map inserted_data_members_;
7015 unsigned_decl_base_sptr_map inserted_dm_by_offset_;
7016 // This map contains the data member which sub-type changed.
7017 string_var_diff_sptr_map subtype_changed_dm_;
7018 var_diff_sptrs_type sorted_subtype_changed_dm_;
7019 // This one contains the list of data members changes that can be
7020 // represented as a data member foo that got removed from offset N,
7021 // and a data member bar that got inserted at offset N; IOW, this
7022 // can be translated as data member foo that got changed into data
7023 // member bar at offset N.
7024 unsigned_var_diff_sptr_map changed_dm_;
7025 var_diff_sptrs_type sorted_changed_dm_;
7026 string_member_function_sptr_map deleted_member_functions_;
7027 string_member_function_sptr_map inserted_member_functions_;
7028 string_function_decl_diff_sptr_map changed_member_functions_;
7029 function_decl_diff_sptrs_type sorted_changed_member_functions_;
7030 string_decl_base_sptr_map deleted_member_class_tmpls_;
7031 string_decl_base_sptr_map inserted_member_class_tmpls_;
7032 string_diff_sptr_map changed_member_class_tmpls_;
7033 diff_sptrs_type sorted_changed_member_class_tmpls_;
7035 class_decl::base_spec_sptr
7036 base_has_changed(class_decl::base_spec_sptr) const;
7038 type_or_decl_base_sptr
7039 member_type_has_changed(decl_base_sptr) const;
7042 subtype_changed_dm(decl_base_sptr) const;
7045 member_class_tmpl_has_changed(decl_base_sptr) const;
7048 get_deleted_non_static_data_members_number() const;
7051 get_inserted_non_static_data_members_number() const;
7054 count_filtered_bases();
7057 count_filtered_subtype_changed_dm();
7060 count_filtered_changed_dm();
7063 count_filtered_changed_mem_fns(const diff_context_sptr&);
7066 count_filtered_inserted_mem_fns(const diff_context_sptr&);
7069 count_filtered_deleted_mem_fns(const diff_context_sptr&);
7073 };//end struct class_diff::priv
7075 /// Clear the lookup tables useful for reporting.
7077 /// This function must be updated each time a lookup table is added or
7078 /// removed from the class_diff::priv.
7080 class_diff::clear_lookup_tables(void)
7082 priv_->deleted_bases_.clear();
7083 priv_->inserted_bases_.clear();
7084 priv_->changed_bases_.clear();
7085 priv_->deleted_member_types_.clear();
7086 priv_->inserted_member_types_.clear();
7087 priv_->changed_member_types_.clear();
7088 priv_->deleted_data_members_.clear();
7089 priv_->inserted_data_members_.clear();
7090 priv_->subtype_changed_dm_.clear();
7091 priv_->deleted_member_functions_.clear();
7092 priv_->inserted_member_functions_.clear();
7093 priv_->changed_member_functions_.clear();
7094 priv_->deleted_member_class_tmpls_.clear();
7095 priv_->inserted_member_class_tmpls_.clear();
7096 priv_->changed_member_class_tmpls_.clear();
7099 /// Tests if the lookup tables are empty.
7101 /// @return true if the lookup tables are empty, false otherwise.
7103 class_diff::lookup_tables_empty(void) const
7105 return (priv_->deleted_bases_.empty()
7106 && priv_->inserted_bases_.empty()
7107 && priv_->changed_bases_.empty()
7108 && priv_->deleted_member_types_.empty()
7109 && priv_->inserted_member_types_.empty()
7110 && priv_->changed_member_types_.empty()
7111 && priv_->deleted_data_members_.empty()
7112 && priv_->inserted_data_members_.empty()
7113 && priv_->subtype_changed_dm_.empty()
7114 && priv_->inserted_member_functions_.empty()
7115 && priv_->deleted_member_functions_.empty()
7116 && priv_->changed_member_functions_.empty()
7117 && priv_->deleted_member_class_tmpls_.empty()
7118 && priv_->inserted_member_class_tmpls_.empty()
7119 && priv_->changed_member_class_tmpls_.empty());
7122 /// If the lookup tables are not yet built, walk the differences and
7123 /// fill the lookup tables.
7125 class_diff::ensure_lookup_tables_populated(void) const
7127 if (!lookup_tables_empty())
7131 edit_script& e = priv_->base_changes_;
7133 for (vector<deletion>::const_iterator it = e.deletions().begin();
7134 it != e.deletions().end();
7137 unsigned i = it->index();
7138 class_decl::base_spec_sptr b =
7139 first_class_decl()->get_base_specifiers()[i];
7140 string qname = b->get_base_class()->get_qualified_name();
7141 assert(priv_->deleted_bases_.find(qname)
7142 == priv_->deleted_bases_.end());
7143 priv_->deleted_bases_[qname] = b;
7146 for (vector<insertion>::const_iterator it = e.insertions().begin();
7147 it != e.insertions().end();
7150 for (vector<unsigned>::const_iterator iit =
7151 it->inserted_indexes().begin();
7152 iit != it->inserted_indexes().end();
7156 class_decl::base_spec_sptr b =
7157 second_class_decl()->get_base_specifiers()[i];
7158 string qname = b->get_base_class()->get_qualified_name();
7159 assert(priv_->inserted_bases_.find(qname)
7160 == priv_->inserted_bases_.end());
7161 string_base_sptr_map::const_iterator j =
7162 priv_->deleted_bases_.find(qname);
7163 if (j != priv_->deleted_bases_.end())
7166 priv_->changed_bases_[qname] =
7167 compute_diff(j->second, b, context());
7168 priv_->deleted_bases_.erase(j);
7171 priv_->inserted_bases_[qname] = b;
7176 sort_string_base_diff_sptr_map(priv_->changed_bases_,
7177 priv_->sorted_changed_bases_);
7180 edit_script& e = priv_->member_types_changes_;
7182 for (vector<deletion>::const_iterator it = e.deletions().begin();
7183 it != e.deletions().end();
7186 unsigned i = it->index();
7188 get_type_declaration(first_class_decl()->get_member_types()[i]);
7189 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(d);
7190 if (klass_decl && klass_decl->get_is_declaration_only())
7192 string qname = d->get_qualified_name();
7193 priv_->deleted_member_types_[qname] = d;
7196 for (vector<insertion>::const_iterator it = e.insertions().begin();
7197 it != e.insertions().end();
7200 for (vector<unsigned>::const_iterator iit =
7201 it->inserted_indexes().begin();
7202 iit != it->inserted_indexes().end();
7207 get_type_declaration(second_class_decl()->get_member_types()[i]);
7208 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(d);
7209 if (klass_decl && klass_decl->get_is_declaration_only())
7211 string qname = d->get_qualified_name();
7212 string_decl_base_sptr_map::const_iterator j =
7213 priv_->deleted_member_types_.find(qname);
7214 if (j != priv_->deleted_member_types_.end())
7216 if (*j->second != *d)
7217 priv_->changed_member_types_[qname] =
7218 compute_diff(j->second, d, context());
7220 priv_->deleted_member_types_.erase(j);
7223 priv_->inserted_member_types_[qname] = d;
7229 edit_script& e = priv_->data_members_changes_;
7231 for (vector<deletion>::const_iterator it = e.deletions().begin();
7232 it != e.deletions().end();
7235 unsigned i = it->index();
7236 decl_base_sptr d = first_class_decl()->get_data_members()[i];
7237 string qname = d->get_qualified_name();
7238 assert(priv_->deleted_data_members_.find(qname)
7239 == priv_->deleted_data_members_.end());
7240 priv_->deleted_data_members_[qname] = d;
7243 for (vector<insertion>::const_iterator it = e.insertions().begin();
7244 it != e.insertions().end();
7247 for (vector<unsigned>::const_iterator iit =
7248 it->inserted_indexes().begin();
7249 iit != it->inserted_indexes().end();
7253 decl_base_sptr d = second_class_decl()->get_data_members()[i];
7254 var_decl_sptr dm = dynamic_pointer_cast<var_decl>(d);
7255 string qname = dm->get_qualified_name();
7256 assert(priv_->inserted_data_members_.find(qname)
7257 == priv_->inserted_data_members_.end());
7258 string_decl_base_sptr_map::const_iterator j =
7259 priv_->deleted_data_members_.find(qname);
7260 if (j != priv_->deleted_data_members_.end())
7262 if (*j->second != *d)
7264 var_decl_sptr old_dm =
7265 dynamic_pointer_cast<var_decl>(j->second);
7266 priv_->subtype_changed_dm_[qname]=
7267 compute_diff(old_dm, dm, context());
7269 priv_->deleted_data_members_.erase(j);
7272 priv_->inserted_data_members_[qname] = d;
7276 // Now detect when a data member is deleted from offset N and
7277 // another one is added to offset N. In that case, we want to be
7278 // able to say that the data member at offset N changed.
7279 for (string_decl_base_sptr_map::const_iterator i =
7280 priv_->deleted_data_members_.begin();
7281 i != priv_->deleted_data_members_.end();
7284 unsigned offset = get_data_member_offset(i->second);
7285 priv_->deleted_dm_by_offset_[offset] = i->second;
7288 for (string_decl_base_sptr_map::const_iterator i =
7289 priv_->inserted_data_members_.begin();
7290 i != priv_->inserted_data_members_.end();
7293 unsigned offset = get_data_member_offset(i->second);
7294 priv_->inserted_dm_by_offset_[offset] = i->second;
7297 for (unsigned_decl_base_sptr_map::const_iterator i =
7298 priv_->inserted_dm_by_offset_.begin();
7299 i != priv_->inserted_dm_by_offset_.end();
7302 unsigned_decl_base_sptr_map::const_iterator j =
7303 priv_->deleted_dm_by_offset_.find(i->first);
7304 if (j != priv_->deleted_dm_by_offset_.end())
7306 var_decl_sptr old_dm = dynamic_pointer_cast<var_decl>(j->second);
7307 var_decl_sptr new_dm = dynamic_pointer_cast<var_decl>(i->second);
7308 priv_->changed_dm_[i->first] =
7309 compute_diff(old_dm, new_dm, context());
7313 for (unsigned_var_diff_sptr_map::const_iterator i =
7314 priv_->changed_dm_.begin();
7315 i != priv_->changed_dm_.end();
7318 priv_->deleted_dm_by_offset_.erase(i->first);
7319 priv_->inserted_dm_by_offset_.erase(i->first);
7320 priv_->deleted_data_members_.erase
7321 (i->second->first_var()->get_qualified_name());
7322 priv_->inserted_data_members_.erase
7323 (i->second->second_var()->get_qualified_name());
7326 sort_string_data_member_diff_sptr_map(priv_->subtype_changed_dm_,
7327 priv_->sorted_subtype_changed_dm_);
7328 sort_unsigned_data_member_diff_sptr_map(priv_->changed_dm_,
7329 priv_->sorted_changed_dm_);
7333 edit_script& e = priv_->member_fns_changes_;
7335 for (vector<deletion>::const_iterator it = e.deletions().begin();
7336 it != e.deletions().end();
7339 unsigned i = it->index();
7340 class_decl::method_decl_sptr mem_fn =
7341 first_class_decl()->get_virtual_mem_fns()[i];
7342 string name = mem_fn->get_linkage_name();
7344 name = mem_fn->get_pretty_representation();
7345 assert(!name.empty());
7346 if (priv_->deleted_member_functions_.find(name)
7347 != priv_->deleted_member_functions_.end())
7349 priv_->deleted_member_functions_[name] = mem_fn;
7352 for (vector<insertion>::const_iterator it = e.insertions().begin();
7353 it != e.insertions().end();
7356 for (vector<unsigned>::const_iterator iit =
7357 it->inserted_indexes().begin();
7358 iit != it->inserted_indexes().end();
7363 class_decl::method_decl_sptr mem_fn =
7364 second_class_decl()->get_virtual_mem_fns()[i];
7365 string name = mem_fn->get_linkage_name();
7367 name = mem_fn->get_pretty_representation();
7368 assert(!name.empty());
7369 if (priv_->inserted_member_functions_.find(name)
7370 != priv_->inserted_member_functions_.end())
7372 string_member_function_sptr_map::const_iterator j =
7373 priv_->deleted_member_functions_.find(name);
7375 if (j != priv_->deleted_member_functions_.end())
7377 if (*j->second != *mem_fn)
7378 priv_->changed_member_functions_[name] =
7379 compute_diff(static_pointer_cast<function_decl>(j->second),
7380 static_pointer_cast<function_decl>(mem_fn),
7382 priv_->deleted_member_functions_.erase(j);
7385 priv_->inserted_member_functions_[name] = mem_fn;
7389 // Now walk the allegedly deleted member functions; check if their
7390 // underlying symbols are deleted as well; otherwise, consider
7391 // that the member function in question hasn't been deleted.
7393 vector<string> to_delete;
7394 corpus_sptr f = context()->get_first_corpus(),
7395 s = context()->get_second_corpus();;
7397 for (string_member_function_sptr_map::const_iterator i =
7398 deleted_member_fns().begin();
7399 i != deleted_member_fns().end();
7401 // We assume that all the functions we look at here have ELF
7403 if (!i->second->get_symbol()
7404 || (i->second->get_symbol()
7405 && s->lookup_function_symbol(i->second->get_symbol()->get_name(),
7406 i->second->get_symbol()->get_version().str())))
7407 to_delete.push_back(i->first);
7410 for (vector<string>::const_iterator i = to_delete.begin();
7411 i != to_delete.end();
7413 priv_->deleted_member_functions_.erase(*i);
7415 // Do something similar for added functions.
7418 for (string_member_function_sptr_map::const_iterator i =
7419 inserted_member_fns().begin();
7420 i != inserted_member_fns().end();
7422 if (!i->second->get_symbol()
7423 || f->lookup_function_symbol(i->second->get_symbol()->get_name(),
7424 i->second->get_symbol()->get_version().str()))
7425 to_delete.push_back(i->first);
7427 for (vector<string>::const_iterator i = to_delete.begin();
7428 i != to_delete.end();
7430 priv_->inserted_member_functions_.erase(*i);
7433 sort_string_virtual_member_function_diff_sptr_map
7434 (priv_->changed_member_functions_,
7435 priv_->sorted_changed_member_functions_);
7438 edit_script& e = priv_->member_class_tmpls_changes_;
7440 for (vector<deletion>::const_iterator it = e.deletions().begin();
7441 it != e.deletions().end();
7444 unsigned i = it->index();
7446 first_class_decl()->get_member_class_templates()[i]->
7448 string qname = d->get_qualified_name();
7449 assert(priv_->deleted_member_class_tmpls_.find(qname)
7450 == priv_->deleted_member_class_tmpls_.end());
7451 priv_->deleted_member_class_tmpls_[qname] = d;
7454 for (vector<insertion>::const_iterator it = e.insertions().begin();
7455 it != e.insertions().end();
7458 for (vector<unsigned>::const_iterator iit =
7459 it->inserted_indexes().begin();
7460 iit != it->inserted_indexes().end();
7465 second_class_decl()->get_member_class_templates()[i]->
7467 string qname = d->get_qualified_name();
7468 assert(priv_->inserted_member_class_tmpls_.find(qname)
7469 == priv_->inserted_member_class_tmpls_.end());
7470 string_decl_base_sptr_map::const_iterator j =
7471 priv_->deleted_member_class_tmpls_.find(qname);
7472 if (j != priv_->deleted_member_class_tmpls_.end())
7474 if (*j->second != *d)
7475 priv_->changed_member_types_[qname]=
7476 compute_diff(j->second, d, context());
7477 priv_->deleted_member_class_tmpls_.erase(j);
7480 priv_->inserted_member_class_tmpls_[qname] = d;
7484 sort_string_diff_sptr_map(priv_->changed_member_types_,
7485 priv_->sorted_changed_member_types_);
7488 /// Test whether a given base class has changed. A base class has
7489 /// changed if it's in both in deleted *and* inserted bases.
7491 ///@param d the declaration for the base class to consider.
7493 /// @return the new base class if the given base class has changed, or
7494 /// NULL if it hasn't.
7495 class_decl::base_spec_sptr
7496 class_diff::priv::base_has_changed(class_decl::base_spec_sptr d) const
7498 string qname = d->get_base_class()->get_qualified_name();
7499 string_base_diff_sptr_map::const_iterator it =
7500 changed_bases_.find(qname);
7502 return (it == changed_bases_.end())
7503 ? class_decl::base_spec_sptr()
7504 : it->second->second_base();
7508 /// Test whether a given member type has changed.
7510 /// @param d the declaration for the member type to consider.
7512 /// @return the new member type if the given member type has changed,
7513 /// or NULL if it hasn't.
7514 type_or_decl_base_sptr
7515 class_diff::priv::member_type_has_changed(decl_base_sptr d) const
7517 string qname = d->get_qualified_name();
7518 string_diff_sptr_map::const_iterator it =
7519 changed_member_types_.find(qname);
7521 return ((it == changed_member_types_.end())
7522 ? type_or_decl_base_sptr()
7523 : it->second->second_subject());
7526 /// Test whether a given data member has changed.
7528 /// @param d the declaration for the data member to consider.
7530 /// @return the new data member if the given data member has changed,
7531 /// or NULL if if hasn't.
7533 class_diff::priv::subtype_changed_dm(decl_base_sptr d) const
7535 string qname = d->get_qualified_name();
7536 string_var_diff_sptr_map::const_iterator it =
7537 subtype_changed_dm_.find(qname);
7539 if (it == subtype_changed_dm_.end())
7540 return decl_base_sptr();
7541 return it->second->second_var();
7544 /// Test whether a given member class template has changed.
7546 /// @param d the declaration for the given member class template to consider.
7548 /// @return the new member class template if the given one has
7549 /// changed, or NULL if it hasn't.
7551 class_diff::priv::member_class_tmpl_has_changed(decl_base_sptr d) const
7553 string qname = d->get_qualified_name();
7554 string_diff_sptr_map::const_iterator it =
7555 changed_member_class_tmpls_.find(qname);
7557 return ((it == changed_member_class_tmpls_.end())
7559 : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
7562 /// Get the number of non-static data member that were deleted from
7563 /// the class which diff we are looking at.
7565 /// @return the number of deleted non-static data members.
7567 class_diff::priv::get_deleted_non_static_data_members_number() const
7571 for (string_decl_base_sptr_map::const_iterator i =
7572 deleted_data_members_.begin();
7573 i != deleted_data_members_.end();
7575 if (is_member_decl(i->second)
7576 && !get_member_is_static(i->second))
7582 /// Get the number of non-static data member that were inserted to the
7583 /// class which diff we are looking at.
7585 /// @return the number of inserted non-static data members.
7587 class_diff::priv::get_inserted_non_static_data_members_number() const
7591 for (string_decl_base_sptr_map::const_iterator i =
7592 inserted_data_members_.begin();
7593 i != inserted_data_members_.end();
7595 if (is_member_decl(i->second)
7596 && !get_member_is_static(i->second))
7602 /// Count the number of bases classes whose changes got filtered out.
7604 /// @return the number of bases classes whose changes got filtered
7607 class_diff::priv::count_filtered_bases()
7609 size_t num_filtered = 0;
7610 for (base_diff_sptrs_type::const_iterator i = sorted_changed_bases_.begin();
7611 i != sorted_changed_bases_.end();
7614 diff_sptr diff = *i;
7615 if (diff && diff->is_filtered_out())
7618 return num_filtered;
7621 /// Count the number of data members whose changes got filtered out.
7623 /// @param ctxt the diff context to use to get the filtering settings
7626 /// @return the number of data members whose changes got filtered out.
7628 class_diff::priv::count_filtered_subtype_changed_dm()
7630 size_t num_filtered= 0;
7631 for (var_diff_sptrs_type::const_iterator i =
7632 sorted_subtype_changed_dm_.begin();
7633 i != sorted_subtype_changed_dm_.end();
7636 if ((*i)->is_filtered_out())
7639 return num_filtered;
7642 /// Count the number of data member offsets that have changed.
7644 /// @return the number of filtered changed data members.
7646 class_diff::priv::count_filtered_changed_dm()
7648 size_t num_filtered= 0;
7650 for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
7651 i != changed_dm_.end();
7654 diff_sptr diff = i->second;
7655 if (diff->is_filtered_out())
7658 return num_filtered;
7662 /// Skip the processing of the current member function if its
7663 /// virtual-ness is disallowed by the user.
7665 /// This is to be used in the member functions below that are used to
7666 /// count the number of filtered inserted, deleted and changed member
7668 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
7670 if (get_member_function_is_virtual(f) \
7671 || get_member_function_is_virtual(s)) \
7673 if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
7678 if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
7683 /// Count the number of member functions whose changes got filtered
7686 /// @param ctxt the diff context to use to get the filtering settings
7689 /// @return the number of member functions whose changes got filtered
7692 class_diff::priv::count_filtered_changed_mem_fns(const diff_context_sptr& ctxt)
7695 diff_category allowed_category = ctxt->get_allowed_category();
7697 for (function_decl_diff_sptrs_type::const_iterator i =
7698 sorted_changed_member_functions_.begin();
7699 i != sorted_changed_member_functions_.end();
7702 class_decl::method_decl_sptr f =
7703 dynamic_pointer_cast<class_decl::method_decl>
7704 ((*i)->first_function_decl());
7707 class_decl::method_decl_sptr s =
7708 dynamic_pointer_cast<class_decl::method_decl>
7709 ((*i)->second_function_decl());
7712 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
7714 diff_sptr diff = *i;
7715 ctxt->maybe_apply_filters(diff);
7717 if (diff->is_filtered_out())
7724 /// Count the number of inserted member functions whose got filtered
7727 /// @param ctxt the diff context to use to get the filtering settings
7730 /// @return the number of inserted member functions whose got filtered
7733 class_diff::priv::count_filtered_inserted_mem_fns(const diff_context_sptr& ctxt)
7736 diff_category allowed_category = ctxt->get_allowed_category();
7738 for (string_member_function_sptr_map::const_iterator i =
7739 inserted_member_functions_.begin();
7740 i != inserted_member_functions_.end();
7743 class_decl::method_decl_sptr f = i->second,
7746 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
7748 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
7749 ctxt->maybe_apply_filters(diff);
7751 if (diff->get_category() != NO_CHANGE_CATEGORY
7752 && diff->is_filtered_out())
7759 /// Count the number of deleted member functions whose got filtered
7762 /// @param ctxt the diff context to use to get the filtering settings
7765 /// @return the number of deleted member functions whose got filtered
7768 class_diff::priv::count_filtered_deleted_mem_fns(const diff_context_sptr& ctxt)
7771 diff_category allowed_category = ctxt->get_allowed_category();
7773 for (string_member_function_sptr_map::const_iterator i =
7774 deleted_member_functions_.begin();
7775 i != deleted_member_functions_.end();
7778 class_decl::method_decl_sptr f = i->second,
7781 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
7783 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
7784 ctxt->maybe_apply_filters(diff);
7786 if (diff->get_category() != NO_CHANGE_CATEGORY
7787 && diff->is_filtered_out())
7794 /// Populate the vector of children node of the @ref diff base type
7795 /// sub-object of this instance of @ref class_diff.
7797 /// The children node can then later be retrieved using
7798 /// diff::children_node().
7800 class_diff::chain_into_hierarchy()
7802 // base class changes.
7803 for (base_diff_sptrs_type::const_iterator i =
7804 priv_->sorted_changed_bases_.begin();
7805 i != priv_->sorted_changed_bases_.end();
7807 if (diff_sptr d = *i)
7808 append_child_node(d);
7810 // data member changes
7811 for (var_diff_sptrs_type::const_iterator i =
7812 priv_->sorted_subtype_changed_dm_.begin();
7813 i != priv_->sorted_subtype_changed_dm_.end();
7815 if (diff_sptr d = *i)
7816 append_child_node(d);
7818 for (unsigned_var_diff_sptr_map::const_iterator i =
7819 priv_->changed_dm_.begin();
7820 i != priv_->changed_dm_.end();
7822 if (diff_sptr d = i->second)
7823 append_child_node(d);
7825 // member types changes
7826 for (diff_sptrs_type::const_iterator i =
7827 priv_->sorted_changed_member_types_.begin();
7828 i != priv_->sorted_changed_member_types_.end();
7830 if (diff_sptr d = *i)
7831 append_child_node(d);
7833 // member function changes
7834 for (function_decl_diff_sptrs_type::const_iterator i =
7835 priv_->sorted_changed_member_functions_.begin();
7836 i != priv_->sorted_changed_member_functions_.end();
7838 if (diff_sptr d = *i)
7839 append_child_node(d);
7842 /// Constructor of class_diff
7844 /// @param first_scope the first class of the diff.
7846 /// @param second_scope the second class of the diff.
7848 /// @param ctxt the diff context to use.
7849 class_diff::class_diff(shared_ptr<class_decl> first_scope,
7850 shared_ptr<class_decl> second_scope,
7851 diff_context_sptr ctxt)
7852 : type_diff_base(first_scope, second_scope, ctxt)
7853 // We don't initialize the priv_ data member here. This is an
7854 // optimization to reduce memory consumption (and also execution
7855 // time) for cases where there are a lot of instances of
7856 // class_diff in the same equivalence class. In compute_diff(),
7857 // the priv_ is set to the priv_ of the canonical diff node.
7858 // See PR libabigail/17948.
7861 class_diff::~class_diff()
7864 /// Finish building the current instance of @ref class_diff.
7866 class_diff::finish_diff_type()
7868 if (diff::priv_->finished_)
7870 chain_into_hierarchy();
7871 diff::priv_->finished_ = true;
7874 /// @return the pretty representation of the current instance of @ref
7877 class_diff::get_pretty_representation() const
7879 if (diff::priv_->pretty_representation_.empty())
7881 std::ostringstream o;
7883 << first_subject()->get_pretty_representation()
7885 << second_subject()->get_pretty_representation()
7887 diff::priv_->pretty_representation_ = o.str();
7889 return diff::priv_->pretty_representation_;
7892 /// Return true iff the current diff node carries a change.
7894 /// @return true iff the current diff node carries a change.
7896 class_diff::has_changes() const
7897 {return (first_class_decl() != second_class_decl());}
7899 /// @return true iff the current diff node carries local changes.
7901 class_diff::has_local_changes() const
7903 ir::change_kind k = ir::NO_CHANGE_KIND;
7904 if (!equals(*first_class_decl(), *second_class_decl(), &k))
7905 return k & LOCAL_CHANGE_KIND;
7909 /// @return the first class invoveld in the diff.
7910 shared_ptr<class_decl>
7911 class_diff::first_class_decl() const
7912 {return dynamic_pointer_cast<class_decl>(first_subject());}
7914 /// Getter of the second class involved in the diff.
7916 /// @return the second class invoveld in the diff
7917 shared_ptr<class_decl>
7918 class_diff::second_class_decl() const
7919 {return dynamic_pointer_cast<class_decl>(second_subject());}
7921 /// @return the edit script of the bases of the two classes.
7923 class_diff::base_changes() const
7924 {return priv_->base_changes_;}
7926 /// Getter for the deleted base classes of the diff.
7928 /// @return a map containing the deleted base classes, keyed with
7929 /// their pretty representation.
7930 const string_base_sptr_map&
7931 class_diff::deleted_bases() const
7932 {return priv_->deleted_bases_;}
7934 /// Getter for the inserted base classes of the diff.
7936 /// @return a map containing the inserted base classes, keyed with
7937 /// their pretty representation.
7938 const string_base_sptr_map&
7939 class_diff::inserted_bases() const
7940 {return priv_->inserted_bases_;}
7942 /// Getter for the changed base classes of the diff.
7944 /// @return a sorted vector containing the changed base classes
7945 const base_diff_sptrs_type&
7946 class_diff::changed_bases()
7947 {return priv_->sorted_changed_bases_;}
7949 /// @return the edit script of the bases of the two classes.
7951 class_diff::base_changes()
7952 {return priv_->base_changes_;}
7954 /// @return the edit script of the member types of the two classes.
7956 class_diff::member_types_changes() const
7957 {return priv_->member_types_changes_;}
7959 /// @return the edit script of the member types of the two classes.
7961 class_diff::member_types_changes()
7962 {return priv_->member_types_changes_;}
7964 /// @return the edit script of the data members of the two classes.
7966 class_diff::data_members_changes() const
7967 {return priv_->data_members_changes_;}
7969 /// @return the edit script of the data members of the two classes.
7971 class_diff::data_members_changes()
7972 {return priv_->data_members_changes_;}
7974 /// Getter for the data members that got inserted.
7976 /// @return a map of data members that got inserted.
7977 const string_decl_base_sptr_map&
7978 class_diff::inserted_data_members() const
7979 {return priv_->inserted_data_members_;}
7981 /// Getter for the data members that got deleted.
7983 /// @return a map of data members that got deleted.
7984 const string_decl_base_sptr_map&
7985 class_diff::deleted_data_members() const
7986 {return priv_->deleted_data_members_;}
7988 /// @return the edit script of the member functions of the two
7991 class_diff::member_fns_changes() const
7992 {return priv_->member_fns_changes_;}
7994 /// Getter for the virtual members functions that have had a change in
7995 /// a sub-type, without having a change in their symbol name.
7997 /// @return a sorted vector of virtual member functions that have a
7998 /// sub-type change.
7999 const function_decl_diff_sptrs_type&
8000 class_diff::changed_member_fns() const
8001 {return priv_->sorted_changed_member_functions_;}
8003 /// @return the edit script of the member functions of the two
8006 class_diff::member_fns_changes()
8007 {return priv_->member_fns_changes_;}
8009 /// @return a map of member functions that got deleted.
8010 const string_member_function_sptr_map&
8011 class_diff::deleted_member_fns() const
8012 {return priv_->deleted_member_functions_;}
8014 /// @return a map of member functions that got inserted.
8015 const string_member_function_sptr_map&
8016 class_diff::inserted_member_fns() const
8017 {return priv_->inserted_member_functions_;}
8019 ///@return the edit script of the member function templates of the two
8022 class_diff::member_fn_tmpls_changes() const
8023 {return priv_->member_fn_tmpls_changes_;}
8025 /// @return the edit script of the member function templates of the
8028 class_diff::member_fn_tmpls_changes()
8029 {return priv_->member_fn_tmpls_changes_;}
8031 /// @return the edit script of the member class templates of the two
8034 class_diff::member_class_tmpls_changes() const
8035 {return priv_->member_class_tmpls_changes_;}
8037 /// @return the edit script of the member class templates of the two
8040 class_diff::member_class_tmpls_changes()
8041 {return priv_->member_class_tmpls_changes_;}
8043 /// A comparison function for instances of @ref base_diff.
8044 struct base_diff_comp
8047 operator()(const base_diff& l, const base_diff& r) const
8049 class_decl::base_spec_sptr f = l.first_base(), s = r.first_base();
8050 if (f->get_offset_in_bits() >= 0
8051 && s->get_offset_in_bits() >= 0)
8052 return f->get_offset_in_bits() < s->get_offset_in_bits();
8054 return (f->get_base_class()->get_pretty_representation()
8055 < s->get_base_class()->get_pretty_representation());
8059 operator()(const base_diff* l, const base_diff* r) const
8060 {return operator()(*l, *r);}
8063 operator()(const base_diff_sptr l, const base_diff_sptr r) const
8064 {return operator()(l.get(), r.get());}
8065 }; // end struct base_diff_comp
8067 /// Sort a map of string -> base_diff_sptr into a sorted vector of
8068 /// base_diff_sptr. The base_diff_sptr are sorted by increasing value
8069 /// of their offset in their containing type.
8071 /// @param map the input map to sort.
8073 /// @param sorted the resulting sorted vector.
8075 sort_string_base_diff_sptr_map(const string_base_diff_sptr_map& map,
8076 base_diff_sptrs_type& sorted)
8078 for (string_base_diff_sptr_map::const_iterator i = map.begin();
8081 sorted.push_back(i->second);
8082 base_diff_comp comp;
8083 sort(sorted.begin(), sorted.end(), comp);
8086 /// A comparison functor to compare two instances of @ref var_diff
8087 /// that represent changed data members based on the offset of their
8089 struct data_member_diff_comp
8091 /// @param f the first change to data member to take into account
8093 /// @param s the second change to data member to take into account.
8095 /// @return true iff f is before s.
8097 operator()(const var_diff_sptr f,
8098 const var_diff_sptr s) const
8100 var_decl_sptr first_dm = f->first_var();
8101 var_decl_sptr second_dm = s->first_var();
8103 assert(is_data_member(first_dm));
8104 assert(is_data_member(second_dm));
8106 return get_data_member_offset(first_dm) < get_data_member_offset(second_dm);
8108 }; // end struct var_diff_comp
8110 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
8111 /// result into a vector of var_diff_sptr.
8113 /// @param map the map of changed data members to sort.
8115 /// @param sorted the resulting vector of sorted var_diff_sptr.
8117 sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,
8118 var_diff_sptrs_type& sorted)
8120 sorted.reserve(map.size());
8121 for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
8124 sorted.push_back(i->second);
8125 data_member_diff_comp comp;
8126 std::sort(sorted.begin(), sorted.end(), comp);
8129 /// Sort the values of a string_var_diff_sptr_map and store the result
8130 /// in a vector of var_diff_sptr.
8132 /// @param map the map of changed data members to sort.
8134 /// @param sorted the resulting vector of var_diff_sptr.
8136 sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map,
8137 var_diff_sptrs_type& sorted)
8139 sorted.reserve(map.size());
8140 for (string_var_diff_sptr_map::const_iterator i = map.begin();
8143 sorted.push_back(i->second);
8144 data_member_diff_comp comp;
8145 std::sort(sorted.begin(), sorted.end(), comp);
8148 /// A comparison functor to compare two data members based on their
8150 struct data_member_comp
8152 /// @param f the first data member to take into account.
8154 /// @param s the second data member to take into account.
8156 /// @return true iff f is before s.
8158 operator()(const decl_base_sptr& f,
8159 const decl_base_sptr& s) const
8161 var_decl_sptr first_dm = is_data_member(f);
8162 var_decl_sptr second_dm = is_data_member(s);
8167 return get_data_member_offset(first_dm) < get_data_member_offset(second_dm);
8169 };//end struct data_member_comp
8171 /// Sort a map of data members by the offset of their initial value.
8173 /// @param data_members the map of changed data members to sort.
8175 /// @param sorted the resulting vector of sorted changed data members.
8177 sort_data_members(const string_decl_base_sptr_map &data_members,
8178 vector<decl_base_sptr>& sorted)
8180 sorted.reserve(data_members.size());
8181 for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
8182 i != data_members.end();
8184 sorted.push_back(i->second);
8186 data_member_comp comp;
8187 std::sort(sorted.begin(), sorted.end(), comp);
8190 /// A comparison functor for instances of @ref function_decl_diff that
8191 /// represent changes between two virtual member functions.
8192 struct virtual_member_function_diff_comp
8195 operator()(const function_decl_diff& l,
8196 const function_decl_diff& r) const
8198 assert(get_member_function_is_virtual(l.first_function_decl()));
8199 assert(get_member_function_is_virtual(r.first_function_decl()));
8201 return (get_member_function_vtable_offset(l.first_function_decl())
8202 < get_member_function_vtable_offset(r.first_function_decl()));
8206 operator()(const function_decl_diff* l,
8207 const function_decl_diff* r)
8208 {return operator()(*l, *r);}
8211 operator()(const function_decl_diff_sptr l,
8212 const function_decl_diff_sptr r)
8213 {return operator()(l.get(), r.get());}
8214 }; // end struct virtual_member_function_diff_comp
8216 /// Sort an map of string -> virtual member function into a vector of
8217 /// virtual member functions. The virtual member functions are sorted
8218 /// by increasing order of their virtual index.
8220 /// @param map the input map.
8222 /// @param sorted the resulting sorted vector of virtual function
8225 sort_string_virtual_member_function_diff_sptr_map
8226 (const string_function_decl_diff_sptr_map& map,
8227 function_decl_diff_sptrs_type& sorted)
8229 sorted.reserve(map.size());
8230 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
8233 sorted.push_back(i->second);
8235 virtual_member_function_diff_comp comp;
8236 sort(sorted.begin(), sorted.end(), comp);
8239 /// Produce a basic report about the changes between two class_decl.
8241 /// @param out the output stream to report the changes to.
8243 /// @param indent the string to use as an indentation prefix in the
8246 class_diff::report(ostream& out, const string& indent) const
8248 if (!to_be_reported())
8251 string name = first_subject()->get_pretty_representation();
8253 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(first_subject(),
8256 currently_reporting(true);
8258 // Now report the changes about the differents parts of the type.
8259 class_decl_sptr first = first_class_decl(),
8260 second = second_class_decl();
8262 if (report_name_size_and_alignment_changes(first, second, context(),
8264 /*start_with_new_line=*/false))
8267 maybe_report_diff_for_member(first, second, context(), out, indent);
8272 // Report deletions.
8273 int numdels = priv_->deleted_bases_.size();
8274 size_t numchanges = priv_->sorted_changed_bases_.size();
8278 report_mem_header(out, numdels, 0, del_kind,
8279 "base class", indent);
8281 for (string_base_sptr_map::const_iterator i
8282 = priv_->deleted_bases_.begin();
8283 i != priv_->deleted_bases_.end();
8286 if (i != priv_->deleted_bases_.begin())
8289 class_decl::base_spec_sptr base = i->second;
8291 if ( priv_->base_has_changed(base))
8293 out << indent << " "
8294 << base->get_base_class()->get_pretty_representation();
8300 bool emitted = false;
8301 size_t num_filtered = priv_->count_filtered_bases();
8304 report_mem_header(out, numchanges, num_filtered, change_kind,
8305 "base class", indent);
8306 for (base_diff_sptrs_type::const_iterator it =
8307 priv_->sorted_changed_bases_.begin();
8308 it != priv_->sorted_changed_bases_.end();
8311 base_diff_sptr diff = *it;
8312 if (!diff || !diff->to_be_reported())
8315 class_decl::base_spec_sptr o = diff->first_base();
8316 out << indent << " '"
8317 << o->get_base_class()->get_pretty_representation()
8319 diff->report(out, indent + " ");
8326 //Report insertions.
8327 int numins = priv_->inserted_bases_.size();
8330 report_mem_header(out, numins, 0, ins_kind,
8331 "base class", indent);
8333 bool emitted = false;
8334 for (string_base_sptr_map::const_iterator i =
8335 priv_->inserted_bases_.begin();
8336 i != priv_->inserted_bases_.end();
8339 class_decl_sptr b = i->second->get_base_class();
8342 out << indent << " " << b->get_pretty_representation();
8350 if (member_fns_changes())
8353 int numdels = priv_->deleted_member_functions_.size();
8354 size_t num_filtered = priv_->count_filtered_deleted_mem_fns(context());
8356 report_mem_header(out, numdels, num_filtered, del_kind,
8357 "member function", indent);
8358 bool emitted = false;
8359 for (string_member_function_sptr_map::const_iterator i =
8360 priv_->deleted_member_functions_.begin();
8361 i != priv_->deleted_member_functions_.end();
8364 if (!(context()->get_allowed_category()
8365 & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
8366 && !get_member_function_is_virtual(i->second))
8370 && i != priv_->deleted_member_functions_.begin())
8372 class_decl::method_decl_sptr mem_fun = i->second;
8373 out << indent << " ";
8374 represent(*context(), mem_fun, out);
8380 // report insertions;
8381 int numins = priv_->inserted_member_functions_.size();
8382 num_filtered = priv_->count_filtered_inserted_mem_fns(context());
8384 report_mem_header(out, numins, num_filtered, ins_kind,
8385 "member function", indent);
8387 for (string_member_function_sptr_map::const_iterator i =
8388 priv_->inserted_member_functions_.begin();
8389 i != priv_->inserted_member_functions_.end();
8392 if (!(context()->get_allowed_category()
8393 & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
8394 && !get_member_function_is_virtual(i->second))
8398 && i != priv_->inserted_member_functions_.begin())
8400 class_decl::method_decl_sptr mem_fun = i->second;
8401 out << indent << " ";
8402 represent(*context(), mem_fun, out);
8408 // report member function with sub-types changes
8409 int numchanges = priv_->sorted_changed_member_functions_.size();
8410 num_filtered = priv_->count_filtered_changed_mem_fns(context());
8412 report_mem_header(out, numchanges, num_filtered, change_kind,
8413 "member function", indent);
8415 for (function_decl_diff_sptrs_type::const_iterator i =
8416 priv_->sorted_changed_member_functions_.begin();
8417 i != priv_->sorted_changed_member_functions_.end();
8420 if (!(context()->get_allowed_category()
8421 & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
8422 && !(get_member_function_is_virtual
8423 ((*i)->first_function_decl()))
8424 && !(get_member_function_is_virtual
8425 ((*i)->second_function_decl())))
8428 diff_sptr diff = *i;
8429 if (!diff || !diff->to_be_reported())
8433 (*i)->first_function_decl()->get_pretty_representation();
8435 && i != priv_->sorted_changed_member_functions_.begin())
8437 out << indent << " '" << repr << "' has some sub-type changes:\n";
8438 diff->report(out, indent + " ");
8446 if (data_members_changes())
8449 int numdels = priv_->get_deleted_non_static_data_members_number();
8452 report_mem_header(out, numdels, 0, del_kind,
8453 "data member", indent);
8454 vector<decl_base_sptr> sorted_dms;
8455 sort_data_members(priv_->deleted_data_members_, sorted_dms);
8456 bool emitted = false;
8457 for (vector<decl_base_sptr>::const_iterator i = sorted_dms.begin();
8458 i != sorted_dms.end();
8461 var_decl_sptr data_mem =
8462 dynamic_pointer_cast<var_decl>(*i);
8464 if (get_member_is_static(data_mem))
8468 out << indent << " ";
8469 represent_data_member(data_mem, out);
8477 int numins = priv_->inserted_data_members_.size();
8480 report_mem_header(out, numins, 0, ins_kind,
8481 "data member", indent);
8482 vector<decl_base_sptr> sorted_dms;
8483 sort_data_members(priv_->inserted_data_members_, sorted_dms);
8484 for (vector<decl_base_sptr>::const_iterator i = sorted_dms.begin();
8485 i != sorted_dms.end();
8488 var_decl_sptr data_mem =
8489 dynamic_pointer_cast<var_decl>(*i);
8491 out << indent << " ";
8492 represent_data_member(data_mem, out);
8497 size_t numchanges = priv_->sorted_subtype_changed_dm_.size();
8498 size_t num_filtered = priv_->count_filtered_subtype_changed_dm();
8501 report_mem_header(out, numchanges, num_filtered,
8502 subtype_change_kind, "data member", indent);
8503 for (var_diff_sptrs_type::const_iterator it =
8504 priv_->sorted_subtype_changed_dm_.begin();
8505 it != priv_->sorted_subtype_changed_dm_.end();
8507 represent(*it, context(), out, indent + " ");
8511 numchanges = priv_->sorted_changed_dm_.size();
8512 num_filtered = priv_->count_filtered_changed_dm();
8515 report_mem_header(out, numchanges, num_filtered,
8516 change_kind, "data member", indent);
8517 for (var_diff_sptrs_type::const_iterator it =
8518 priv_->sorted_changed_dm_.begin();
8519 it != priv_->sorted_changed_dm_.end();
8521 represent(*it, context(), out, indent + " ");
8527 if (const edit_script& e = member_types_changes())
8529 int numchanges = priv_->sorted_changed_member_types_.size();
8530 int numdels = priv_->deleted_member_types_.size();
8535 report_mem_header(out, numdels, 0, del_kind,
8536 "member type", indent);
8538 for (string_decl_base_sptr_map::const_iterator i =
8539 priv_->deleted_member_types_.begin();
8540 i != priv_->deleted_member_types_.end();
8543 if (i != priv_->deleted_member_types_.begin())
8545 decl_base_sptr mem_type = i->second;
8546 out << indent << " '"
8547 << mem_type->get_pretty_representation()
8555 report_mem_header(out, numchanges, 0, change_kind,
8556 "member type", indent);
8558 for (diff_sptrs_type::const_iterator it =
8559 priv_->sorted_changed_member_types_.begin();
8560 it != priv_->sorted_changed_member_types_.end();
8563 if (!(*it)->to_be_reported())
8566 type_or_decl_base_sptr o = (*it)->first_subject();
8567 type_or_decl_base_sptr n = (*it)->second_subject();
8568 out << indent << " '"
8569 << o->get_pretty_representation()
8571 (*it)->report(out, indent + " ");
8576 // report insertions
8577 int numins = e.num_insertions();
8578 assert(numchanges <= numins);
8579 numins -= numchanges;
8583 report_mem_header(out, numins, 0, ins_kind,
8584 "member type", indent);
8586 bool emitted = false;
8587 for (vector<insertion>::const_iterator i = e.insertions().begin();
8588 i != e.insertions().end();
8591 type_base_sptr mem_type;
8592 for (vector<unsigned>::const_iterator j =
8593 i->inserted_indexes().begin();
8594 j != i->inserted_indexes().end();
8599 mem_type = second->get_member_types()[*j];
8601 member_type_has_changed(get_type_declaration(mem_type)))
8603 out << indent << " '"
8604 << get_type_declaration(mem_type)->
8605 get_pretty_representation()
8615 // member function templates
8616 if (const edit_script& e = member_fn_tmpls_changes())
8619 int numdels = e.num_deletions();
8621 report_mem_header(out, numdels, 0, del_kind,
8622 "member function template", indent);
8623 for (vector<deletion>::const_iterator i = e.deletions().begin();
8624 i != e.deletions().end();
8627 if (i != e.deletions().begin())
8629 class_decl::member_function_template_sptr mem_fn_tmpl =
8630 first->get_member_function_templates()[i->index()];
8631 out << indent << " '"
8632 << mem_fn_tmpl->as_function_tdecl()->get_pretty_representation()
8638 // report insertions
8639 int numins = e.num_insertions();
8641 report_mem_header(out, numins, 0, ins_kind,
8642 "member function template", indent);
8643 bool emitted = false;
8644 for (vector<insertion>::const_iterator i = e.insertions().begin();
8645 i != e.insertions().end();
8648 class_decl::member_function_template_sptr mem_fn_tmpl;
8649 for (vector<unsigned>::const_iterator j =
8650 i->inserted_indexes().begin();
8651 j != i->inserted_indexes().end();
8656 mem_fn_tmpl = second->get_member_function_templates()[*j];
8657 out << indent << " '"
8658 << mem_fn_tmpl->as_function_tdecl()->
8659 get_pretty_representation()
8668 // member class templates.
8669 if (const edit_script& e = member_class_tmpls_changes())
8672 int numdels = e.num_deletions();
8674 report_mem_header(out, numdels, 0, del_kind,
8675 "member class template", indent);
8676 for (vector<deletion>::const_iterator i = e.deletions().begin();
8677 i != e.deletions().end();
8680 if (i != e.deletions().begin())
8682 class_decl::member_class_template_sptr mem_cls_tmpl =
8683 first->get_member_class_templates()[i->index()];
8684 out << indent << " '"
8685 << mem_cls_tmpl->as_class_tdecl()->get_pretty_representation()
8691 // report insertions
8692 int numins = e.num_insertions();
8694 report_mem_header(out, numins, 0, ins_kind,
8695 "member class template", indent);
8696 bool emitted = false;
8697 for (vector<insertion>::const_iterator i = e.insertions().begin();
8698 i != e.insertions().end();
8701 class_decl::member_class_template_sptr mem_cls_tmpl;
8702 for (vector<unsigned>::const_iterator j =
8703 i->inserted_indexes().begin();
8704 j != i->inserted_indexes().end();
8709 mem_cls_tmpl = second->get_member_class_templates()[*j];
8710 out << indent << " '"
8711 << mem_cls_tmpl->as_class_tdecl()
8712 ->get_pretty_representation()
8721 currently_reporting(false);
8722 reported_once(true);
8725 /// Compute the set of changes between two instances of class_decl.
8727 /// @param first the first class_decl to consider.
8729 /// @param second the second class_decl to consider.
8731 /// @return changes the resulting changes.
8733 /// @param ctxt the diff context to use.
8735 compute_diff(const class_decl_sptr first,
8736 const class_decl_sptr second,
8737 diff_context_sptr ctxt)
8739 class_decl_sptr f = look_through_decl_only_class(first),
8740 s = look_through_decl_only_class(second);
8742 class_diff_sptr changes(new class_diff(f, s, ctxt));
8744 ctxt->initialize_canonical_diff(changes);
8745 assert(changes->get_canonical_diff());
8747 if (!ctxt->get_canonical_diff_for(first, second))
8749 // Either first or second is a decl-only class; let's set the
8750 // canonical diff here in that case.
8751 diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
8752 assert(canonical_diff);
8753 ctxt->set_canonical_diff_for(first, second, canonical_diff);
8756 // Ok, so this is an optimization. Do not freak out if it looks
8757 // weird, because, well, it does look weird. This speeds up
8758 // greatly, for instance, the test case given at PR
8759 // libabigail/17948.
8761 // We are setting the private data of the new instance of class_diff
8762 // (which is 'changes') to the private data of its canonical
8763 // instance. That is, we are sharing the private data of 'changes'
8764 // with the private data of its canonical instance to consume less
8765 // memory in cases where the equivalence class of 'changes' is huge.
8767 // But if changes is its own canonical instance, then we initialize
8768 // its private data properly.
8769 if (dynamic_cast<class_diff*>(changes->get_canonical_diff()) == changes.get())
8770 // changes is its own canonical instance, so it gets a brand new
8772 changes->priv_.reset(new class_diff::priv);
8775 // changes has a non-empty equivalence class so it's going to
8776 // share its private data with its canonical instance.
8778 dynamic_cast<class_diff*>(changes->get_canonical_diff())->priv_;
8779 assert(changes->priv_);
8783 // Compare base specs
8784 compute_diff(f->get_base_specifiers().begin(),
8785 f->get_base_specifiers().end(),
8786 s->get_base_specifiers().begin(),
8787 s->get_base_specifiers().end(),
8788 changes->base_changes());
8790 // Do *not* compare member types because it generates lots of noise
8791 // and I doubt it's really useful.
8793 compute_diff(f->get_member_types().begin(),
8794 f->get_member_types().end(),
8795 s->get_member_types().begin(),
8796 s->get_member_types().end(),
8797 changes->member_types_changes());
8800 // Compare data member
8801 compute_diff(f->get_data_members().begin(),
8802 f->get_data_members().end(),
8803 s->get_data_members().begin(),
8804 s->get_data_members().end(),
8805 changes->data_members_changes());
8807 // Compare virtual member functions
8808 compute_diff(f->get_virtual_mem_fns().begin(),
8809 f->get_virtual_mem_fns().end(),
8810 s->get_virtual_mem_fns().begin(),
8811 s->get_virtual_mem_fns().end(),
8812 changes->member_fns_changes());
8814 // Compare member function templates
8815 compute_diff(f->get_member_function_templates().begin(),
8816 f->get_member_function_templates().end(),
8817 s->get_member_function_templates().begin(),
8818 s->get_member_function_templates().end(),
8819 changes->member_fn_tmpls_changes());
8821 // Likewise, do not compare member class templates
8823 compute_diff(f->get_member_class_templates().begin(),
8824 f->get_member_class_templates().end(),
8825 s->get_member_class_templates().begin(),
8826 s->get_member_class_templates().end(),
8827 changes->member_class_tmpls_changes());
8830 changes->ensure_lookup_tables_populated();
8835 //</class_diff stuff>
8837 // <base_diff stuff>
8838 struct base_diff::priv
8840 class_diff_sptr underlying_class_diff_;
8842 priv(class_diff_sptr underlying)
8843 : underlying_class_diff_(underlying)
8845 }; // end struct base_diff::priv
8847 /// Populate the vector of children node of the @ref diff base type
8848 /// sub-object of this instance of @ref base_diff.
8850 /// The children node can then later be retrieved using
8851 /// diff::children_node().
8853 base_diff::chain_into_hierarchy()
8854 {append_child_node(get_underlying_class_diff());}
8856 /// @param first the first base spec to consider.
8858 /// @param second the second base spec to consider.
8860 /// @param ctxt the context of the diff.
8861 base_diff::base_diff(class_decl::base_spec_sptr first,
8862 class_decl::base_spec_sptr second,
8863 class_diff_sptr underlying,
8864 diff_context_sptr ctxt)
8865 : diff(first, second, ctxt),
8866 priv_(new priv(underlying))
8869 /// Finish building the current instance of @ref base_diff.
8871 base_diff::finish_diff_type()
8873 if (diff::priv_->finished_)
8876 chain_into_hierarchy();
8877 diff::priv_->finished_ = true;
8880 /// Getter for the first base spec of the diff object.
8882 /// @return the first base specifier for the diff object.
8883 class_decl::base_spec_sptr
8884 base_diff::first_base() const
8885 {return dynamic_pointer_cast<class_decl::base_spec>(first_subject());}
8887 /// Getter for the second base spec of the diff object.
8889 /// @return the second base specifier for the diff object.
8890 class_decl::base_spec_sptr
8891 base_diff::second_base() const
8892 {return dynamic_pointer_cast<class_decl::base_spec>(second_subject());}
8894 /// Getter for the diff object for the diff of the underlying base
8897 /// @return the diff object for the diff of the underlying base
8899 const class_diff_sptr
8900 base_diff::get_underlying_class_diff() const
8901 {return priv_->underlying_class_diff_;}
8903 /// Setter for the diff object for the diff of the underlyng base
8906 /// @param d the new diff object for the diff of the underlying base
8909 base_diff::set_underlying_class_diff(class_diff_sptr d)
8910 {priv_->underlying_class_diff_ = d;}
8912 /// @return the pretty representation for the current instance of @ref
8915 base_diff::get_pretty_representation() const
8917 if (diff::priv_->pretty_representation_.empty())
8919 std::ostringstream o;
8921 << first_subject()->get_pretty_representation()
8923 << second_subject()->get_pretty_representation()
8925 diff::priv_->pretty_representation_ = o.str();
8927 return diff::priv_->pretty_representation_;
8930 /// Return true iff the current diff node carries a change.
8932 /// Return true iff the current diff node carries a change.
8934 base_diff::has_changes() const
8935 {return first_base() != second_base();}
8937 /// @return true iff the current diff node carries local changes.
8939 base_diff::has_local_changes() const
8941 ir::change_kind k = ir::NO_CHANGE_KIND;
8942 if (!equals(*first_base(), *second_base(), &k))
8943 return k & LOCAL_CHANGE_KIND;
8947 /// Generates a report for the current instance of base_diff.
8949 /// @param out the output stream to send the report to.
8951 /// @param indent the string to use for indentation.
8953 base_diff::report(ostream& out, const string& indent) const
8955 if (!to_be_reported())
8958 class_decl::base_spec_sptr f = first_base(), s = second_base();
8959 string repr = f->get_base_class()->get_pretty_representation();
8960 bool emitted = false;
8962 if (f->get_is_static() != s->get_is_static())
8964 if (f->get_is_static())
8965 out << indent << "is no more static";
8967 out << indent << "now becomes static";
8971 if ((context()->get_allowed_category() & ACCESS_CHANGE_CATEGORY)
8972 && (f->get_access_specifier() != s->get_access_specifier()))
8977 out << "has access changed from '"
8978 << f->get_access_specifier()
8980 << s->get_access_specifier()
8986 if (class_diff_sptr d = get_underlying_class_diff())
8988 if (d->to_be_reported())
8992 d->report(out, indent);
8997 /// Constructs the diff object representing a diff between two base
8998 /// class specifications.
9000 /// @param first the first base class specification.
9002 /// @param second the second base class specification.
9004 /// @param ctxt the content of the diff.
9006 /// @return the resulting diff object.
9008 compute_diff(const class_decl::base_spec_sptr first,
9009 const class_decl::base_spec_sptr second,
9010 diff_context_sptr ctxt)
9012 class_diff_sptr cl = compute_diff(first->get_base_class(),
9013 second->get_base_class(),
9015 base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
9017 ctxt->initialize_canonical_diff(changes);
9022 // </base_diff stuff>
9024 //<scope_diff stuff>
9025 struct scope_diff::priv
9027 // The edit script built by the function compute_diff.
9028 edit_script member_changes_;
9030 // Below are the useful lookup tables.
9032 // If you add a new lookup table, please update member functions
9033 // clear_lookup_tables, lookup_tables_empty and
9034 // ensure_lookup_tables_built.
9036 // The deleted/inserted types/decls. These basically map what is
9037 // inside the member_changes_ data member. Note that for instance,
9038 // a given type T might be deleted from the first scope and added to
9039 // the second scope again; this means that the type was *changed*.
9040 string_decl_base_sptr_map deleted_types_;
9041 string_decl_base_sptr_map deleted_decls_;
9042 string_decl_base_sptr_map inserted_types_;
9043 string_decl_base_sptr_map inserted_decls_;
9045 // The changed types/decls lookup tables.
9047 // These lookup tables are populated from the lookup tables above.
9049 // Note that the value stored in each of these tables is a pair
9050 // containing the old decl/type and the new one. That way it is
9051 // easy to run a diff between the old decl/type and the new one.
9053 // A changed type/decl is one that has been deleted from the first
9054 // scope and that has been inserted into the second scope.
9055 string_diff_sptr_map changed_types_;
9056 diff_sptrs_type sorted_changed_types_;
9057 string_diff_sptr_map changed_decls_;
9058 diff_sptrs_type sorted_changed_decls_;
9060 // The removed types/decls lookup tables.
9062 // A removed type/decl is one that has been deleted from the first
9063 // scope and that has *NOT* been inserted into it again.
9064 string_decl_base_sptr_map removed_types_;
9065 string_decl_base_sptr_map removed_decls_;
9067 // The added types/decls lookup tables.
9069 // An added type/decl is one that has been inserted to the first
9070 // scope but that has not been deleted from it.
9071 string_decl_base_sptr_map added_types_;
9072 string_decl_base_sptr_map added_decls_;
9073 };//end struct scope_diff::priv
9075 /// Clear the lookup tables that are useful for reporting.
9077 /// This function must be updated each time a lookup table is added or
9080 scope_diff::clear_lookup_tables()
9082 priv_->deleted_types_.clear();
9083 priv_->deleted_decls_.clear();
9084 priv_->inserted_types_.clear();
9085 priv_->inserted_decls_.clear();
9086 priv_->changed_types_.clear();
9087 priv_->changed_decls_.clear();
9088 priv_->removed_types_.clear();
9089 priv_->removed_decls_.clear();
9090 priv_->added_types_.clear();
9091 priv_->added_decls_.clear();
9094 /// Tests if the lookup tables are empty.
9096 /// This function must be updated each time a lookup table is added or
9099 /// @return true iff all the lookup tables are empty.
9101 scope_diff::lookup_tables_empty() const
9103 return (priv_->deleted_types_.empty()
9104 && priv_->deleted_decls_.empty()
9105 && priv_->inserted_types_.empty()
9106 && priv_->inserted_decls_.empty()
9107 && priv_->changed_types_.empty()
9108 && priv_->changed_decls_.empty()
9109 && priv_->removed_types_.empty()
9110 && priv_->removed_decls_.empty()
9111 && priv_->added_types_.empty()
9112 && priv_->added_decls_.empty());
9115 /// If the lookup tables are not yet built, walk the member_changes_
9116 /// member and fill the lookup tables.
9118 scope_diff::ensure_lookup_tables_populated()
9120 if (!lookup_tables_empty())
9123 edit_script& e = priv_->member_changes_;
9125 // Populate deleted types & decls lookup tables.
9126 for (vector<deletion>::const_iterator i = e.deletions().begin();
9127 i != e.deletions().end();
9130 decl_base_sptr decl = deleted_member_at(i);
9131 string qname = decl->get_qualified_name();
9134 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
9135 if (klass_decl && klass_decl->get_is_declaration_only())
9138 assert(priv_->deleted_types_.find(qname)
9139 == priv_->deleted_types_.end());
9140 priv_->deleted_types_[qname] = decl;
9144 assert(priv_->deleted_decls_.find(qname)
9145 == priv_->deleted_decls_.end());
9146 priv_->deleted_decls_[qname] = decl;
9150 // Populate inserted types & decls as well as chagned types & decls
9152 for (vector<insertion>::const_iterator it = e.insertions().begin();
9153 it != e.insertions().end();
9156 for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
9157 i != it->inserted_indexes().end();
9160 decl_base_sptr decl = inserted_member_at(i);
9161 string qname = decl->get_qualified_name();
9164 class_decl_sptr klass_decl =
9165 dynamic_pointer_cast<class_decl>(decl);
9166 if (klass_decl && klass_decl->get_is_declaration_only())
9169 assert(priv_->inserted_types_.find(qname)
9170 == priv_->inserted_types_.end());
9171 string_decl_base_sptr_map::const_iterator j =
9172 priv_->deleted_types_.find(qname);
9173 if (j != priv_->deleted_types_.end())
9175 if (*j->second != *decl)
9176 priv_->changed_types_[qname] =
9177 compute_diff(j->second, decl, context());
9178 priv_->deleted_types_.erase(j);
9181 priv_->inserted_types_[qname] = decl;
9185 assert(priv_->inserted_decls_.find(qname)
9186 == priv_->inserted_decls_.end());
9187 string_decl_base_sptr_map::const_iterator j =
9188 priv_->deleted_decls_.find(qname);
9189 if (j != priv_->deleted_decls_.end())
9191 if (*j->second != *decl)
9192 priv_->changed_decls_[qname] =
9193 compute_diff(j->second, decl, context());
9194 priv_->deleted_decls_.erase(j);
9197 priv_->inserted_decls_[qname] = decl;
9202 sort_string_diff_sptr_map(priv_->changed_decls_,
9203 priv_->sorted_changed_decls_);
9204 sort_string_diff_sptr_map(priv_->changed_types_,
9205 priv_->sorted_changed_types_);
9207 // Populate removed types/decls lookup tables
9208 for (string_decl_base_sptr_map::const_iterator i =
9209 priv_->deleted_types_.begin();
9210 i != priv_->deleted_types_.end();
9213 string_decl_base_sptr_map::const_iterator r =
9214 priv_->inserted_types_.find(i->first);
9215 if (r == priv_->inserted_types_.end())
9216 priv_->removed_types_[i->first] = i->second;
9218 for (string_decl_base_sptr_map::const_iterator i =
9219 priv_->deleted_decls_.begin();
9220 i != priv_->deleted_decls_.end();
9223 string_decl_base_sptr_map::const_iterator r =
9224 priv_->inserted_decls_.find(i->first);
9225 if (r == priv_->inserted_decls_.end())
9226 priv_->removed_decls_[i->first] = i->second;
9229 // Populate added types/decls.
9230 for (string_decl_base_sptr_map::const_iterator i =
9231 priv_->inserted_types_.begin();
9232 i != priv_->inserted_types_.end();
9235 string_decl_base_sptr_map::const_iterator r =
9236 priv_->deleted_types_.find(i->first);
9237 if (r == priv_->deleted_types_.end())
9238 priv_->added_types_[i->first] = i->second;
9240 for (string_decl_base_sptr_map::const_iterator i =
9241 priv_->inserted_decls_.begin();
9242 i != priv_->inserted_decls_.end();
9245 string_decl_base_sptr_map::const_iterator r =
9246 priv_->deleted_decls_.find(i->first);
9247 if (r == priv_->deleted_decls_.end())
9248 priv_->added_decls_[i->first] = i->second;
9252 /// Populate the vector of children node of the @ref diff base type
9253 /// sub-object of this instance of @ref scope_diff.
9255 /// The children node can then later be retrieved using
9256 /// diff::children_node().
9258 scope_diff::chain_into_hierarchy()
9260 for (diff_sptrs_type::const_iterator i = changed_types().begin();
9261 i != changed_types().end();
9264 append_child_node(*i);
9266 for (diff_sptrs_type::const_iterator i = changed_decls().begin();
9267 i != changed_decls().end();
9270 append_child_node(*i);
9273 /// Constructor for scope_diff
9275 /// @param first_scope the first scope to consider for the diff.
9277 /// @param second_scope the second scope to consider for the diff.
9279 /// @param ctxt the diff context to use.
9280 scope_diff::scope_diff(scope_decl_sptr first_scope,
9281 scope_decl_sptr second_scope,
9282 diff_context_sptr ctxt)
9283 : diff(first_scope, second_scope, ctxt),
9287 /// Finish building the current instance of @ref scope_diff.
9289 scope_diff::finish_diff_type()
9291 if (diff::priv_->finished_)
9293 chain_into_hierarchy();
9294 diff::priv_->finished_ = true;
9297 /// Getter for the first scope of the diff.
9299 /// @return the first scope of the diff.
9300 const scope_decl_sptr
9301 scope_diff::first_scope() const
9302 {return dynamic_pointer_cast<scope_decl>(first_subject());}
9304 /// Getter for the second scope of the diff.
9306 /// @return the second scope of the diff.
9307 const scope_decl_sptr
9308 scope_diff::second_scope() const
9309 {return dynamic_pointer_cast<scope_decl>(second_subject());}
9311 /// Accessor of the edit script of the members of a scope.
9313 /// This edit script is computed using the equality operator that
9314 /// applies to shared_ptr<decl_base>.
9316 /// That has interesting consequences. For instance, consider two
9317 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
9318 /// S0'. C0 and C0' have the same qualified name, but have different
9319 /// members. The edit script will consider that C0 has been deleted
9320 /// from S0 and that S0' has been inserted. This is a low level
9321 /// canonical representation of the changes; a higher level
9322 /// representation would give us a simpler way to say "the class C0
9323 /// has been modified into C0'". But worry not. We do have such
9324 /// higher representation as well; that is what changed_types() and
9325 /// changed_decls() is for.
9327 /// @return the edit script of the changes encapsulatd in this
9328 /// instance of scope_diff.
9330 scope_diff::member_changes() const
9331 {return priv_->member_changes_;}
9333 /// Accessor of the edit script of the members of a scope.
9335 /// This edit script is computed using the equality operator that
9336 /// applies to shared_ptr<decl_base>.
9338 /// That has interesting consequences. For instance, consider two
9339 /// scopes S0 and S1. S0 contains a class C0 and S1 contains a class
9340 /// S0'. C0 and C0' have the same qualified name, but have different
9341 /// members. The edit script will consider that C0 has been deleted
9342 /// from S0 and that S0' has been inserted. This is a low level
9343 /// canonical representation of the changes; a higher level
9344 /// representation would give us a simpler way to say "the class C0
9345 /// has been modified into C0'". But worry not. We do have such
9346 /// higher representation as well; that is what changed_types() and
9347 /// changed_decls() is for.
9349 /// @return the edit script of the changes encapsulatd in this
9350 /// instance of scope_diff.
9352 scope_diff::member_changes()
9353 {return priv_->member_changes_;}
9355 /// Accessor that eases the manipulation of the edit script associated
9356 /// to this instance. It returns the scope member that is reported
9357 /// (in the edit script) as deleted at a given index.
9359 /// @param i the index (in the edit script) of an element of the first
9360 /// scope that has been reported as being delete.
9362 /// @return the scope member that has been reported by the edit script
9363 /// as being deleted at index i.
9364 const decl_base_sptr
9365 scope_diff::deleted_member_at(unsigned i) const
9367 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
9368 return scope->get_member_decls()[i];
9371 /// Accessor that eases the manipulation of the edit script associated
9372 /// to this instance. It returns the scope member (of the first scope
9373 /// of this diff instance) that is reported (in the edit script) as
9374 /// deleted at a given iterator.
9376 /// @param i the iterator of an element of the first scope that has
9377 /// been reported as being delete.
9379 /// @return the scope member of the first scope of this diff that has
9380 /// been reported by the edit script as being deleted at iterator i.
9381 const decl_base_sptr
9382 scope_diff::deleted_member_at(vector<deletion>::const_iterator i) const
9383 {return deleted_member_at(i->index());}
9385 /// Accessor that eases the manipulation of the edit script associated
9386 /// to this instance. It returns the scope member (of the second
9387 /// scope of this diff instance) that is reported as being inserted
9388 /// from a given index.
9390 /// @param i the index of an element of the second scope this diff
9391 /// that has been reported by the edit script as being inserted.
9393 /// @return the scope member of the second scope of this diff that has
9394 /// been reported as being inserted from index i.
9395 const decl_base_sptr
9396 scope_diff::inserted_member_at(unsigned i)
9398 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
9399 return scope->get_member_decls()[i];
9402 /// Accessor that eases the manipulation of the edit script associated
9403 /// to this instance. It returns the scope member (of the second
9404 /// scope of this diff instance) that is reported as being inserted
9405 /// from a given iterator.
9407 /// @param i the iterator of an element of the second scope this diff
9408 /// that has been reported by the edit script as being inserted.
9410 /// @return the scope member of the second scope of this diff that has
9411 /// been reported as being inserted from iterator i.
9412 const decl_base_sptr
9413 scope_diff::inserted_member_at(vector<unsigned>::const_iterator i)
9414 {return inserted_member_at(*i);}
9416 /// @return a sorted vector of the types which content has changed
9417 /// from the first scope to the other.
9418 const diff_sptrs_type&
9419 scope_diff::changed_types() const
9420 {return priv_->sorted_changed_types_;}
9422 /// @return a sorted vector of the decls which content has changed
9423 /// from the first scope to the other.
9424 const diff_sptrs_type&
9425 scope_diff::changed_decls() const
9426 {return priv_->sorted_changed_decls_;}
9428 const string_decl_base_sptr_map&
9429 scope_diff::removed_types() const
9430 {return priv_->removed_types_;}
9432 const string_decl_base_sptr_map&
9433 scope_diff::removed_decls() const
9434 {return priv_->removed_decls_;}
9436 const string_decl_base_sptr_map&
9437 scope_diff::added_types() const
9438 {return priv_->added_types_;}
9440 const string_decl_base_sptr_map&
9441 scope_diff::added_decls() const
9442 {return priv_->added_decls_;}
9444 /// @return the pretty representation for the current instance of @ref
9447 scope_diff::get_pretty_representation() const
9449 if (diff::priv_->pretty_representation_.empty())
9451 std::ostringstream o;
9453 << first_subject()->get_pretty_representation()
9455 << second_subject()->get_pretty_representation()
9457 diff::priv_->pretty_representation_ = o.str();
9459 return diff::priv_->pretty_representation_;
9462 /// Return true iff the current diff node carries a change.
9464 /// Return true iff the current diff node carries a change.
9466 scope_diff::has_changes() const
9468 // TODO: add the number of really removed/added stuff.
9469 return changed_types().size() + changed_decls().size();
9472 /// @return true iff the current diff node carries local changes.
9474 scope_diff::has_local_changes() const
9476 ir::change_kind k = ir::NO_CHANGE_KIND;
9477 if (!equals(*first_scope(), *second_scope(), &k))
9478 return k & LOCAL_CHANGE_KIND;
9482 /// A comparison functor for instances of @ref diff.
9486 operator()(const diff& l, diff& r) const
9488 return (get_name(l.first_subject()) < get_name(r.first_subject()));
9492 operator()(const diff* l, diff* r) const
9493 {return operator()(*l, *r);}
9496 operator()(const diff_sptr l, diff_sptr r) const
9497 {return operator()(l.get(), r.get());}
9498 }; // end struct diff_comp;
9500 /// Sort a map ofg string -> @ref diff_sptr into a vector of @ref
9501 /// diff_sptr. The diff_sptr are sorted lexicographically wrt
9502 /// qualified names of their first subjects.
9504 sort_string_diff_sptr_map(const string_diff_sptr_map& map,
9505 diff_sptrs_type& sorted)
9507 sorted.reserve(map.size());
9508 for (string_diff_sptr_map::const_iterator i = map.begin();
9511 sorted.push_back(i->second);
9514 sort(sorted.begin(), sorted.end(), comp);
9517 /// Report the changes of one scope against another.
9519 /// @param out the out stream to report the changes to.
9521 /// @param indent the string to use for indentation.
9523 scope_diff::report(ostream& out, const string& indent) const
9525 if (!to_be_reported())
9528 // Report changed types.
9529 unsigned num_changed_types = changed_types().size();
9530 if (num_changed_types == 0)
9532 else if (num_changed_types == 1)
9533 out << indent << "1 changed type:\n";
9535 out << indent << num_changed_types << " changed types:\n";
9537 for (diff_sptrs_type::const_iterator d = changed_types().begin();
9538 d != changed_types().end();
9544 out << indent << " '"
9545 << (*d)->first_subject()->get_pretty_representation()
9547 (*d)->report(out, indent + " ");
9550 // Report changed decls
9551 unsigned num_changed_decls = changed_decls().size();
9552 if (num_changed_decls == 0)
9554 else if (num_changed_decls == 1)
9555 out << indent << "1 changed declaration:\n";
9557 out << indent << num_changed_decls << " changed declarations:\n";
9559 for (diff_sptrs_type::const_iterator d= changed_decls().begin();
9560 d != changed_decls().end ();
9566 out << indent << " '"
9567 << (*d)->first_subject()->get_pretty_representation()
9568 << "' was changed to '"
9569 << (*d)->second_subject()->get_pretty_representation()
9572 (*d)->report(out, indent + " ");
9575 // Report removed types/decls
9576 for (string_decl_base_sptr_map::const_iterator i =
9577 priv_->deleted_types_.begin();
9578 i != priv_->deleted_types_.end();
9582 << i->second->get_pretty_representation()
9583 << "' was removed\n";
9584 if (priv_->deleted_types_.size())
9587 for (string_decl_base_sptr_map::const_iterator i =
9588 priv_->deleted_decls_.begin();
9589 i != priv_->deleted_decls_.end();
9593 << i->second->get_pretty_representation()
9594 << "' was removed\n";
9595 if (priv_->deleted_decls_.size())
9598 // Report added types/decls
9599 bool emitted = false;
9600 for (string_decl_base_sptr_map::const_iterator i =
9601 priv_->inserted_types_.begin();
9602 i != priv_->inserted_types_.end();
9605 // Do not report about type_decl as these are usually built-in
9607 if (dynamic_pointer_cast<type_decl>(i->second))
9611 << i->second->get_pretty_representation()
9619 for (string_decl_base_sptr_map::const_iterator i =
9620 priv_->inserted_decls_.begin();
9621 i != priv_->inserted_decls_.end();
9624 // Do not report about type_decl as these are usually built-in
9626 if (dynamic_pointer_cast<type_decl>(i->second))
9630 << i->second->get_pretty_representation()
9638 /// Compute the diff between two scopes.
9640 /// @param first the first scope to consider in computing the diff.
9642 /// @param second the second scope to consider in the diff
9643 /// computation. The second scope is diffed against the first scope.
9645 /// @param d a pointer to the diff object to populate with the
9648 /// @return return the populated \a d parameter passed to this
9651 /// @param ctxt the diff context to use.
9653 compute_diff(const scope_decl_sptr first,
9654 const scope_decl_sptr second,
9656 diff_context_sptr ctxt)
9658 assert(d->first_scope() == first && d->second_scope() == second);
9660 compute_diff(first->get_member_decls().begin(),
9661 first->get_member_decls().end(),
9662 second->get_member_decls().begin(),
9663 second->get_member_decls().end(),
9664 d->member_changes());
9666 d->ensure_lookup_tables_populated();
9672 /// Compute the diff between two scopes.
9674 /// @param first_scope the first scope to consider in computing the diff.
9676 /// @param second_scope the second scope to consider in the diff
9677 /// computation. The second scope is diffed against the first scope.
9679 /// @param ctxt the diff context to use.
9681 /// @return return the resulting diff
9683 compute_diff(const scope_decl_sptr first_scope,
9684 const scope_decl_sptr second_scope,
9685 diff_context_sptr ctxt)
9687 scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
9688 d = compute_diff(first_scope, second_scope, d, ctxt);
9689 ctxt->initialize_canonical_diff(d);
9693 //</scope_diff stuff>
9695 // <fn_parm_diff stuff>
9696 struct fn_parm_diff::priv
9698 mutable diff_sptr type_diff;
9699 }; // end struct fn_parm_diff::priv
9701 /// Constructor for the fn_parm_diff type.
9703 /// @param first the first subject of the diff.
9705 /// @param second the second subject of the diff.
9707 /// @param ctxt the context of the diff.
9708 fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
9709 const function_decl::parameter_sptr second,
9710 diff_context_sptr ctxt)
9711 : decl_diff_base(first, second, ctxt),
9714 assert(first->get_index() == second->get_index());
9715 priv_->type_diff = compute_diff(first->get_type(),
9718 assert(priv_->type_diff);
9721 /// Finish the building of the current instance of @ref fn_parm_diff.
9723 fn_parm_diff::finish_diff_type()
9725 if (diff::priv_->finished_)
9727 chain_into_hierarchy();
9728 diff::priv_->finished_ = true;
9731 /// Getter for the first subject of this diff node.
9733 /// @return the first function_decl::parameter_sptr subject of this
9735 const function_decl::parameter_sptr
9736 fn_parm_diff::first_parameter() const
9737 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
9739 /// Getter for the second subject of this diff node.
9741 /// @return the second function_decl::parameter_sptr subject of this
9743 const function_decl::parameter_sptr
9744 fn_parm_diff::second_parameter() const
9745 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
9747 /// Getter for the diff representing the changes on the type of the
9748 /// function parameter involved in the current instance of @ref
9751 /// @return a diff_sptr representing the changes on the type of the
9752 /// function parameter we are interested in.
9754 fn_parm_diff::get_type_diff() const
9755 {return priv_->type_diff;}
9757 /// Build and return a textual representation of the current instance
9758 /// of @ref fn_parm_diff.
9760 /// @return the string representing the current instance of
9763 fn_parm_diff::get_pretty_representation() const
9765 if (diff::priv_->pretty_representation_.empty())
9767 std::ostringstream o;
9768 o << "function_parameter_diff["
9769 << first_subject()->get_pretty_representation()
9771 << second_subject()->get_pretty_representation()
9773 diff::priv_->pretty_representation_ = o.str();
9775 return diff::priv_->pretty_representation_;
9778 /// Return true iff the current diff node carries a change.
9780 /// @return true iff the current diff node carries a change.
9782 fn_parm_diff::has_changes() const
9783 {return *first_parameter() != *second_parameter();}
9785 /// Check if the the current diff node carries a local change.
9787 /// @return true iff the current diff node carries a local change.
9789 fn_parm_diff::has_local_changes() const
9791 ir::change_kind k = ir::NO_CHANGE_KIND;
9792 if (!equals(*first_parameter(), *second_parameter(), &k))
9793 return k & LOCAL_CHANGE_KIND;
9797 /// Emit a textual report about the current fn_parm_diff instance.
9799 /// @param out the output stream to emit the textual report to.
9801 /// @param indent the indentation string to use in the report.
9803 fn_parm_diff::report(ostream& out, const string& indent) const
9805 function_decl::parameter_sptr f = first_parameter(), s = second_parameter();
9807 // either the parameter has a sub-type change (if its type name
9808 // hasn't changed) or it has a "grey" change (that is, a change that
9809 // changes his type name w/o changing the signature of the
9811 bool has_sub_type_change =
9812 type_has_sub_type_changes(first_parameter()->get_type(),
9813 second_parameter()->get_type());
9815 if (to_be_reported())
9817 assert(get_type_diff() && get_type_diff()->to_be_reported());
9819 << "parameter " << f->get_index()
9821 << f->get_type_pretty_representation();
9823 if (has_sub_type_change)
9824 out << "' has sub-type changes:\n";
9826 out << "' changed:\n";
9828 get_type_diff()->report(out, indent + " ");
9832 /// Populate the vector of children nodes of the @ref diff base type
9833 /// sub-object of this instance of @ref fn_parm_diff.
9835 /// The children nodes can then later be retrieved using
9836 /// diff::children_nodes()
9838 fn_parm_diff::chain_into_hierarchy()
9840 if (get_type_diff())
9841 append_child_node(get_type_diff());
9844 /// Compute the difference between two function_decl::parameter_sptr;
9845 /// that is, between two function parameters. Return a resulting
9846 /// fn_parm_diff_sptr that represents the changes.
9848 /// @param first the first subject of the diff.
9850 /// @param second the second subject of the diff.
9852 /// @param ctxt the context of the diff.
9854 /// @return fn_parm_diff_sptr the resulting diff node.
9856 compute_diff(const function_decl::parameter_sptr first,
9857 const function_decl::parameter_sptr second,
9858 diff_context_sptr ctxt)
9860 if (!first || !second)
9861 return fn_parm_diff_sptr();
9863 fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
9864 ctxt->initialize_canonical_diff(result);
9868 // </fn_parm_diff stuff>
9870 // <function_type_diff stuff>
9871 struct function_type_diff::priv
9873 diff_sptr return_type_diff_;
9874 edit_script parm_changes_;
9876 // useful lookup tables.
9877 string_parm_map deleted_parms_;
9878 vector<function_decl::parameter_sptr> sorted_deleted_parms_;
9879 string_parm_map added_parms_;
9880 vector<function_decl::parameter_sptr> sorted_added_parms_;
9881 // This map contains parameters sub-type changes that don't change
9882 // the name of the type of the parameter.
9883 string_fn_parm_diff_sptr_map subtype_changed_parms_;
9884 unsigned_parm_map deleted_parms_by_id_;
9885 unsigned_parm_map added_parms_by_id_;
9886 // This map contains parameter type changes that actually change the
9887 // name of the type of the parameter, but in a compatible way;
9888 // otherwise, the mangling of the function would have changed (in
9890 unsigned_fn_parm_diff_sptr_map changed_parms_by_id_;
9894 }; // end struct function_type_diff::priv
9897 function_type_diff::ensure_lookup_tables_populated()
9899 priv_->return_type_diff_ =
9900 compute_diff(first_function_type()->get_return_type(),
9901 second_function_type()->get_return_type(),
9905 function_decl::parameter_sptr parm;
9906 for (vector<deletion>::const_iterator i =
9907 priv_->parm_changes_.deletions().begin();
9908 i != priv_->parm_changes_.deletions().end();
9911 parm = *(first_function_type()->get_first_non_implicit_parm()
9913 parm_name = parm->get_name_id();
9914 // If for a reason the type name is empty we want to know and
9916 assert(!parm_name.empty());
9917 priv_->deleted_parms_[parm_name] = parm;
9918 priv_->deleted_parms_by_id_[parm->get_index()] = parm;
9921 for (vector<insertion>::const_iterator i =
9922 priv_->parm_changes_.insertions().begin();
9923 i != priv_->parm_changes_.insertions().end();
9926 for (vector<unsigned>::const_iterator j =
9927 i->inserted_indexes().begin();
9928 j != i->inserted_indexes().end();
9931 parm = *(second_function_type()->get_first_non_implicit_parm() + *j);
9932 parm_name = parm->get_name_id();
9933 // If for a reason the type name is empty we want to know and
9935 assert(!parm_name.empty());
9937 string_parm_map::const_iterator k =
9938 priv_->deleted_parms_.find(parm_name);
9939 if (k != priv_->deleted_parms_.end())
9941 if (*k->second != *parm)
9942 priv_->subtype_changed_parms_[parm_name] =
9943 compute_diff(k->second, parm, context());
9944 priv_->deleted_parms_.erase(parm_name);
9947 priv_->added_parms_[parm_name] = parm;
9950 unsigned_parm_map::const_iterator k =
9951 priv_->deleted_parms_by_id_.find(parm->get_index());
9952 if (k != priv_->deleted_parms_by_id_.end())
9954 if (*k->second != *parm
9955 && (k->second->get_name_id() != parm_name))
9956 priv_->changed_parms_by_id_[parm->get_index()] =
9957 compute_diff(k->second, parm, context());
9958 priv_->added_parms_.erase(parm_name);
9959 priv_->deleted_parms_.erase(k->second->get_name_id());
9960 priv_->deleted_parms_by_id_.erase(parm->get_index());
9963 priv_->added_parms_by_id_[parm->get_index()] = parm;
9968 sort_string_parm_map(priv_->deleted_parms_,
9969 priv_->sorted_deleted_parms_);
9971 sort_string_parm_map(priv_->added_parms_,
9972 priv_->sorted_added_parms_);
9975 /// In the vector of deleted parameters, get the one that is at a given
9978 /// @param i the index of the deleted parameter to get.
9980 /// @return the parameter returned.
9981 const function_decl::parameter_sptr
9982 function_type_diff::deleted_parameter_at(int i) const
9983 {return first_function_type()->get_parameters()[i];}
9985 /// In the vector of inserted parameters, get the one that is at a
9988 /// @param i the index of the inserted parameter to get.
9990 /// @return the parameter returned.
9991 const function_decl::parameter_sptr
9992 function_type_diff::inserted_parameter_at(int i) const
9993 {return second_function_type()->get_parameters()[i];}
9995 /// Consutrctor of the @ref function_type type.
9997 /// @param first the first @ref function_type subject of the diff to
10000 /// @param second the second @ref function_type subject of the diff to
10003 /// @param ctxt the diff context to be used by the newly created
10004 /// instance of function_type_diff.
10005 function_type_diff::function_type_diff(const function_type_sptr first,
10006 const function_type_sptr second,
10007 diff_context_sptr ctxt)
10008 : type_diff_base(first, second, ctxt),
10012 /// Finish building the current instance of @ref function_type_diff
10014 function_type_diff::finish_diff_type()
10016 if (diff::priv_->finished_)
10018 chain_into_hierarchy();
10019 diff::priv_->finished_ = true;
10022 /// Getter for the first subject of the diff.
10024 /// @return the first function type involved in the diff.
10025 const function_type_sptr
10026 function_type_diff::first_function_type() const
10027 {return dynamic_pointer_cast<function_type>(first_subject());}
10029 /// Getter for the second subject of the diff.
10031 /// @return the second function type involved in the diff.
10032 const function_type_sptr
10033 function_type_diff::second_function_type() const
10034 {return dynamic_pointer_cast<function_type>(second_subject());}
10036 /// Getter for the diff of the return types of the two function types
10037 /// of the current diff.
10039 /// @return the diff of the return types of the two function types of
10040 /// the current diff.
10042 function_type_diff::return_type_diff() const
10043 {return priv_->return_type_diff_;}
10045 /// Getter for the map of function parameter changes of the current diff.
10047 /// @return a map of function parameter changes of the current diff.
10048 const string_fn_parm_diff_sptr_map&
10049 function_type_diff::subtype_changed_parms() const
10050 {return priv_->subtype_changed_parms_;}
10052 /// Getter for the map of parameters that got removed.
10054 /// @return the map of parameters that got removed.
10055 const string_parm_map&
10056 function_type_diff::removed_parms() const
10057 {return priv_->deleted_parms_;}
10059 /// Getter for the map of parameters that got added.
10061 /// @return the map of parameters that got added.
10062 const string_parm_map&
10063 function_type_diff::added_parms() const
10064 {return priv_->added_parms_;}
10066 /// Build and return a copy of a pretty representation of the current
10067 /// instance of @ref function_type_diff.
10069 /// @return a copy of the pretty representation of the current
10070 /// instance of @ref function_type_diff.
10072 function_type_diff::get_pretty_representation() const
10074 if (diff::priv_->pretty_representation_.empty())
10076 std::ostringstream o;
10077 o << "function_type_diff["
10078 << abigail::ir::get_pretty_representation(first_function_type())
10080 << abigail::ir::get_pretty_representation(second_function_type())
10082 diff::priv_->pretty_representation_ = o.str();
10084 return diff::priv_->pretty_representation_;
10087 /// Test if the current diff node carries changes.
10089 /// @return true iff the current diff node carries changes.
10091 function_type_diff::has_changes() const
10092 {return *first_function_type() != *second_function_type();}
10094 /// Test if the current diff node carries local changes.
10096 /// A local change is a change that is carried by this diff node, not
10097 /// by any of its children nodes.
10099 /// @return true iff the current diff node has local changes.
10101 function_type_diff::has_local_changes() const
10103 ir::change_kind k = ir::NO_CHANGE_KIND;
10104 if (!equals(*first_function_type(), *second_function_type(), &k))
10105 return k & LOCAL_CHANGE_KIND;
10109 /// Build and emit a textual report about the current
10111 /// @param out the output stream.
10113 /// @param indent the indentation string to use.
10115 function_type_diff::report(ostream& out, const string& indent) const
10117 if (!to_be_reported())
10120 function_type_sptr fft = first_function_type();
10121 function_type_sptr sft = second_function_type();
10123 diff_context_sptr ctxt = context();
10124 corpus_sptr fc = ctxt->get_first_corpus();
10125 corpus_sptr sc = ctxt->get_second_corpus();
10128 string qn1 = get_function_type_name(fft), qn2 = get_function_type_name(sft);
10132 string frep1 = ir::get_pretty_representation(fft),
10133 frep2 = ir::get_pretty_representation(sft);
10134 out << indent << "'" << frep1 << "' now becomes '" << frep2 << "'\n";
10139 // Report about the size of the function address
10140 if (fft->get_size_in_bits() != sft->get_size_in_bits())
10142 out << indent << "address size of function changed from "
10143 << fft->get_size_in_bits()
10145 << sft->get_size_in_bits()
10149 // Report about the alignment of the function address
10150 if (fft->get_alignment_in_bits()
10151 != sft->get_alignment_in_bits())
10153 out << indent << "address alignment of function changed from "
10154 << fft->get_alignment_in_bits()
10156 << sft->get_alignment_in_bits()
10160 // Report about return type differences.
10161 if (priv_->return_type_diff_ && priv_->return_type_diff_->to_be_reported())
10163 out << indent << "return type changed:\n";
10164 priv_->return_type_diff_->report(out, indent + " ");
10167 // Hmmh, the above was quick. Now report about function parameters;
10168 // this shouldn't be as straightforward.
10170 // Report about the parameter types that have changed sub-types.
10171 vector<fn_parm_diff_sptr> sorted_fn_parms;
10172 sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
10174 for (vector<fn_parm_diff_sptr>::const_iterator i =
10175 sorted_fn_parms.begin();
10176 i != sorted_fn_parms.end();
10180 if (d && d->to_be_reported())
10181 d->report(out, indent);
10183 // Report about parameters that have changed, while staying
10184 // compatible -- otherwise they would have changed the mangled name
10185 // of the function and the function would have been reported as
10187 sorted_fn_parms.clear();
10188 sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
10190 for (vector<fn_parm_diff_sptr>::const_iterator i = sorted_fn_parms.begin();
10191 i != sorted_fn_parms.end();
10195 if (d && d->to_be_reported())
10196 d->report(out, indent);
10199 // Report about the parameters that got removed.
10200 bool emitted = false;
10201 for (vector<function_decl::parameter_sptr>::const_iterator i =
10202 priv_->sorted_deleted_parms_.begin();
10203 i != priv_->sorted_deleted_parms_.end();
10206 out << indent << "parameter " << (*i)->get_index()
10207 << " of type '" << (*i)->get_type_pretty_representation()
10208 << "' was removed\n";
10214 // Report about the parameters that got added
10216 for (vector<function_decl::parameter_sptr>::const_iterator i =
10217 priv_->sorted_added_parms_.begin();
10218 i != priv_->sorted_added_parms_.end();
10221 out << indent << "parameter " << (*i)->get_index()
10222 << " of type '" << (*i)->get_type_pretty_representation()
10223 << "' was added\n";
10230 /// Populate the vector of children node of the @ref diff base type
10231 /// sub-object of this instance of @ref function_type_diff.
10233 /// The children node can then later be retrieved using
10234 /// diff::children_node().
10236 function_type_diff::chain_into_hierarchy()
10238 if (diff_sptr d = return_type_diff())
10239 append_child_node(d);
10241 for (string_fn_parm_diff_sptr_map::const_iterator i =
10242 subtype_changed_parms().begin();
10243 i != subtype_changed_parms().end();
10245 if (diff_sptr d = i->second)
10246 append_child_node(d);
10248 for (unsigned_fn_parm_diff_sptr_map::const_iterator i =
10249 priv_->changed_parms_by_id_.begin();
10250 i != priv_->changed_parms_by_id_.end();
10252 if (diff_sptr d = i->second)
10253 append_child_node(d);
10256 /// Compute the diff between two instances of @ref function_type.
10258 /// @param first the first @ref function_type to consider for the diff.
10260 /// @param second the second @ref function_type to consider for the diff.
10262 /// @param ctxt the diff context to use.
10264 /// @return the resulting diff between the two @ref function_type.
10265 function_type_diff_sptr
10266 compute_diff(const function_type_sptr first,
10267 const function_type_sptr second,
10268 diff_context_sptr ctxt)
10270 if (!first || !second)
10272 // TODO: implement this for either first or second being NULL.
10273 return function_type_diff_sptr();
10276 function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
10278 diff_utils::compute_diff(first->get_first_non_implicit_parm(),
10279 first->get_parameters().end(),
10280 second->get_first_non_implicit_parm(),
10281 second->get_parameters().end(),
10282 result->priv_->parm_changes_);
10284 result->ensure_lookup_tables_populated();
10286 ctxt->initialize_canonical_diff(result);
10290 // </function_type_diff stuff>
10292 // <function_decl_diff stuff>
10293 struct function_decl_diff::priv
10295 function_type_diff_sptr type_diff_;
10299 };// end struct function_decl_diff::priv
10301 /// Build the lookup tables of the diff, if necessary.
10303 function_decl_diff::ensure_lookup_tables_populated()
10307 /// Populate the vector of children node of the @ref diff base type
10308 /// sub-object of this instance of @ref function_decl_diff.
10310 /// The children node can then later be retrieved using
10311 /// diff::children_node().
10313 function_decl_diff::chain_into_hierarchy()
10315 if (diff_sptr d = type_diff())
10316 append_child_node(d);
10319 /// Constructor for function_decl_diff
10321 /// @param first the first function considered by the diff.
10323 /// @param second the second function considered by the diff.
10324 function_decl_diff::function_decl_diff(const function_decl_sptr first,
10325 const function_decl_sptr second,
10326 diff_context_sptr ctxt)
10327 : decl_diff_base(first, second, ctxt),
10332 /// Finish building the current instance of @ref function_decl_diff.
10334 function_decl_diff::finish_diff_type()
10336 if (diff::priv_->finished_)
10338 chain_into_hierarchy();
10339 diff::priv_->finished_ = true;
10342 /// @return the first function considered by the diff.
10343 const function_decl_sptr
10344 function_decl_diff::first_function_decl() const
10345 {return dynamic_pointer_cast<function_decl>(first_subject());}
10347 /// @return the second function considered by the diff.
10348 const function_decl_sptr
10349 function_decl_diff::second_function_decl() const
10350 {return dynamic_pointer_cast<function_decl>(second_subject());}
10352 const function_type_diff_sptr
10353 function_decl_diff::type_diff() const
10354 {return priv_->type_diff_;}
10356 /// @return the pretty representation for the current instance of @ref
10357 /// function_decl_diff.
10359 function_decl_diff::get_pretty_representation() const
10361 if (diff::priv_->pretty_representation_.empty())
10363 std::ostringstream o;
10364 o << "function_diff["
10365 << first_subject()->get_pretty_representation()
10367 << second_subject()->get_pretty_representation()
10369 diff::priv_->pretty_representation_ = o.str();
10371 return diff::priv_->pretty_representation_;
10374 /// Return true iff the current diff node carries a change.
10376 /// @return true iff the current diff node carries a change.
10378 function_decl_diff::has_changes() const
10379 {return *first_function_decl() != *second_function_decl();}
10381 /// @return true iff the current diff node carries local changes.
10383 function_decl_diff::has_local_changes() const
10385 ir::change_kind k = ir::NO_CHANGE_KIND;
10386 if (!equals(*first_function_decl(), *second_function_decl(), &k))
10387 return k & LOCAL_CHANGE_KIND;
10391 /// A comparison functor to compare two instances of @ref fn_parm_diff
10392 /// based on their indexes.
10393 struct fn_parm_diff_comp
10395 /// @param f the first diff
10397 /// @param s the second diff
10399 /// @return true if the index of @p f is less than the index of @p
10402 operator()(const fn_parm_diff& f, const fn_parm_diff& s)
10403 {return f.first_parameter()->get_index() < s.first_parameter()->get_index();}
10406 operator()(const fn_parm_diff_sptr& f, const fn_parm_diff_sptr& s)
10407 {return operator()(*f, *s);}
10408 }; // end struct fn_parm_diff_comp
10410 /// Sort a map of @ref fn_parm_diff by the indexes of the function
10413 /// @param map the map to sort.
10415 /// @param sorted the resulting sorted vector of changed function
10418 sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map,
10419 vector<fn_parm_diff_sptr>& sorted)
10421 sorted.reserve(map.size());
10422 for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
10425 sorted.push_back(i->second);
10427 fn_parm_diff_comp comp;
10428 std::sort(sorted.begin(), sorted.end(), comp);
10431 /// Sort a map of changed function parameters by the indexes of the
10432 /// function parameters.
10434 /// @param map the map to sort.
10436 /// @param sorted the resulting sorted vector of instances of @ref
10437 /// fn_parm_diff_sptr
10439 sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map& map,
10440 vector<fn_parm_diff_sptr>& sorted)
10442 sorted.reserve(map.size());
10443 for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
10446 sorted.push_back(i->second);
10448 fn_parm_diff_comp comp;
10449 std::sort(sorted.begin(), sorted.end(), comp);
10452 /// Functor that compares two function parameters for the purpose of
10456 /// Returns true iff the index of the first parameter is smaller
10457 /// than the of the second parameter.
10459 /// @param l the first parameter to compare.
10461 /// @param r the second parameter to compare.
10463 /// @return true iff the index of the first parameter is smaller
10464 /// than the of the second parameter.
10466 operator()(const function_decl::parameter& l,
10467 const function_decl::parameter& r)
10468 {return l.get_index() < r.get_index();}
10470 /// Returns true iff the index of the first parameter is smaller
10471 /// than the of the second parameter.
10473 /// @param l the first parameter to compare.
10475 /// @param r the second parameter to compare.
10477 /// @return true iff the index of the first parameter is smaller
10478 /// than the of the second parameter.
10480 operator()(const function_decl::parameter_sptr& l,
10481 const function_decl::parameter_sptr& r)
10482 {return operator()(*l, *r);}
10483 }; // end struct parm_comp
10485 /// Sort a map of string -> function parameters.
10487 /// @param map the map to sort.
10489 /// @param sorted the resulting sorted vector of
10490 /// @ref vector<function_decl::parameter_sptr>
10492 sort_string_parm_map(const string_parm_map& map,
10493 vector<function_decl::parameter_sptr>& sorted)
10495 for (string_parm_map::const_iterator i = map.begin();
10498 sorted.push_back(i->second);
10500 // TODO: finish this.
10502 std::sort(sorted.begin(), sorted.end(), comp);
10505 /// Serialize a report of the changes encapsulated in the current
10506 /// instance of function_decl_diff over to an output stream.
10508 /// @param out the output stream to serialize the report to.
10510 /// @param indent the string to use an an indentation prefix.
10512 function_decl_diff::report(ostream& out, const string& indent) const
10514 if (!to_be_reported())
10517 maybe_report_diff_for_member(first_function_decl(),
10518 second_function_decl(),
10519 context(), out, indent);
10521 function_decl_sptr ff = first_function_decl();
10522 function_decl_sptr sf = second_function_decl();
10524 diff_context_sptr ctxt = context();
10525 corpus_sptr fc = ctxt->get_first_corpus();
10526 corpus_sptr sc = ctxt->get_second_corpus();
10528 string qn1 = ff->get_qualified_name(), qn2 = sf->get_qualified_name(),
10529 linkage_names1, linkage_names2;
10530 elf_symbol_sptr s1 = ff->get_symbol(), s2 = sf->get_symbol();
10533 linkage_names1 = s1->get_id_string();
10535 linkage_names2 = s2->get_id_string();
10537 // If the symbols for ff and sf have aliases, get all the names of
10541 s1->get_aliases_id_string(fc->get_fun_symbol_map());
10544 s2->get_aliases_id_string(sc->get_fun_symbol_map());
10546 /// If the set of linkage names of the function have changed, report
10548 if (linkage_names1 != linkage_names2)
10550 if (linkage_names1.empty())
10552 out << indent << ff->get_pretty_representation()
10553 << " didn't have any linkage name, and it now has: '"
10554 << linkage_names2 << "'\n";
10556 else if (linkage_names2.empty())
10558 out << indent << ff->get_pretty_representation()
10559 << " did have linkage names '" << linkage_names1
10561 << indent << "but it doesn't have any linkage name anymore\n";
10564 out << indent << "linkage names of "
10565 << ff->get_pretty_representation()
10566 << "\n" << indent << "changed from '"
10567 << linkage_names1 << "' to '" << linkage_names2 << "'\n";
10572 string frep1 = first_function_decl()->get_pretty_representation(),
10573 frep2 = second_function_decl()->get_pretty_representation();
10574 out << indent << "'" << frep1 << " {" << linkage_names1<< "}"
10575 << "' now becomes '"
10576 << frep2 << " {" << linkage_names2 << "}" << "'\n";
10580 // Now report about inline-ness changes
10581 if (ff->is_declared_inline() != sf->is_declared_inline())
10584 if (ff->is_declared_inline())
10585 out << sf->get_pretty_representation()
10586 << " is not declared inline anymore\n";
10588 out << sf->get_pretty_representation()
10589 << " is now declared inline\n";
10592 // Report about vtable offset changes.
10593 if (is_member_function(ff) && is_member_function(sf))
10595 bool ff_is_virtual = get_member_function_is_virtual(ff),
10596 sf_is_virtual = get_member_function_is_virtual(sf);
10597 if (ff_is_virtual != sf_is_virtual)
10601 out << ff->get_pretty_representation()
10602 << " is no more declared virtual\n";
10604 out << ff->get_pretty_representation()
10605 << " is now declared virtual\n";
10608 size_t ff_vtable_offset = get_member_function_vtable_offset(ff),
10609 sf_vtable_offset = get_member_function_vtable_offset(sf);
10610 if (ff_is_virtual && sf_is_virtual
10611 && (ff_vtable_offset != sf_vtable_offset))
10614 << "the vtable offset of " << ff->get_pretty_representation()
10615 << " changed from " << ff_vtable_offset
10616 << " to " << sf_vtable_offset << "\n";
10620 // Report about function type differences.
10621 if (type_diff() && type_diff()->to_be_reported())
10622 type_diff()->report(out, indent);
10625 /// Compute the diff between two function_decl.
10627 /// @param first the first function_decl to consider for the diff
10629 /// @param second the second function_decl to consider for the diff
10631 /// @param ctxt the diff context to use.
10633 /// @return the computed diff
10634 function_decl_diff_sptr
10635 compute_diff(const function_decl_sptr first,
10636 const function_decl_sptr second,
10637 diff_context_sptr ctxt)
10639 if (!first || !second)
10641 // TODO: implement this for either first or second being NULL.
10642 return function_decl_diff_sptr();
10645 function_type_diff_sptr type_diff = compute_diff(first->get_type(),
10646 second->get_type(),
10649 function_decl_diff_sptr result(new function_decl_diff(first, second,
10651 result->priv_->type_diff_ = type_diff;
10653 result->ensure_lookup_tables_populated();
10655 ctxt->initialize_canonical_diff(result);
10660 // </function_decl_diff stuff>
10662 // <type_decl_diff stuff>
10664 /// Constructor for type_decl_diff.
10665 type_decl_diff::type_decl_diff(const type_decl_sptr first,
10666 const type_decl_sptr second,
10667 diff_context_sptr ctxt)
10668 : type_diff_base(first, second, ctxt)
10671 /// Finish building the current instance of @ref type_decl_diff.
10673 type_decl_diff::finish_diff_type()
10675 if (diff::priv_->finished_)
10677 diff::priv_->finished_ = true;
10680 /// Getter for the first subject of the type_decl_diff.
10682 /// @return the first type_decl involved in the diff.
10683 const type_decl_sptr
10684 type_decl_diff::first_type_decl() const
10685 {return dynamic_pointer_cast<type_decl>(first_subject());}
10687 /// Getter for the second subject of the type_decl_diff.
10689 /// @return the second type_decl involved in the diff.
10690 const type_decl_sptr
10691 type_decl_diff::second_type_decl() const
10692 {return dynamic_pointer_cast<type_decl>(second_subject());}
10694 /// @return the pretty representation for the current instance of @ref
10695 /// type_decl_diff.
10697 type_decl_diff::get_pretty_representation() const
10699 if (diff::priv_->pretty_representation_.empty())
10701 std::ostringstream o;
10702 o << "type_decl_diff["
10703 << first_subject()->get_pretty_representation()
10705 << second_subject()->get_pretty_representation()
10707 diff::priv_->pretty_representation_ = o.str();
10709 return diff::priv_->pretty_representation_;
10711 /// Return true iff the current diff node carries a change.
10713 /// @return true iff the current diff node carries a change.
10715 type_decl_diff::has_changes() const
10716 {return first_type_decl() != second_type_decl();}
10718 /// @return true iff the current diff node carries local changes.
10720 type_decl_diff::has_local_changes() const
10722 ir::change_kind k = ir::NO_CHANGE_KIND;
10723 if (!equals(*first_type_decl(), *second_type_decl(), &k))
10724 return k & LOCAL_CHANGE_KIND;
10727 /// Ouputs a report of the differences between of the two type_decl
10728 /// involved in the type_decl_diff.
10730 /// @param out the output stream to emit the report to.
10732 /// @param indent the string to use for indentatino indent.
10734 type_decl_diff::report(ostream& out, const string& indent) const
10736 if (!to_be_reported())
10739 type_decl_sptr f = first_type_decl(), s = second_type_decl();
10741 string name = f->get_pretty_representation();
10743 bool n = report_name_size_and_alignment_changes(f, s, context(),
10745 /*new line=*/false);
10747 if (f->get_visibility() != s->get_visibility())
10752 << "visibility changed from '"
10753 << f->get_visibility() << "' to '" << s->get_visibility();
10757 if (f->get_linkage_name() != s->get_linkage_name())
10762 << "mangled name changed from '"
10763 << f->get_linkage_name() << "' to "
10764 << s->get_linkage_name();
10772 /// Compute a diff between two type_decl.
10774 /// This function doesn't actually compute a diff. As a type_decl is
10775 /// very simple (unlike compound constructs like function_decl or
10776 /// class_decl) it's easy to just compare the components of the
10777 /// type_decl to know what has changed. Thus this function just
10778 /// builds and return a type_decl_diff object. The
10779 /// type_decl_diff::report function will just compare the components
10780 /// of the the two type_decl and display where and how they differ.
10782 /// @param first a pointer to the first type_decl to
10785 /// @param second a pointer to the second type_decl to consider.
10787 /// @param ctxt the diff context to use.
10789 /// @return a pointer to the resulting type_decl_diff.
10790 type_decl_diff_sptr
10791 compute_diff(const type_decl_sptr first,
10792 const type_decl_sptr second,
10793 diff_context_sptr ctxt)
10795 type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
10797 // We don't need to actually compute a diff here as a type_decl
10798 // doesn't have complicated sub-components. type_decl_diff::report
10799 // just walks the members of the type_decls and display information
10800 // about the ones that have changed. On a similar note,
10801 // type_decl_diff::length returns 0 if the two type_decls are equal,
10802 // and 1 otherwise.
10804 ctxt->initialize_canonical_diff(result);
10809 // </type_decl_diff stuff>
10811 // <typedef_diff stuff>
10813 struct typedef_diff::priv
10815 diff_sptr underlying_type_diff_;
10817 priv(const diff_sptr underlying_type_diff)
10818 : underlying_type_diff_(underlying_type_diff)
10820 };//end struct typedef_diff::priv
10822 /// Populate the vector of children node of the @ref diff base type
10823 /// sub-object of this instance of @ref typedef_diff.
10825 /// The children node can then later be retrieved using
10826 /// diff::children_node().
10828 typedef_diff::chain_into_hierarchy()
10829 {append_child_node(underlying_type_diff());}
10831 /// Constructor for typedef_diff.
10832 typedef_diff::typedef_diff(const typedef_decl_sptr first,
10833 const typedef_decl_sptr second,
10834 const diff_sptr underlying,
10835 diff_context_sptr ctxt)
10836 : type_diff_base(first, second, ctxt),
10837 priv_(new priv(underlying))
10840 /// Finish building the current instance of @ref typedef_diff.
10842 typedef_diff::finish_diff_type()
10844 if (diff::priv_->finished_)
10846 chain_into_hierarchy();
10847 diff::priv_->finished_ = true;
10850 /// Getter for the firt typedef_decl involved in the diff.
10852 /// @return the first subject of the diff.
10853 const typedef_decl_sptr
10854 typedef_diff::first_typedef_decl() const
10855 {return dynamic_pointer_cast<typedef_decl>(first_subject());}
10857 /// Getter for the second typedef_decl involved in the diff.
10859 /// @return the second subject of the diff.
10860 const typedef_decl_sptr
10861 typedef_diff::second_typedef_decl() const
10862 {return dynamic_pointer_cast<typedef_decl>(second_subject());}
10864 /// Getter for the diff between the two underlying types of the
10867 /// @return the diff object reprensenting the difference between the
10868 /// two underlying types of the typedefs.
10870 typedef_diff::underlying_type_diff() const
10871 {return priv_->underlying_type_diff_;}
10873 /// Setter for the diff between the two underlying types of the
10876 /// @param d the new diff object reprensenting the difference between
10877 /// the two underlying types of the typedefs.
10879 typedef_diff::underlying_type_diff(const diff_sptr d)
10880 {priv_->underlying_type_diff_ = d;}
10882 /// @return the pretty representation for the current instance of @ref
10885 typedef_diff::get_pretty_representation() const
10887 if (diff::priv_->pretty_representation_.empty())
10889 std::ostringstream o;
10890 o << "typedef_diff["
10891 << first_subject()->get_pretty_representation()
10893 << second_subject()->get_pretty_representation()
10895 diff::priv_->pretty_representation_ = o.str();
10897 return diff::priv_->pretty_representation_;
10900 /// Return true iff the current diff node carries a change.
10902 /// @return true iff the current diff node carries a change.
10904 typedef_diff::has_changes() const
10906 decl_base_sptr second = second_typedef_decl();
10907 return !(*first_typedef_decl() == *second);
10910 /// @return true iff the current diff node carries local changes.
10912 typedef_diff::has_local_changes() const
10914 ir::change_kind k = ir::NO_CHANGE_KIND;
10915 if (!equals(*first_typedef_decl(), *second_typedef_decl(), &k))
10916 return k & LOCAL_CHANGE_KIND;
10920 /// Reports the difference between the two subjects of the diff in a
10921 /// serialized form.
10923 /// @param out the output stream to emit the report to.
10925 /// @param indent the indentation string to use.
10927 typedef_diff::report(ostream& out, const string& indent) const
10929 if (!to_be_reported())
10932 bool emit_nl = false;
10933 typedef_decl_sptr f = first_typedef_decl(), s = second_typedef_decl();
10935 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(f, s);
10937 maybe_report_diff_for_member(f, s, context(), out, indent);
10939 if (filtering::has_harmless_name_change(f, s)
10940 && context()->get_allowed_category() & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
10942 out << indent << "typedef name changed from "
10943 << f->get_qualified_name()
10945 << s->get_qualified_name()
10950 diff_sptr d = underlying_type_diff();
10951 if (d && d->to_be_reported())
10953 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(d, "underlying type");
10955 << "underlying type '"
10956 << d->first_subject()->get_pretty_representation()
10958 d->report(out, indent + " ");
10966 /// Compute a diff between two typedef_decl.
10968 /// @param first a pointer to the first typedef_decl to consider.
10970 /// @param second a pointer to the second typedef_decl to consider.
10972 /// @param ctxt the diff context to use.
10974 /// @return a pointer to the the resulting typedef_diff.
10976 compute_diff(const typedef_decl_sptr first,
10977 const typedef_decl_sptr second,
10978 diff_context_sptr ctxt)
10980 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
10981 second->get_underlying_type(),
10983 typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
10985 ctxt->initialize_canonical_diff(result);
10990 // </typedef_diff stuff>
10992 // <translation_unit_diff stuff>
10994 struct translation_unit_diff::priv
10996 translation_unit_sptr first_;
10997 translation_unit_sptr second_;
10999 priv(translation_unit_sptr f, translation_unit_sptr s)
11000 : first_(f), second_(s)
11002 };//end struct translation_unit_diff::priv
11004 /// Constructor for translation_unit_diff.
11006 /// @param first the first translation unit to consider for this diff.
11008 /// @param second the second translation unit to consider for this diff.
11009 translation_unit_diff::translation_unit_diff(translation_unit_sptr first,
11010 translation_unit_sptr second,
11011 diff_context_sptr ctxt)
11012 : scope_diff(first->get_global_scope(), second->get_global_scope(), ctxt),
11013 priv_(new priv(first, second))
11017 /// Getter for the first translation unit of this diff.
11019 /// @return the first translation unit of this diff.
11020 const translation_unit_sptr
11021 translation_unit_diff::first_translation_unit() const
11022 {return priv_->first_;}
11024 /// Getter for the second translation unit of this diff.
11026 /// @return the second translation unit of this diff.
11027 const translation_unit_sptr
11028 translation_unit_diff::second_translation_unit() const
11029 {return priv_->second_;}
11031 /// Return true iff the current diff node carries a change.
11033 /// @return true iff the current diff node carries a change.
11035 translation_unit_diff::has_changes() const
11036 {return scope_diff::has_changes();}
11038 /// @return true iff the current diff node carries local changes.
11040 translation_unit_diff::has_local_changes() const
11043 /// Report the diff in a serialized form.
11045 /// @param out the output stream to serialize the report to.
11047 /// @param indent the prefix to use as indentation for the report.
11049 translation_unit_diff::report(ostream& out, const string& indent) const
11050 {scope_diff::report(out, indent);}
11052 /// Compute the diff between two translation_units.
11054 /// @param first the first translation_unit to consider.
11056 /// @param second the second translation_unit to consider.
11058 /// @param ctxt the diff context to use. If null, this function will
11059 /// create a new context and set to the diff object returned.
11061 /// @return the newly created diff object.
11062 translation_unit_diff_sptr
11063 compute_diff(const translation_unit_sptr first,
11064 const translation_unit_sptr second,
11065 diff_context_sptr ctxt)
11068 ctxt.reset(new diff_context);
11070 // TODO: handle first or second having empty contents.
11071 translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
11073 scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
11075 compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
11076 static_pointer_cast<scope_decl>(second->get_global_scope()),
11080 ctxt->initialize_canonical_diff(tu_diff);
11085 // </translation_unit_diff stuff>
11087 /// The type of the private data of corpus_diff::diff_stats.
11088 class corpus_diff::diff_stats::priv
11090 friend class corpus_diff::diff_stats;
11092 size_t num_func_removed;
11093 size_t num_func_added;
11094 size_t num_func_changed;
11095 size_t num_func_filtered_out;
11096 size_t num_vars_removed;
11097 size_t num_vars_added;
11098 size_t num_vars_changed;
11099 size_t num_vars_filtered_out;
11100 size_t num_func_syms_removed;
11101 size_t num_func_syms_added;
11102 size_t num_var_syms_removed;
11103 size_t num_var_syms_added;
11106 : num_func_removed(0),
11108 num_func_changed(0),
11109 num_func_filtered_out(0),
11110 num_vars_removed(0),
11112 num_vars_changed(0),
11113 num_vars_filtered_out(0),
11114 num_func_syms_removed(0),
11115 num_func_syms_added(0),
11116 num_var_syms_removed(0),
11117 num_var_syms_added(0)
11119 }; // end class corpus_diff::diff_stats::priv
11121 /// Default constructor for the @ref diff_stat type.
11122 corpus_diff::diff_stats::diff_stats()
11126 /// Getter for the number of functions removed.
11128 /// @return the number of functions removed.
11130 corpus_diff::diff_stats::num_func_removed() const
11131 {return priv_->num_func_removed;}
11133 /// Setter for the number of functions removed.
11135 /// @param n the new number of functions removed.
11137 corpus_diff::diff_stats::num_func_removed(size_t n)
11138 {priv_->num_func_removed = n;}
11140 /// Getter for the number of functions added.
11142 /// @return the number of functions added.
11144 corpus_diff::diff_stats::num_func_added() const
11145 {return priv_->num_func_added;}
11147 /// Setter for the number of functions added.
11149 /// @param n the new number of functions added.
11151 corpus_diff::diff_stats::num_func_added(size_t n)
11152 {priv_->num_func_added = n;}
11154 /// Getter for the number of functions that have a change in one of
11155 /// their sub-types.
11157 /// @return the number of functions that have a change in one of their
11160 corpus_diff::diff_stats::num_func_changed() const
11161 {return priv_->num_func_changed;}
11163 /// Setter for the number of functions that have a change in one of
11164 /// their sub-types.
11166 /// @@param n the new number of functions that have a change in one of
11167 /// their sub-types.
11169 corpus_diff::diff_stats::num_func_changed(size_t n)
11170 {priv_->num_func_changed = n;}
11172 /// Getter for the number of functions that have a change in one of
11173 /// their sub-types, and that have been filtered out.
11175 /// @return the number of functions that have a change in one of their
11176 /// sub-types, and that have been filtered out.
11178 corpus_diff::diff_stats::num_func_filtered_out() const
11179 {return priv_->num_func_filtered_out;}
11181 /// Setter for the number of functions that have a change in one of
11182 /// their sub-types, and that have been filtered out.
11184 /// @param n the new number of functions that have a change in one of their
11185 /// sub-types, and that have been filtered out.
11187 corpus_diff::diff_stats::num_func_filtered_out(size_t n)
11188 {priv_->num_func_filtered_out = n;}
11190 /// Getter for the number of functions that have a change in their
11191 /// sub-types, minus the number of these functions that got filtered
11192 /// out from the diff.
11194 /// @return for the the number of functions that have a change in
11195 /// their sub-types, minus the number of these functions that got
11196 /// filtered out from the diff.
11198 corpus_diff::diff_stats::net_num_func_changed() const
11199 {return num_func_changed() - num_func_filtered_out();}
11201 /// Getter for the number of variables removed.
11203 /// @return the number of variables removed.
11205 corpus_diff::diff_stats::num_vars_removed() const
11206 {return priv_->num_vars_removed;}
11208 /// Setter for the number of variables removed.
11210 /// @param n the new number of variables removed.
11212 corpus_diff::diff_stats::num_vars_removed(size_t n)
11213 {priv_->num_vars_removed = n;}
11215 /// Getter for the number of variables added.
11217 /// @return the number of variables added.
11219 corpus_diff::diff_stats::num_vars_added() const
11220 {return priv_->num_vars_added;}
11222 /// Setter for the number of variables added.
11224 /// @param n the new number of variables added.
11226 corpus_diff::diff_stats::num_vars_added(size_t n)
11227 {priv_->num_vars_added = n;}
11229 /// Getter for the number of variables that have a change in one of
11230 /// their sub-types.
11232 /// @return the number of variables that have a change in one of their
11235 corpus_diff::diff_stats::num_vars_changed() const
11236 {return priv_->num_vars_changed;}
11238 /// Setter for the number of variables that have a change in one of
11239 /// their sub-types.
11241 /// @param n the new number of variables that have a change in one of
11242 /// their sub-types.
11244 corpus_diff::diff_stats::num_vars_changed(size_t n)
11245 {priv_->num_vars_changed = n;}
11247 /// Getter for the number of variables that have a change in one of
11248 /// their sub-types, and that have been filtered out.
11250 /// @return the number of functions that have a change in one of their
11251 /// sub-types, and that have been filtered out.
11253 corpus_diff::diff_stats::num_vars_filtered_out() const
11254 {return priv_->num_vars_filtered_out;}
11256 /// Setter for the number of variables that have a change in one of
11257 /// their sub-types, and that have been filtered out.
11259 /// @param n the new number of variables that have a change in one of their
11260 /// sub-types, and that have been filtered out.
11262 corpus_diff::diff_stats::num_vars_filtered_out(size_t n)
11263 {priv_->num_vars_filtered_out = n;}
11265 /// Getter for the number of variables that have a change in their
11266 /// sub-types, minus the number of these variables that got filtered
11267 /// out from the diff.
11269 /// @return for the the number of variables that have a change in
11270 /// their sub-types, minus the number of these variables that got
11271 /// filtered out from the diff.
11273 corpus_diff::diff_stats::net_num_vars_changed() const
11274 {return num_vars_changed() - num_vars_filtered_out();}
11276 /// Getter for the number of function symbols (not referenced by any
11277 /// debug info) that got removed.
11279 /// @return the number of function symbols (not referenced by any
11280 /// debug info) that got removed.
11282 corpus_diff::diff_stats::num_func_syms_removed() const
11283 {return priv_->num_func_syms_removed;}
11285 /// Setter for the number of function symbols (not referenced by any
11286 /// debug info) that got removed.
11288 /// @param n the number of function symbols (not referenced by any
11289 /// debug info) that got removed.
11291 corpus_diff::diff_stats::num_func_syms_removed(size_t n)
11292 {priv_->num_func_syms_removed = n;}
11294 /// Getter for the number of function symbols (not referenced by any
11295 /// debug info) that got added.
11297 /// @return the number of function symbols (not referenced by any
11298 /// debug info) that got added.
11300 corpus_diff::diff_stats::num_func_syms_added() const
11301 {return priv_->num_func_syms_added;}
11303 /// Setter for the number of function symbols (not referenced by any
11304 /// debug info) that got added.
11306 /// @param n the new number of function symbols (not referenced by any
11307 /// debug info) that got added.
11309 corpus_diff::diff_stats::num_func_syms_added(size_t n)
11310 {priv_->num_func_syms_added = n;}
11312 /// Getter for the number of variable symbols (not referenced by any
11313 /// debug info) that got removed.
11315 /// @return the number of variable symbols (not referenced by any
11316 /// debug info) that got removed.
11318 corpus_diff::diff_stats::num_var_syms_removed() const
11319 {return priv_->num_var_syms_removed;}
11321 /// Setter for the number of variable symbols (not referenced by any
11322 /// debug info) that got removed.
11324 /// @param n the number of variable symbols (not referenced by any
11325 /// debug info) that got removed.
11327 corpus_diff::diff_stats::num_var_syms_removed(size_t n)
11328 {priv_->num_var_syms_removed = n;}
11330 /// Getter for the number of variable symbols (not referenced by any
11331 /// debug info) that got added.
11333 /// @return the number of variable symbols (not referenced by any
11334 /// debug info) that got added.
11336 corpus_diff::diff_stats::num_var_syms_added() const
11337 {return priv_->num_var_syms_added;}
11339 /// Setter for the number of variable symbols (not referenced by any
11340 /// debug info) that got added.
11342 /// @param n the new number of variable symbols (not referenced by any
11343 /// debug info) that got added.
11345 corpus_diff::diff_stats::num_var_syms_added(size_t n)
11346 {priv_->num_var_syms_added = n;}
11349 struct corpus_diff::priv
11352 string pretty_representation_;
11353 vector<diff_sptr> children_;
11354 diff_context_sptr ctxt_;
11355 corpus_sptr first_;
11356 corpus_sptr second_;
11357 corpus_diff::diff_stats diff_stats_;
11358 bool filters_and_suppr_applied_;
11359 bool sonames_equal_;
11360 bool architectures_equal_;
11361 edit_script fns_edit_script_;
11362 edit_script vars_edit_script_;
11363 edit_script unrefed_fn_syms_edit_script_;
11364 edit_script unrefed_var_syms_edit_script_;
11365 string_function_ptr_map deleted_fns_;
11366 string_function_ptr_map added_fns_;
11367 string_function_decl_diff_sptr_map changed_fns_map_;
11368 function_decl_diff_sptrs_type changed_fns_;
11369 string_var_ptr_map deleted_vars_;
11370 string_var_ptr_map added_vars_;
11371 string_var_diff_sptr_map changed_vars_map_;
11372 var_diff_sptrs_type sorted_changed_vars_;
11373 string_elf_symbol_map added_unrefed_fn_syms_;
11374 string_elf_symbol_map deleted_unrefed_fn_syms_;
11375 string_elf_symbol_map added_unrefed_var_syms_;
11376 string_elf_symbol_map deleted_unrefed_var_syms_;
11379 : finished_(false),
11380 filters_and_suppr_applied_(false),
11381 sonames_equal_(false),
11382 architectures_equal_(false)
11386 lookup_tables_empty() const;
11389 clear_lookup_tables();
11392 ensure_lookup_tables_populated();
11395 apply_filters_and_compute_diff_stats(corpus_diff::diff_stats&);
11398 emit_diff_stats(const diff_stats& stats,
11400 const string& indent);
11403 categorize_redundant_changed_sub_nodes();
11406 clear_redundancy_categorization();
11409 maybe_dump_diff_tree();
11410 }; // end corpus::priv
11412 /// Tests if the lookup tables are empty.
11414 /// @return true if the lookup tables are empty, false otherwise.
11416 corpus_diff::priv::lookup_tables_empty() const
11418 return (deleted_fns_.empty()
11419 && added_fns_.empty()
11420 && changed_fns_map_.empty()
11421 && deleted_vars_.empty()
11422 && added_vars_.empty()
11423 && changed_vars_map_.empty());
11426 /// Clear the lookup tables useful for reporting an enum_diff.
11428 corpus_diff::priv::clear_lookup_tables()
11430 deleted_fns_.clear();
11431 added_fns_.clear();
11432 changed_fns_map_.clear();
11433 deleted_vars_.clear();
11434 added_vars_.clear();
11435 changed_vars_map_.clear();
11438 /// If the lookup tables are not yet built, walk the differences and
11439 /// fill the lookup tables.
11441 corpus_diff::priv::ensure_lookup_tables_populated()
11443 if (!lookup_tables_empty())
11447 edit_script& e = fns_edit_script_;
11449 for (vector<deletion>::const_iterator it = e.deletions().begin();
11450 it != e.deletions().end();
11453 unsigned i = it->index();
11454 assert(i < first_->get_functions().size());
11456 function_decl* deleted_fn = first_->get_functions()[i];
11457 string n = deleted_fn->get_id();
11458 assert(!n.empty());
11459 assert(deleted_fns_.find(n) == deleted_fns_.end());
11460 deleted_fns_[n] = deleted_fn;
11463 for (vector<insertion>::const_iterator it = e.insertions().begin();
11464 it != e.insertions().end();
11467 for (vector<unsigned>::const_iterator iit =
11468 it->inserted_indexes().begin();
11469 iit != it->inserted_indexes().end();
11473 function_decl* added_fn = second_->get_functions()[i];
11474 string n = added_fn->get_id();
11475 assert(!n.empty());
11476 assert(added_fns_.find(n) == added_fns_.end());
11477 string_function_ptr_map::const_iterator j =
11478 deleted_fns_.find(n);
11479 if (j != deleted_fns_.end())
11481 function_decl_sptr f(j->second, noop_deleter());
11482 function_decl_sptr s(added_fn, noop_deleter());
11483 function_decl_diff_sptr d = compute_diff(f, s, ctxt_);
11484 if (*j->second != *added_fn)
11485 changed_fns_map_[j->first] = d;
11486 deleted_fns_.erase(j);
11489 added_fns_[n] = added_fn;
11492 sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
11494 // Now walk the allegedly deleted functions; check if their
11495 // underlying symbols are deleted as well; otherwise, consider
11496 // that the function in question hasn't been deleted.
11498 vector<string> to_delete;
11499 for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
11500 i != deleted_fns_.end();
11502 if (second_->lookup_function_symbol(i->second->get_symbol()->get_name(),
11503 i->second->get_symbol()->get_version().str()))
11504 to_delete.push_back(i->first);
11506 for (vector<string>::const_iterator i = to_delete.begin();
11507 i != to_delete.end();
11509 deleted_fns_.erase(*i);
11511 // Do something similar for added functions.
11514 for (string_function_ptr_map::const_iterator i = added_fns_.begin();
11515 i != added_fns_.end();
11517 if (first_->lookup_function_symbol(i->second->get_symbol()->get_name(),
11518 i->second->get_symbol()->get_version().str()))
11519 to_delete.push_back(i->first);
11521 for (vector<string>::const_iterator i = to_delete.begin();
11522 i != to_delete.end();
11524 added_fns_.erase(*i);
11528 edit_script& e = vars_edit_script_;
11530 for (vector<deletion>::const_iterator it = e.deletions().begin();
11531 it != e.deletions().end();
11534 unsigned i = it->index();
11535 assert(i < first_->get_variables().size());
11537 var_decl* deleted_var = first_->get_variables()[i];
11538 string n = deleted_var->get_id();
11539 assert(!n.empty());
11540 assert(deleted_vars_.find(n) == deleted_vars_.end());
11541 deleted_vars_[n] = deleted_var;
11544 for (vector<insertion>::const_iterator it = e.insertions().begin();
11545 it != e.insertions().end();
11548 for (vector<unsigned>::const_iterator iit =
11549 it->inserted_indexes().begin();
11550 iit != it->inserted_indexes().end();
11554 var_decl* added_var = second_->get_variables()[i];
11555 string n = added_var->get_id();
11556 assert(!n.empty());
11558 string_var_ptr_map::const_iterator k = added_vars_.find(n);
11559 if ( k != added_vars_.end())
11561 assert(is_member_decl(k->second)
11562 && get_member_is_static(k->second));
11566 string_var_ptr_map::const_iterator j =
11567 deleted_vars_.find(n);
11568 if (j != deleted_vars_.end())
11570 if (*j->second != *added_var)
11572 var_decl_sptr f(j->second, noop_deleter());
11573 var_decl_sptr s(added_var, noop_deleter());
11574 changed_vars_map_[n] = compute_diff(f, s, ctxt_);
11576 deleted_vars_.erase(j);
11579 added_vars_[n] = added_var;
11582 sort_string_var_diff_sptr_map(changed_vars_map_,
11583 sorted_changed_vars_);
11585 // Now walk the allegedly deleted variables; check if their
11586 // underlying symbols are deleted as well; otherwise consider
11587 // that the variable in question hasn't been deleted.
11589 vector<string> to_delete;
11590 for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
11591 i != deleted_vars_.end();
11593 if (second_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
11594 i->second->get_symbol()->get_version().str()))
11595 to_delete.push_back(i->first);
11597 for (vector<string>::const_iterator i = to_delete.begin();
11598 i != to_delete.end();
11600 deleted_fns_.erase(*i);
11602 // Do something similar for added variables.
11605 for (string_var_ptr_map::const_iterator i = added_vars_.begin();
11606 i != added_vars_.end();
11608 if (first_->lookup_variable_symbol(i->second->get_symbol()->get_name(),
11609 i->second->get_symbol()->get_version().str()))
11610 to_delete.push_back(i->first);
11612 for (vector<string>::const_iterator i = to_delete.begin();
11613 i != to_delete.end();
11615 added_vars_.erase(*i);
11618 // Massage the edit script for added/removed function symbols that
11619 // were not referenced by any debug info and turn them into maps of
11620 // {symbol_name, symbol}.
11622 edit_script& e = unrefed_fn_syms_edit_script_;
11623 for (vector<deletion>::const_iterator it = e.deletions().begin();
11624 it != e.deletions().end();
11627 unsigned i = it->index();
11628 assert(i < first_->get_unreferenced_function_symbols().size());
11629 elf_symbol_sptr deleted_sym =
11630 first_->get_unreferenced_function_symbols()[i];
11631 if (!second_->lookup_function_symbol(deleted_sym->get_name(),
11632 deleted_sym->get_version()))
11633 deleted_unrefed_fn_syms_[deleted_sym->get_id_string()] = deleted_sym;
11636 for (vector<insertion>::const_iterator it = e.insertions().begin();
11637 it != e.insertions().end();
11640 for (vector<unsigned>::const_iterator iit =
11641 it->inserted_indexes().begin();
11642 iit != it->inserted_indexes().end();
11646 assert(i < second_->get_unreferenced_function_symbols().size());
11647 elf_symbol_sptr added_sym =
11648 second_->get_unreferenced_function_symbols()[i];
11649 if ((deleted_unrefed_fn_syms_.find(added_sym->get_id_string())
11650 == deleted_unrefed_fn_syms_.end()))
11652 if (!first_->lookup_function_symbol(added_sym->get_name(),
11653 added_sym->get_version()))
11654 added_unrefed_fn_syms_[added_sym->get_id_string()] =
11658 deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
11663 // Massage the edit script for added/removed variable symbols that
11664 // were not referenced by any debug info and turn them into maps of
11665 // {symbol_name, symbol}.
11667 edit_script& e = unrefed_var_syms_edit_script_;
11668 for (vector<deletion>::const_iterator it = e.deletions().begin();
11669 it != e.deletions().end();
11672 unsigned i = it->index();
11673 assert(i < first_->get_unreferenced_variable_symbols().size());
11674 elf_symbol_sptr deleted_sym =
11675 first_->get_unreferenced_variable_symbols()[i];
11676 if (!second_->lookup_variable_symbol(deleted_sym->get_name(),
11677 deleted_sym->get_version()))
11678 deleted_unrefed_var_syms_[deleted_sym->get_id_string()] = deleted_sym;
11681 for (vector<insertion>::const_iterator it = e.insertions().begin();
11682 it != e.insertions().end();
11685 for (vector<unsigned>::const_iterator iit =
11686 it->inserted_indexes().begin();
11687 iit != it->inserted_indexes().end();
11691 assert(i < second_->get_unreferenced_variable_symbols().size());
11692 elf_symbol_sptr added_sym =
11693 second_->get_unreferenced_variable_symbols()[i];
11694 if (deleted_unrefed_var_syms_.find(added_sym->get_id_string())
11695 == deleted_unrefed_var_syms_.end())
11697 if (!first_->lookup_variable_symbol(added_sym->get_name(),
11698 added_sym->get_version()))
11699 added_unrefed_var_syms_[added_sym->get_id_string()] =
11703 deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
11709 /// Compute the diff stats.
11711 /// To know the number of functions that got filtered out, this
11712 /// function applies the categorizing filters to the diff sub-trees of
11713 /// each function changes diff, prior to calculating the stats.
11715 /// @param num_removed the number of removed functions.
11717 /// @param num_added the number of added functions.
11719 /// @param num_changed the number of changed functions.
11721 /// @param num_filtered_out the number of changed functions that are
11722 /// got filtered out from the report
11724 corpus_diff::priv::apply_filters_and_compute_diff_stats(diff_stats& stat)
11727 stat.num_func_removed(deleted_fns_.size());
11728 stat.num_func_added(added_fns_.size());
11729 stat.num_func_changed(changed_fns_map_.size());
11731 stat.num_vars_removed(deleted_vars_.size());
11732 stat.num_vars_added(added_vars_.size());
11733 stat.num_vars_changed(changed_vars_map_.size());
11735 // Walk the changed function diff nodes to apply the categorization
11738 for (function_decl_diff_sptrs_type::const_iterator i =
11739 changed_fns_.begin();
11740 i != changed_fns_.end();
11743 diff_sptr diff = *i;
11744 ctxt_->maybe_apply_filters(diff);
11747 // Walk the changed variable diff nodes to apply the categorization
11749 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11750 i != sorted_changed_vars_.end();
11753 diff_sptr diff = *i;
11754 ctxt_->maybe_apply_filters(diff);
11757 categorize_redundant_changed_sub_nodes();
11759 // Walk the changed function diff nodes to count the number of
11760 // filtered-out functions.
11761 for (function_decl_diff_sptrs_type::const_iterator i =
11762 changed_fns_.begin();
11763 i != changed_fns_.end();
11765 if ((*i)->is_filtered_out())
11766 stat.num_func_filtered_out(stat.num_func_filtered_out() + 1);
11768 // Walk the changed variables diff nodes to count the number of
11769 // filtered-out variables.
11770 for (var_diff_sptrs_type ::const_iterator i = sorted_changed_vars_.begin();
11771 i != sorted_changed_vars_.end();
11774 if ((*i)->is_filtered_out())
11775 stat.num_vars_filtered_out(stat.num_vars_filtered_out() + 1);
11778 stat.num_func_syms_added(added_unrefed_fn_syms_.size());
11779 stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
11780 stat.num_var_syms_added(added_unrefed_var_syms_.size());
11781 stat.num_var_syms_removed(deleted_unrefed_var_syms_.size());
11784 /// Emit the summary of the functions & variables that got
11785 /// removed/changed/added.
11787 /// @param out the output stream to emit the stats to.
11789 /// @param indent the indentation string to use in the summary.
11791 corpus_diff::priv::emit_diff_stats(const diff_stats& s,
11793 const string& indent)
11795 /// Report added/removed/changed functions.
11796 size_t total = s.num_func_removed() + s.num_func_added() +
11797 s.net_num_func_changed();
11799 if (!sonames_equal_)
11800 out << indent << "ELF SONAME changed\n";
11802 if (!architectures_equal_)
11803 out << indent << "ELF architecture changed\n";
11805 // function changes summary
11806 out << indent << "Functions changes summary: ";
11807 out << s.num_func_removed() << " Removed, ";
11808 out << s.num_func_changed() - s.num_func_filtered_out() << " Changed";
11809 if (s.num_func_filtered_out())
11810 out << " (" << s.num_func_filtered_out() << " filtered out)";
11812 out << s.num_func_added() << " Added ";
11814 out << "function\n";
11816 out << "functions\n";
11818 total = s.num_vars_removed() + s.num_vars_added() +
11819 s.net_num_vars_changed();
11821 // variables changes summary
11822 out << indent << "Variables changes summary: ";
11823 out << s.num_vars_removed() << " Removed, ";
11824 out << s.num_vars_changed() - s.num_vars_filtered_out() << " Changed";
11825 if (s.num_vars_filtered_out())
11826 out << " (" << s.num_vars_filtered_out() << " filtered out)";
11828 out << s.num_vars_added() << " Added ";
11830 out << "variable\n";
11832 out << "variables\n";
11834 if (ctxt_->show_symbols_unreferenced_by_debug_info()
11835 && (s.num_func_syms_removed()
11836 || s.num_func_syms_added()
11837 || s.num_var_syms_removed()
11838 || s.num_var_syms_added()))
11840 // function symbols changes summary.
11842 if (!ctxt_->show_added_symbols_unreferenced_by_debug_info()
11843 && s.num_func_syms_removed() == 0
11844 && s.num_func_syms_added() != 0)
11845 // If the only unreferenced function symbol change is function
11846 // syms that got added, but we were forbidden to show function
11847 // syms being added, do nothing.
11852 << "Function symbols changes summary: "
11853 << s.num_func_syms_removed() << " Removed, "
11854 << s.num_func_syms_added() << " Added function symbol";
11855 if (s.num_func_syms_added() + s.num_func_syms_removed() > 1)
11857 out << " not referenced by debug info\n";
11860 // variable symbol changes summary.
11862 if (!ctxt_->show_added_symbols_unreferenced_by_debug_info()
11863 && s.num_var_syms_removed() == 0
11864 && s.num_var_syms_added() != 0)
11865 // If the only unreferenced variable symbol change is variable
11866 // syms that got added, but we were forbidden to show variable
11867 // syms being added, do nothing.
11872 << "Variable symbols changes summary: "
11873 << s.num_var_syms_removed() << " Removed, "
11874 << s.num_var_syms_added() << " Added function symbol";
11875 if (s.num_var_syms_added() + s.num_var_syms_removed() > 1)
11877 out << " not referenced by debug info\n";
11882 /// Walk the changed functions and variables diff nodes to categorize
11883 /// redundant nodes.
11885 corpus_diff::priv::categorize_redundant_changed_sub_nodes()
11889 ctxt_->forget_visited_diffs();
11890 for (function_decl_diff_sptrs_type::const_iterator i =
11891 changed_fns_.begin();
11892 i!= changed_fns_.end();
11896 categorize_redundancy(diff);
11899 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11900 i!= sorted_changed_vars_.end();
11903 diff_sptr diff = *i;
11904 categorize_redundancy(diff);
11908 /// Walk the changed functions and variables diff nodes and clear the
11909 /// redundancy categorization they might carry.
11911 corpus_diff::priv::clear_redundancy_categorization()
11914 for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
11915 i!= changed_fns_.end();
11919 abigail::comparison::clear_redundancy_categorization(diff);
11922 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11923 i!= sorted_changed_vars_.end();
11927 abigail::comparison::clear_redundancy_categorization(diff);
11931 /// If the user asked to dump the diff tree node (for changed
11932 /// variables and functions) on the error output stream, then just do
11935 /// This function is used for debugging purposes.
11937 corpus_diff::priv::maybe_dump_diff_tree()
11939 if (!ctxt_->dump_diff_tree()
11940 || ctxt_->error_output_stream() == 0)
11943 if (!changed_fns_.empty())
11945 *ctxt_->error_output_stream() << "changed functions diff tree: \n\n";
11946 for (function_decl_diff_sptrs_type::const_iterator i =
11947 changed_fns_.begin();
11948 i != changed_fns_.end();
11952 print_diff_tree(d, *ctxt_->error_output_stream());
11956 if (!sorted_changed_vars_.empty())
11958 *ctxt_->error_output_stream() << "\nchanged variables diff tree: \n\n";
11959 for (var_diff_sptrs_type::const_iterator i =
11960 sorted_changed_vars_.begin();
11961 i != sorted_changed_vars_.end();
11965 print_diff_tree(d, *ctxt_->error_output_stream());
11970 /// Populate the vector of children node of the @ref corpus_diff type.
11972 /// The children node can then later be retrieved using
11973 /// corpus_diff::children_node().
11975 corpus_diff::chain_into_hierarchy()
11977 for (function_decl_diff_sptrs_type::const_iterator i =
11978 changed_functions_sorted().begin();
11979 i != changed_functions_sorted().end();
11981 if (diff_sptr d = *i)
11982 append_child_node(d);
11985 /// Constructor for @ref corpus_diff.
11987 /// @param first the first corpus of the diff.
11989 /// @param second the second corpus of the diff.
11991 /// @param ctxt the diff context to use.
11992 corpus_diff::corpus_diff(corpus_sptr first,
11993 corpus_sptr second,
11994 diff_context_sptr ctxt)
11997 priv_->first_ = first;
11998 priv_->second_ = second;
11999 priv_->ctxt_ = ctxt;
12002 /// Finish building the current instance of @ref corpus_diff.
12004 corpus_diff::finish_diff_type()
12006 if (priv_->finished_)
12008 chain_into_hierarchy();
12009 priv_->finished_ = true;
12012 /// @return the first corpus of the diff.
12014 corpus_diff::first_corpus() const
12015 {return priv_->first_;}
12017 /// @return the second corpus of the diff.
12019 corpus_diff::second_corpus() const
12020 {return priv_->second_;}
12022 /// @return the children nodes of the current instance of corpus_diff.
12023 const vector<diff_sptr>&
12024 corpus_diff::children_nodes() const
12025 {return priv_->children_;}
12027 /// Append a new child node to the vector of childre nodes for the
12028 /// current instance of @ref corpus_diff node.
12030 /// @param d the new child node. Note that the life time of the
12031 /// object held by @p d will thus equal the life time of the current
12032 /// instance of @ref corpus_diff.
12034 corpus_diff::append_child_node(diff_sptr d)
12037 priv_->children_.push_back(d);
12039 diff_less_than_functor comp;
12040 std::sort(priv_->children_.begin(),
12041 priv_->children_.end(),
12045 /// @return the bare edit script of the functions changed as recorded
12048 corpus_diff::function_changes() const
12049 {return priv_->fns_edit_script_;}
12051 /// @return the bare edit script of the variables changed as recorded
12054 corpus_diff::variable_changes() const
12055 {return priv_->vars_edit_script_;}
12057 /// Test if the soname of the underlying corpus has changed.
12059 /// @return true iff the soname has changed.
12061 corpus_diff::soname_changed() const
12062 {return !priv_->sonames_equal_;}
12064 /// Test if the architecture of the underlying corpus has changed.
12066 /// @return true iff the architecture has changed.
12068 corpus_diff::architecture_changed() const
12069 {return !priv_->architectures_equal_;}
12071 /// Getter for the deleted functions of the diff.
12073 /// @return the the deleted functions of the diff.
12074 const string_function_ptr_map&
12075 corpus_diff::deleted_functions() const
12076 {return priv_->deleted_fns_;}
12078 /// Getter for the added functions of the diff.
12080 /// @return the added functions of the diff.
12081 const string_function_ptr_map&
12082 corpus_diff::added_functions()
12083 {return priv_->added_fns_;}
12085 /// Getter for the functions which signature didn't change, but which
12086 /// do have some indirect changes in their parms.
12088 /// @return a non-sorted map of functions which signature didn't
12089 /// change, but which do have some indirect changes in their parms.
12090 /// The key of the map is a unique identifier for the function; it's
12091 /// usually made of the name and version of the underlying ELF symbol
12092 /// of the function for corpora that were built from ELF files.
12093 const string_function_decl_diff_sptr_map&
12094 corpus_diff::changed_functions()
12095 {return priv_->changed_fns_map_;}
12097 /// Getter for a sorted vector of functions which signature didn't
12098 /// change, but which do have some indirect changes in their parms.
12100 /// @return a sorted vector of functions which signature didn't
12101 /// change, but which do have some indirect changes in their parms.
12102 const function_decl_diff_sptrs_type&
12103 corpus_diff::changed_functions_sorted()
12104 {return priv_->changed_fns_;}
12106 /// Getter for the variables that got deleted from the first subject
12109 /// @return the map of deleted variable.
12110 const string_var_ptr_map&
12111 corpus_diff::deleted_variables() const
12112 {return priv_->deleted_vars_;}
12114 /// Getter for the added variables of the diff.
12116 /// @return the map of added variable.
12117 const string_var_ptr_map&
12118 corpus_diff::added_variables() const
12119 {return priv_->added_vars_;}
12121 /// Getter for the non-sorted map of variables which signature didn't
12122 /// change but which do have some indirect changes in some sub-types.
12124 /// @return the non-sorted map of changed variables.
12125 const string_var_diff_sptr_map&
12126 corpus_diff::changed_variables()
12127 {return priv_->changed_vars_map_;}
12129 /// Getter for the sorted vector of variables which signature didn't
12130 /// change but which do have some indirect changes in some sub-types.
12132 /// @return a sorted vector of changed variables.
12133 const var_diff_sptrs_type&
12134 corpus_diff::changed_variables_sorted()
12135 {return priv_->sorted_changed_vars_;}
12137 /// Getter for function symbols not referenced by any debug info and
12138 /// that got deleted.
12140 /// @return a map of elf function symbols not referenced by any debug
12141 /// info and that got deleted.
12142 const string_elf_symbol_map&
12143 corpus_diff::deleted_unrefed_function_symbols() const
12144 {return priv_->deleted_unrefed_fn_syms_;}
12146 /// Getter for function symbols not referenced by any debug info and
12147 /// that got added.
12149 /// @return a map of elf function symbols not referenced by any debug
12150 /// info and that got added.
12151 const string_elf_symbol_map&
12152 corpus_diff::added_unrefed_function_symbols() const
12153 {return priv_->added_unrefed_fn_syms_;}
12155 /// Getter for variable symbols not referenced by any debug info and
12156 /// that got deleted.
12158 /// @return a map of elf variable symbols not referenced by any debug
12159 /// info and that got deleted.
12160 const string_elf_symbol_map&
12161 corpus_diff::deleted_unrefed_variable_symbols() const
12162 {return priv_->deleted_unrefed_var_syms_;}
12164 /// Getter for variable symbols not referenced by any debug info and
12165 /// that got added.
12167 /// @return a map of elf variable symbols not referenced by any debug
12168 /// info and that got added.
12169 const string_elf_symbol_map&
12170 corpus_diff::added_unrefed_variable_symbols() const
12171 {return priv_->added_unrefed_var_syms_;}
12173 /// Getter of the diff context of this diff
12175 /// @return the diff context for this diff.
12176 const diff_context_sptr
12177 corpus_diff::context() const
12178 {return priv_->ctxt_;}
12180 /// @return the pretty representation for the current instance of @ref
12183 corpus_diff::get_pretty_representation() const
12185 if (priv_->pretty_representation_.empty())
12187 std::ostringstream o;
12188 o << "corpus_diff["
12189 << first_corpus()->get_path()
12191 << second_corpus()->get_path()
12193 priv_->pretty_representation_ = o.str();
12195 return priv_->pretty_representation_;
12197 /// Return true iff the current diff node carries a change.
12199 /// @return true iff the current diff node carries a change.
12201 corpus_diff::has_changes() const
12203 return (soname_changed()
12204 || architecture_changed()
12205 || priv_->deleted_fns_.size()
12206 || priv_->added_fns_.size()
12207 || priv_->changed_fns_map_.size()
12208 || priv_->deleted_vars_.size()
12209 || priv_->added_vars_.size()
12210 || priv_->changed_vars_map_.size()
12211 || priv_->added_unrefed_fn_syms_.size()
12212 || priv_->deleted_unrefed_fn_syms_.size()
12213 || priv_->added_unrefed_var_syms_.size()
12214 || priv_->deleted_unrefed_var_syms_.size());
12217 /// "Less than" functor to compare instances of @ref function_decl.
12218 struct function_comp
12220 /// The actual "less than" operator for instances of @ref
12221 /// function_decl. It returns true if the first @ref function_decl
12222 /// is lest than the second one.
12224 /// @param f the first @ref function_decl to take in account.
12226 /// @param s the second @ref function_decl to take in account.
12228 /// @return true iff @p f is less than @p s.
12230 operator()(const function_decl& f, const function_decl& s)
12232 string fr = f.get_pretty_representation_of_declarator(),
12233 sr = s.get_pretty_representation_of_declarator();
12238 fr = f.get_pretty_representation(),
12239 sr = f.get_pretty_representation();
12244 if (f.get_symbol())
12245 fr = f.get_symbol()->get_id_string();
12246 else if (!f.get_linkage_name().empty())
12247 fr = f.get_linkage_name();
12249 if (s.get_symbol())
12250 fr = s.get_symbol()->get_id_string();
12251 else if (!s.get_linkage_name().empty())
12252 fr = s.get_linkage_name();
12257 /// The actual "less than" operator for instances of @ref
12258 /// function_decl. It returns true if the first @ref function_decl
12259 /// is lest than the second one.
12261 /// @param f the first @ref function_decl to take in account.
12263 /// @param s the second @ref function_decl to take in account.
12265 /// @return true iff @p f is less than @p s.
12267 operator()(const function_decl* f, const function_decl* s)
12268 {return operator()(*f, *s);}
12270 /// The actual "less than" operator for instances of @ref
12271 /// function_decl. It returns true if the first @ref function_decl
12272 /// is lest than the second one.
12274 /// @param f the first @ref function_decl to take in account.
12276 /// @param s the second @ref function_decl to take in account.
12278 /// @return true iff @p f is less than @p s.
12280 operator()(const function_decl_sptr f, const function_decl_sptr s)
12281 {return operator()(f.get(), s.get());}
12282 }; // end function_comp
12284 /// Sort a an instance of @ref string_function_ptr_map map and stuff
12285 /// a resulting sorted vector of pointers to function_decl.
12287 /// @param map the map to sort.
12289 /// @param sorted the resulting sorted vector.
12291 sort_string_function_ptr_map(const string_function_ptr_map& map,
12292 vector<function_decl*>& sorted)
12294 sorted.reserve(map.size());
12295 for (string_function_ptr_map::const_iterator i = map.begin();
12298 sorted.push_back(i->second);
12300 function_comp comp;
12301 std::sort(sorted.begin(), sorted.end(), comp);
12304 /// A "Less Than" functor to compare instance of @ref
12305 /// function_decl_diff.
12306 struct function_decl_diff_comp
12308 /// The actual less than operator.
12310 /// It returns true if the first @ref function_decl_diff is less
12311 /// than the second one.
12313 /// param first the first @ref function_decl_diff to consider.
12315 /// @param second the second @ref function_decl_diff to consider.
12317 /// @return true iff @p first is less than @p second.
12319 operator()(const function_decl_diff& first,
12320 const function_decl_diff& second)
12322 function_decl_sptr f = first.first_function_decl(),
12323 s = second.first_function_decl();
12325 string fr = f->get_qualified_name(),
12326 sr = s->get_qualified_name();
12330 if (f->get_symbol())
12331 fr = f->get_symbol()->get_id_string();
12332 else if (!f->get_linkage_name().empty())
12333 fr = f->get_linkage_name();
12335 fr = f->get_pretty_representation();
12337 if (s->get_symbol())
12338 sr = s->get_symbol()->get_id_string();
12339 else if (!s->get_linkage_name().empty())
12340 sr = s->get_linkage_name();
12342 sr = s->get_pretty_representation();
12345 return (fr.compare(sr) < 0);
12348 /// The actual less than operator.
12350 /// It returns true if the first @ref function_decl_diff_sptr is
12351 /// less than the second one.
12353 /// param first the first @ref function_decl_diff_sptr to consider.
12355 /// @param second the second @ref function_decl_diff_sptr to
12358 /// @return true iff @p first is less than @p second.
12360 operator()(const function_decl_diff_sptr first,
12361 const function_decl_diff_sptr second)
12362 {return operator()(*first, *second);}
12363 }; // end struct function_decl_diff_comp
12365 /// Sort the values of a @ref string_function_decl_diff_sptr_map map
12366 /// and store the result in a vector of @ref function_decl_diff_sptr
12369 /// @param map the map whose values to store.
12371 /// @param sorted the vector of function_decl_diff_sptr to store the
12372 /// result of the sort into.
12374 sort_string_function_decl_diff_sptr_map
12375 (const string_function_decl_diff_sptr_map& map,
12376 function_decl_diff_sptrs_type& sorted)
12378 sorted.reserve(map.size());
12379 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
12382 sorted.push_back(i->second);
12383 function_decl_diff_comp comp;
12384 std::sort(sorted.begin(), sorted.end(), comp);
12387 /// Functor to sort instances of @ref var_diff_sptr
12388 struct var_diff_sptr_comp
12390 /// Return true if the first argument is less than the second one.
12392 /// @param f the first argument to consider.
12394 /// @param s the second argument to consider.
12396 /// @return true if @p f is less than @p s.
12398 operator()(const var_diff_sptr f,
12399 const var_diff_sptr s)
12401 return (f->first_var()->get_qualified_name()
12402 < s->first_var()->get_qualified_name());
12404 }; // end struct var_diff_sptr_comp
12406 /// Sort of an instance of @ref string_var_diff_sptr_map map.
12408 /// @param map the input map to sort.
12410 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
12411 /// It's populated with the sorted content.
12413 sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
12414 var_diff_sptrs_type& sorted)
12416 sorted.reserve(map.size());
12417 for (string_var_diff_sptr_map::const_iterator i = map.begin();
12420 sorted.push_back(i->second);
12422 var_diff_sptr_comp comp;
12423 std::sort(sorted.begin(), sorted.end(), comp);
12426 /// For a given symbol, emit a string made of its name and version.
12427 /// The string also contains the list of symbols that alias this one.
12429 /// @param out the output string to emit the resulting string to.
12431 /// @param indent the indentation string to use before emitting the
12432 /// resulting string.
12434 /// @param symbol the symbol to emit the representation string for.
12436 /// @param sym_map the symbol map to consider to look for aliases of
12439 show_linkage_name_and_aliases(ostream& out,
12440 const string& indent,
12441 const elf_symbol& symbol,
12442 const string_elf_symbols_map_type& sym_map)
12444 out << indent << symbol.get_id_string();
12446 symbol.get_aliases_id_string(sym_map,
12447 /*include_symbol_itself=*/false);
12448 if (!aliases.empty())
12449 out << ", aliases " << aliases;
12452 /// Apply the different filters that are registered to be applied to
12453 /// the diff tree; that includes the categorization filters. Also,
12454 /// apply the suppression interpretation filters.
12456 /// After the filters are applied, this function calculates some
12457 /// statistics about the changes carried by the current instance of
12458 /// @ref corpus_diff. These statistics are represented by an instance
12459 /// of @ref corpus_diff::diff_stats.
12461 /// This member function is called by the reporting function
12462 /// corpus_diff::report().
12464 /// Note that for a given instance of corpus_diff, this function
12465 /// applies the filters and suppressions only the first time it is
12466 /// invoked. Subsequent invocations just return the instance of
12467 /// corpus_diff::diff_stats that was cached after the first
12470 /// @return a reference to the statistics about the changes carried by
12471 /// the current instance of @ref corpus_diff.
12472 const corpus_diff::diff_stats&
12473 corpus_diff::apply_filters_and_suppressions_before_reporting()
12475 if (priv_->filters_and_suppr_applied_)
12476 return priv_->diff_stats_;
12478 apply_suppressions(this);
12479 priv_->apply_filters_and_compute_diff_stats(priv_->diff_stats_);
12481 priv_->filters_and_suppr_applied_ = true;
12483 return priv_->diff_stats_;
12486 /// Report the diff in a serialized form.
12488 /// @param out the stream to serialize the diff to.
12490 /// @param indent the prefix to use for the indentation of this
12493 corpus_diff::report(ostream& out, const string& indent) const
12495 size_t total = 0, removed = 0, added = 0;
12496 const diff_stats &s =
12497 const_cast<corpus_diff*>(this)->apply_filters_and_suppressions_before_reporting();
12499 /// Report removed/added/changed functions.
12500 total = s.num_func_removed() + s.num_func_added() +
12501 s.num_func_changed() - s.num_func_filtered_out();
12502 const unsigned large_num = 100;
12504 priv_->emit_diff_stats(s, out, indent);
12505 if (context()->show_stats_only())
12509 if (context()->show_soname_change()
12510 && !priv_->sonames_equal_)
12511 out << indent << "SONAME changed from '"
12512 << first_corpus()->get_soname() << "' to '"
12513 << second_corpus()->get_soname() << "'\n\n";
12515 if (context()->show_architecture_change()
12516 && !priv_->architectures_equal_)
12517 out << indent << "architecture changed from '"
12518 << first_corpus()->get_architecture_name() << "' to '"
12519 << second_corpus()->get_architecture_name() << "'\n\n";
12521 if (context()->show_deleted_fns())
12523 if (s.num_func_removed() == 1)
12524 out << indent << "1 Removed function:\n\n";
12525 else if (s.num_func_removed() > 1)
12526 out << indent << s.num_func_removed() << " Removed functions:\n\n";
12528 vector<function_decl*>sorted_deleted_fns;
12529 sort_string_function_ptr_map(priv_->deleted_fns_, sorted_deleted_fns);
12530 for (vector<function_decl*>::const_iterator i =
12531 sorted_deleted_fns.begin();
12532 i != sorted_deleted_fns.end();
12537 if (total > large_num)
12539 out << "'" << (*i)->get_pretty_representation() << "'";
12540 if (context()->show_linkage_names())
12543 show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
12544 first_corpus()->get_fun_symbol_map());
12554 if (context()->show_added_fns())
12556 if (s.num_func_added() == 1)
12557 out << indent << "1 Added function:\n";
12558 else if (s.num_func_added() > 1)
12559 out << indent << s.num_func_added()
12560 << " Added functions:\n\n";
12561 vector<function_decl*> sorted_added_fns;
12562 sort_string_function_ptr_map(priv_->added_fns_, sorted_added_fns);
12563 for (vector<function_decl*>::const_iterator i = sorted_added_fns.begin();
12564 i != sorted_added_fns.end();
12570 if (total > large_num)
12573 << (*i)->get_pretty_representation()
12575 if (context()->show_linkage_names())
12578 show_linkage_name_and_aliases
12579 (out, "", *(*i)->get_symbol(),
12580 second_corpus()->get_fun_symbol_map());
12593 if (context()->show_changed_fns())
12595 size_t num_changed = s.num_func_changed() - s.num_func_filtered_out();
12596 if (num_changed == 1)
12597 out << indent << "1 function with some indirect sub-type change:\n\n";
12598 else if (num_changed > 1)
12599 out << indent << num_changed
12600 << " functions with some indirect sub-type change:\n\n";
12602 bool emitted = false;
12603 vector<function_decl_diff_sptr> sorted_changed_fns;
12604 sort_string_function_decl_diff_sptr_map(priv_->changed_fns_map_,
12605 sorted_changed_fns);
12606 for (vector<function_decl_diff_sptr>::const_iterator i =
12607 sorted_changed_fns.begin();
12608 i != sorted_changed_fns.end();
12611 diff_sptr diff = *i;
12615 if (diff->to_be_reported())
12617 out << indent << " [C]'"
12618 << (*i)->first_function_decl()->get_pretty_representation()
12619 << "' has some indirect sub-type changes:\n";
12620 diff->report(out, indent + " ");
12632 // Report added/removed/changed variables.
12633 total = s.num_vars_removed() + s.num_vars_added() +
12634 s.num_vars_changed() - s.num_vars_filtered_out();
12636 if (context()->show_deleted_vars())
12638 if (s.num_vars_removed() == 1)
12639 out << indent << "1 Deleted variable:\n";
12640 else if (s.num_vars_removed() > 1)
12641 out << indent << s.num_vars_removed()
12642 << " Deleted variables:\n\n";
12644 for (string_var_ptr_map::const_iterator i =
12645 priv_->deleted_vars_.begin();
12646 i != priv_->deleted_vars_.end();
12649 n = i->second->get_pretty_representation();
12652 if (total > large_num)
12657 if (context()->show_linkage_names())
12660 show_linkage_name_and_aliases(out, "", *i->second->get_symbol(),
12661 first_corpus()->get_var_symbol_map());
12674 if (context()->show_added_vars())
12676 if (s.num_vars_added() == 1)
12677 out << indent << "1 Added variable:\n";
12678 else if (s.num_vars_added() > 1)
12679 out << indent << s.num_vars_added()
12680 << " Added variables:\n";
12682 for (string_var_ptr_map::const_iterator i =
12683 priv_->added_vars_.begin();
12684 i != priv_->added_vars_.end();
12687 n = i->second->get_pretty_representation();
12690 if (total > large_num)
12692 out << "'" << n << "'";
12693 if (context()->show_linkage_names())
12696 show_linkage_name_and_aliases(out, "", *i->second->get_symbol(),
12697 second_corpus()->get_var_symbol_map());
12710 if (context()->show_changed_vars())
12712 size_t num_changed = s.num_vars_changed() - s.num_vars_filtered_out();
12713 if (num_changed == 1)
12714 out << indent << "1 Changed variable:\n";
12715 else if (num_changed > 1)
12716 out << indent << num_changed
12717 << " Changed variables:\n\n";
12720 for (var_diff_sptrs_type::const_iterator i =
12721 priv_->sorted_changed_vars_.begin();
12722 i != priv_->sorted_changed_vars_.end();
12725 diff_sptr diff = *i;
12730 if (!diff->to_be_reported())
12733 n1 = diff->first_subject()->get_pretty_representation();
12734 n2 = diff->second_subject()->get_pretty_representation();
12736 out << indent << " [C]'" << n1 << "' was changed";
12738 out << " to '" << n2 << "'";
12740 diff->report(out, indent + " ");
12747 // Report removed function symbols not referenced by any debug info.
12748 if (context()->show_symbols_unreferenced_by_debug_info()
12749 && priv_->deleted_unrefed_fn_syms_.size())
12751 if (s.num_func_syms_removed() == 1)
12753 << "1 Removed function symbol not referenced by debug info:\n\n";
12754 else if (s.num_func_syms_removed() > 0)
12756 << s.num_func_syms_removed()
12757 << " Removed function symbols not referenced by debug info:\n\n";
12759 for (string_elf_symbol_map::const_iterator i =
12760 priv_->deleted_unrefed_fn_syms_.begin();
12761 i != priv_->deleted_unrefed_fn_syms_.end();
12764 out << indent << " ";
12765 if (s.num_func_syms_removed() > large_num)
12768 show_linkage_name_and_aliases(out, "", *i->second,
12769 first_corpus()->get_fun_symbol_map());
12772 if (priv_->deleted_unrefed_fn_syms_.size())
12776 // Report added function symbols not referenced by any debug info.
12777 if (context()->show_symbols_unreferenced_by_debug_info()
12778 && priv_->added_unrefed_fn_syms_.size())
12780 if (s.num_func_syms_added() == 1)
12782 << "1 Added function symbol not referenced by debug info:\n\n";
12783 else if (s.num_func_syms_added() > 0)
12785 << s.num_func_syms_added()
12786 << " Added function symbols not referenced by debug info:\n\n";
12788 for (string_elf_symbol_map::const_iterator i =
12789 priv_->added_unrefed_fn_syms_.begin();
12790 i != priv_->added_unrefed_fn_syms_.end();
12793 out << indent << " ";
12794 if (s.num_func_syms_added() > large_num)
12796 show_linkage_name_and_aliases(out, "",
12798 second_corpus()->get_fun_symbol_map());
12801 if (priv_->added_unrefed_fn_syms_.size())
12805 // Report removed variable symbols not referenced by any debug info.
12806 if (context()->show_symbols_unreferenced_by_debug_info()
12807 && priv_->deleted_unrefed_var_syms_.size())
12809 if (s.num_var_syms_removed() == 1)
12811 << "1 Removed variable symbol not referenced by debug info:\n\n";
12812 else if (s.num_var_syms_removed() > 0)
12814 << s.num_var_syms_removed()
12815 << " Removed variable symbols not referenced by debug info:\n\n";
12817 for (string_elf_symbol_map::const_iterator i =
12818 priv_->deleted_unrefed_var_syms_.begin();
12819 i != priv_->deleted_unrefed_var_syms_.end();
12822 out << indent << " ";
12823 if (s.num_var_syms_removed() > large_num)
12826 show_linkage_name_and_aliases(out, "", *i->second,
12827 first_corpus()->get_fun_symbol_map());
12830 if (priv_->deleted_unrefed_var_syms_.size())
12834 // Report added variable symbols not referenced by any debug info.
12835 if (context()->show_symbols_unreferenced_by_debug_info()
12836 && priv_->added_unrefed_var_syms_.size())
12838 if (s.num_var_syms_added() == 1)
12840 << "1 Added variable symbol not referenced by debug info:\n\n";
12841 else if (s.num_var_syms_added() > 0)
12843 << s.num_var_syms_added()
12844 << " Added variable symbols not referenced by debug info:\n\n";
12846 for (string_elf_symbol_map::const_iterator i =
12847 priv_->added_unrefed_var_syms_.begin();
12848 i != priv_->added_unrefed_var_syms_.end();
12851 out << indent << " ";
12852 if (s.num_var_syms_added() > large_num)
12854 show_linkage_name_and_aliases(out, "",
12856 second_corpus()->get_fun_symbol_map());
12859 if (priv_->added_unrefed_var_syms_.size())
12863 priv_->maybe_dump_diff_tree();
12866 /// Traverse the diff sub-tree under the current instance corpus_diff.
12868 /// @param v the visitor to invoke on each diff node of the sub-tree.
12870 /// @return true if the traversing has to keep going on, false otherwise.
12872 corpus_diff::traverse(diff_node_visitor& v)
12874 finish_diff_type();
12876 v.visit_begin(this);
12878 if (!v.visit(this, true))
12884 for (function_decl_diff_sptrs_type::const_iterator i =
12885 changed_functions_sorted().begin();
12886 i != changed_functions_sorted().end();
12889 if (diff_sptr d = *i)
12891 if (!d->traverse(v))
12899 for (var_diff_sptrs_type::const_iterator i =
12900 changed_variables_sorted().begin();
12901 i != changed_variables_sorted().end();
12904 if (diff_sptr d = *i)
12906 if (!d->traverse(v))
12918 /// Compute the diff between two instances fo the @ref corpus
12920 /// @param f the first @ref corpus to consider for the diff.
12922 /// @param s the second @ref corpus to consider for the diff.
12924 /// @param ctxt the diff context to use.
12926 /// @return the resulting diff between the two @ref corpus.
12928 compute_diff(const corpus_sptr f,
12929 const corpus_sptr s,
12930 diff_context_sptr ctxt)
12932 typedef corpus::functions::const_iterator fns_it_type;
12933 typedef corpus::variables::const_iterator vars_it_type;
12934 typedef elf_symbols::const_iterator symbols_it_type;
12935 typedef diff_utils::deep_ptr_eq_functor eq_type;
12938 ctxt.reset(new diff_context);
12940 ctxt->set_corpora(f, s);
12942 corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
12944 r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
12946 r->priv_->architectures_equal_ =
12947 f->get_architecture_name() == s->get_architecture_name();
12949 diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
12950 f->get_functions().end(),
12951 s->get_functions().begin(),
12952 s->get_functions().end(),
12953 r->priv_->fns_edit_script_);
12955 diff_utils::compute_diff<vars_it_type, eq_type>
12956 (f->get_variables().begin(), f->get_variables().end(),
12957 s->get_variables().begin(), s->get_variables().end(),
12958 r->priv_->vars_edit_script_);
12960 diff_utils::compute_diff<symbols_it_type, eq_type>
12961 (f->get_unreferenced_function_symbols().begin(),
12962 f->get_unreferenced_function_symbols().end(),
12963 s->get_unreferenced_function_symbols().begin(),
12964 s->get_unreferenced_function_symbols().end(),
12965 r->priv_->unrefed_fn_syms_edit_script_);
12967 diff_utils::compute_diff<symbols_it_type, eq_type>
12968 (f->get_unreferenced_variable_symbols().begin(),
12969 f->get_unreferenced_variable_symbols().end(),
12970 s->get_unreferenced_variable_symbols().begin(),
12971 s->get_unreferenced_variable_symbols().end(),
12972 r->priv_->unrefed_var_syms_edit_script_);
12974 r->priv_->ensure_lookup_tables_populated();
12981 // <diff_node_visitor stuff>
12983 /// This is called by the traversing code on a @ref diff node just
12984 /// before visiting it. That is, before visiting it and its children
12987 /// @param d the diff node to visit.
12989 diff_node_visitor::visit_begin(diff* /*p*/)
12992 /// This is called by the traversing code on a @ref diff node just
12993 /// after visiting it. That is after visiting it and its children
12996 /// @param d the diff node that got visited.
12998 diff_node_visitor::visit_end(diff* /*p*/)
13001 /// This is called by the traversing code on a @ref corpus_diff node
13002 /// just before visiting it. That is, before visiting it and its
13005 /// @param p the corpus_diff node to visit.
13008 diff_node_visitor::visit_begin(corpus_diff* /*p*/)
13011 /// This is called by the traversing code on a @ref corpus_diff node
13012 /// just after visiting it. That is after visiting it and its children
13015 /// @param d the diff node that got visited.
13017 diff_node_visitor::visit_end(corpus_diff* /*d*/)
13020 /// Default visitor implementation
13024 diff_node_visitor::visit(diff*, bool)
13027 /// Default visitor implementation.
13031 diff_node_visitor::visit(distinct_diff* dif, bool pre)
13039 /// Default visitor implementation.
13043 diff_node_visitor::visit(var_diff* dif, bool pre)
13051 /// Default visitor implementation.
13055 diff_node_visitor::visit(pointer_diff* dif, bool pre)
13063 /// Default visitor implementation.
13067 diff_node_visitor::visit(reference_diff* dif, bool pre)
13075 /// Default visitor implementation.
13079 diff_node_visitor::visit(qualified_type_diff* dif, bool pre)
13087 /// Default visitor implementation.
13091 diff_node_visitor::visit(enum_diff* dif, bool pre)
13099 /// Default visitor implementation.
13103 diff_node_visitor::visit(class_diff* dif, bool pre)
13111 /// Default visitor implementation.
13115 diff_node_visitor::visit(base_diff* dif, bool pre)
13123 /// Default visitor implementation.
13127 diff_node_visitor::visit(scope_diff* dif, bool pre)
13135 /// Default visitor implementation.
13139 diff_node_visitor::visit(function_decl_diff* dif, bool pre)
13147 /// Default visitor implementation.
13151 diff_node_visitor::visit(type_decl_diff* dif, bool pre)
13159 /// Default visitor implementation.
13163 diff_node_visitor::visit(typedef_diff* dif, bool pre)
13171 /// Default visitor implementation.
13175 diff_node_visitor::visit(translation_unit_diff* dif, bool pre)
13183 /// Default visitor implementation.
13187 diff_node_visitor::visit(corpus_diff*, bool)
13190 // </diff_node_visitor stuff>
13192 // <redundant diff node marking>
13194 // </redundant diff node marking>
13196 // <diff tree category propagation>
13198 /// A visitor to propagate the category of a node up to its parent
13199 /// nodes. This visitor doesn't touch the REDUNDANT_CATEGORY because
13200 /// that one is propagated using another specific visitor.
13201 struct category_propagation_visitor : public diff_node_visitor
13206 // Has this diff node 'd' been already visited ?
13207 bool already_visited = d->context()->diff_has_been_visited(d);
13209 // The canonical diff node of the class of equivalence of the diff
13211 diff* canonical = d->get_canonical_diff();
13213 // If this class of equivalence of diff node is being visited for
13214 // the first time, then update its canonical node's category too.
13215 bool update_canonical = !already_visited && canonical;
13217 for (vector<diff_sptr>::const_iterator i = d->children_nodes().begin();
13218 i != d->children_nodes().end();
13221 // If we are visiting the class of equivalence of 'd' for the
13222 // first time, then let's look at the children of 'd' and
13223 // propagate their categories to 'd'.
13225 // If the class of equivalence of 'd' has already been
13226 // visited, then let's look at the canonical diff nodes of the
13227 // children of 'd' and propagate their categories to 'd'.
13228 diff* diff = already_visited
13229 ? (*i)->get_canonical_diff()
13234 diff_category c = diff->get_category();
13235 c &= ~(REDUNDANT_CATEGORY|SUPPRESSED_CATEGORY);
13236 d->add_to_category(c);
13237 if (!already_visited && canonical)
13238 if (update_canonical)
13239 canonical->add_to_category(c);
13242 };// end struct category_propagation_visitor
13244 /// Visit all the nodes of a given sub-tree. For each node that has a
13245 /// particular category set, propagate that category set up to its
13248 /// @param diff_tree the diff sub-tree to walk for categorization
13251 propagate_categories(diff* diff_tree)
13253 category_propagation_visitor v;
13254 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13255 diff_tree->context()->forbid_visiting_a_node_twice(true);
13256 diff_tree->context()->forget_visited_diffs();
13257 diff_tree->traverse(v);
13258 diff_tree->context()->forbid_visiting_a_node_twice(s);
13261 /// Visit all the nodes of a given sub-tree. For each node that has a
13262 /// particular category set, propagate that category set up to its
13265 /// @param diff_tree the diff sub-tree to walk for categorization
13268 propagate_categories(diff_sptr diff_tree)
13269 {propagate_categories(diff_tree.get());}
13271 /// Visit all the nodes of a given corpus tree. For each node that
13272 /// has a particular category set, propagate that category set up to
13273 /// its parent nodes.
13275 /// @param diff_tree the corpus_diff tree to walk for categorization
13278 propagate_categories(corpus_diff* diff_tree)
13280 category_propagation_visitor v;
13281 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13282 diff_tree->context()->forbid_visiting_a_node_twice(false);
13283 diff_tree->traverse(v);
13284 diff_tree->context()->forbid_visiting_a_node_twice(s);
13287 /// Visit all the nodes of a given corpus tree. For each node that
13288 /// has a particular category set, propagate that category set up to
13289 /// its parent nodes.
13291 /// @param diff_tree the corpus_diff tree to walk for categorization
13294 propagate_categories(corpus_diff_sptr diff_tree)
13295 {propagate_categories(diff_tree.get());}
13297 /// A tree node visitor that knows how to categorizes a given in the
13298 /// SUPPRESSED_CATEGORY category and how to propagate that
13299 /// categorization.
13300 struct suppression_categorization_visitor : public diff_node_visitor
13303 /// Before visiting the children of the diff node, check if the node
13304 /// is suppressed by a suppression specification. If it is, mark
13305 /// the node as belonging to the SUPPRESSED_CATEGORY category.
13307 /// @param p the diff node to visit.
13309 visit_begin(diff* d)
13311 if (d->is_suppressed())
13312 d->add_to_local_and_inherited_categories(SUPPRESSED_CATEGORY);
13315 /// After visiting the children nodes of a given diff node,
13316 /// propagate the SUPPRESSED_CATEGORY from the children nodes to the
13317 /// diff node, if need be.
13319 /// That is, if all children nodes carry a suppressed change the
13320 /// current node should be marked as suppressed as well.
13322 /// In practice, this might be too strong of a condition. If the
13323 /// current node carries a local change (i.e, a change not carried
13324 /// by any of its children node) and if that change is not
13325 /// suppressed, then the current node should *NOT* be suppressed.
13327 /// But right now, the IR doesn't let us know about local vs
13328 /// children-carried changes. So we cannot be that precise yet.
13332 bool has_non_suppressed_child = false;
13333 bool has_non_empty_child = false;
13334 bool has_suppressed_child = false;
13336 if (!(d->get_category() & SUPPRESSED_CATEGORY)
13337 && !d->has_local_changes())
13339 for (vector<diff_sptr>::const_iterator i = d->children_nodes().begin();
13340 i != d->children_nodes().end();
13343 diff_sptr child = *i;
13344 if (child->has_changes())
13346 has_non_empty_child = true;
13347 if (child->get_category() & SUPPRESSED_CATEGORY)
13348 has_suppressed_child = true;
13350 has_non_suppressed_child = true;
13354 if (has_non_empty_child
13355 && has_suppressed_child
13356 && !has_non_suppressed_child)
13357 d->add_to_category(SUPPRESSED_CATEGORY);
13360 }; //end struct suppression_categorization_visitor
13362 /// Walk a given diff-sub tree and appply the suppressions carried by
13363 /// the context. If the suppression applies to a given node than
13364 /// categorize the node into the SUPPRESSED_CATEGORY category and
13365 /// propagate that categorization.
13367 /// @param diff_tree the diff-sub tree to apply the suppressions to.
13369 apply_suppressions(diff* diff_tree)
13371 if (diff_tree && !diff_tree->context()->suppressions().empty())
13373 suppression_categorization_visitor v;
13374 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13375 diff_tree->context()->forbid_visiting_a_node_twice(false);
13376 diff_tree->traverse(v);
13377 diff_tree->context()->forbid_visiting_a_node_twice(s);
13381 /// Walk a given diff-sub tree and appply the suppressions carried by
13382 /// the context. If the suppression applies to a given node than
13383 /// categorize the node into the SUPPRESSED_CATEGORY category and
13384 /// propagate that categorization.
13386 /// @param diff_tree the diff-sub tree to apply the suppressions to.
13388 apply_suppressions(diff_sptr diff_tree)
13389 {apply_suppressions(diff_tree.get());}
13391 /// Walk a diff tree and appply the suppressions carried by the
13392 /// context. If the suppression applies to a given node than
13393 /// categorize the node into the SUPPRESSED_CATEGORY category and
13394 /// propagate that categorization.
13396 /// @param diff_tree the diff tree to apply the suppressions to.
13398 apply_suppressions(const corpus_diff* diff_tree)
13400 if (diff_tree && !diff_tree->context()->suppressions().empty())
13402 suppression_categorization_visitor v;
13403 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13404 diff_tree->context()->forbid_visiting_a_node_twice(false);
13405 const_cast<corpus_diff*>(diff_tree)->traverse(v);
13406 diff_tree->context()->forbid_visiting_a_node_twice(s);
13410 /// Walk a diff tree and appply the suppressions carried by the
13411 /// context. If the suppression applies to a given node than
13412 /// categorize the node into the SUPPRESSED_CATEGORY category and
13413 /// propagate that categorization.
13415 /// @param diff_tree the diff tree to apply the suppressions to.
13417 apply_suppressions(corpus_diff_sptr diff_tree)
13418 {apply_suppressions(diff_tree.get());}
13420 // </diff tree category propagation>
13422 // <diff tree printing stuff>
13424 /// A visitor to print (to an output stream) a pretty representation
13425 /// of a @ref diff sub-tree or of a complete @ref corpus_diff tree.
13426 struct diff_node_printer : public diff_node_visitor
13431 /// Emit a certain number of spaces to the output stream associated
13432 /// to this diff_node_printer.
13434 /// @param level half of the numver of spaces to emit.
13436 do_indent(unsigned level)
13438 for (unsigned i = 0; i < level; ++i)
13442 diff_node_printer(ostream& out)
13443 : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
13461 visit_begin(corpus_diff*)
13467 visit_end(corpus_diff*)
13473 visit(diff* d, bool pre)
13476 // We are post-visiting the diff node D. Which means, we have
13477 // printed a pretty representation for it already. So do
13482 out_ << d->get_pretty_representation();
13486 do_indent(level_ + 1);
13487 out_ << "category: "<< d->get_category() << "\n";
13488 do_indent(level_ + 1);
13489 out_ << "@: " << std::hex << d << std::dec << "\n";
13490 do_indent(level_ + 1);
13491 out_ << "@-canonical: " << std::hex
13492 << d->get_canonical_diff()
13493 << std::dec << "\n";
13501 visit(corpus_diff* d, bool pre)
13504 // We are post-visiting the diff node D. Which means, we have
13505 // printed a pretty representation for it already. So do
13510 for (unsigned i = 0; i < level_; ++i)
13512 out_ << d->get_pretty_representation();
13516 }; // end struct diff_printer_visitor
13518 // </ diff tree printing stuff>
13520 /// Emit a textual representation of a @ref diff sub-tree to an
13523 /// @param diff_tree the sub-tree to emit the textual representation
13526 /// @param out the output stream to emit the textual representation
13527 /// for @p diff_tree to.
13529 print_diff_tree(diff* diff_tree, ostream& out)
13531 diff_node_printer p(out);
13532 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13533 diff_tree->context()->forbid_visiting_a_node_twice(false);
13534 diff_tree->traverse(p);
13535 diff_tree->context()->forbid_visiting_a_node_twice(s);
13538 /// Emit a textual representation of a @ref corpus_diff tree to an
13541 /// @param diff_tree the @ref corpus_diff tree to emit the textual
13542 /// representation for.
13544 /// @param out the output stream to emit the textual representation
13545 /// for @p diff_tree to.
13547 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
13549 diff_node_printer p(out);
13550 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13551 diff_tree->context()->forbid_visiting_a_node_twice(false);
13552 diff_tree->traverse(p);
13553 diff_tree->context()->forbid_visiting_a_node_twice(s);
13556 /// Emit a textual representation of a @ref diff sub-tree to an
13559 /// @param diff_tree the sub-tree to emit the textual representation
13562 /// @param out the output stream to emit the textual representation
13563 /// for @p diff_tree to.
13565 print_diff_tree(diff_sptr diff_tree,
13567 {print_diff_tree(diff_tree.get(), o);}
13569 /// Emit a textual representation of a @ref corpus_diff tree to an
13572 /// @param diff_tree the @ref corpus_diff tree to emit the textual
13573 /// representation for.
13575 /// @param out the output stream to emit the textual representation
13576 /// for @p diff_tree to.
13578 print_diff_tree(corpus_diff_sptr diff_tree,
13580 {print_diff_tree(diff_tree.get(), o);}
13582 // <redundancy_marking_visitor>
13584 /// A tree visitor to categorize nodes with respect to the
13585 /// REDUNDANT_CATEGORY. That is, detect if a node is redundant (is
13586 /// present on several spots of the tree) and mark such nodes
13587 /// appropriatly. This visitor also takes care of propagating the
13588 /// REDUNDANT_CATEGORY of a given node to its parent nodes as
13590 struct redundancy_marking_visitor : public diff_node_visitor
13592 bool skip_children_nodes_;
13594 redundancy_marking_visitor()
13595 : skip_children_nodes_()
13599 visit_begin(diff* d)
13601 if (d->to_be_reported())
13603 // A diff node that carries a change and that has been already
13604 // traversed elsewhere is considered redundant. So let's mark
13605 // it as such and let's not traverse it; that is, let's not
13606 // visit its children.
13607 if ((d->context()->diff_has_been_visited(d)
13608 || d->get_canonical_diff()->is_traversing())
13609 && d->has_changes())
13611 // But if two diff nodes are redundant sibbling, do not
13612 // mark them as being redundant. This is to avoid marking
13613 // nodes as redundant in this case:
13615 // int foo(int a, int b);
13617 // float foo(float a, float b); (in C).
13619 // In this case, we want to report all the occurences of
13620 // the int->float change because logically, they are at
13621 // the same level in the diff tree.
13623 bool redundant_with_sibling_node = false;
13624 const diff* p = d->parent_node();
13626 // If this is a child node of a fn_parm_diff, look through
13627 // the fn_parm_diff node to get the function diff node.
13628 if (p && dynamic_cast<const fn_parm_diff*>(p))
13629 p = p->parent_node();
13632 for (vector<diff_sptr>::const_iterator s =
13633 p->children_nodes().begin();
13634 s != p->children_nodes().end();
13639 diff* sib = s->get();
13640 // If this is a fn_parm_diff, look through the
13641 // fn_parm_diff node to get at the real type node.
13642 if (fn_parm_diff_sptr f =
13643 dynamic_pointer_cast<fn_parm_diff>(*s))
13644 sib = f->get_type_diff().get();
13647 if (sib->get_canonical_diff() == d->get_canonical_diff())
13649 redundant_with_sibling_node = true;
13653 if (!redundant_with_sibling_node
13654 // Functions with similar *local* changes are never marked
13655 // redundant because otherwise one could miss important
13656 // similar local changes that are applied to different
13658 && !dynamic_cast<function_type_diff*>(d)
13659 // Changes involving variadic parameters of functions
13660 // should never be marked redundant because we want to see
13662 && !is_diff_of_variadic_parameter(d)
13663 && !is_diff_of_variadic_parameter_type(d)
13664 // If the canonical diff itself has been filtered out,
13665 // then this one is not marked redundant, obviously.
13666 && !d->get_canonical_diff()->is_filtered_out()
13667 && !(diff_has_ancestor_filtered_out
13669 get_last_visited_diff_of_class_of_equivalence(d)))
13670 // If the *same* diff node (not one that is merely
13671 // equivalent to this one) has already been visited
13672 // the do not mark it as beind redundant. It's only
13673 // the other nodes that are equivalent to this one
13674 // that must be marked redundant.
13675 && d->context()->diff_has_been_visited(d) != d
13676 // If the diff node is a function parameter and is not
13677 // a reference/pointer then do not mark it as
13679 && (is_reference_or_pointer_diff(d)
13680 || (!is_child_node_of_function_parm_diff(d)
13681 && !is_child_node_of_base_diff(d))))
13683 d->add_to_category(REDUNDANT_CATEGORY);
13684 // As we said in preamble, as this node is marked as
13685 // being redundant, let's not visit its children.
13686 // This is not an optimization; it's needed for
13687 // correctness. In the case of a diff node involving
13688 // a class type that refers to himself, visiting the
13689 // children nodes might cause them to be wrongly
13690 // marked as redundant.
13691 set_visiting_kind(get_visiting_kind()
13692 | SKIP_CHILDREN_VISITING_KIND);
13693 skip_children_nodes_ = true;
13699 // If the node is not to be reported, do not look at it children.
13700 set_visiting_kind(get_visiting_kind() | SKIP_CHILDREN_VISITING_KIND);
13701 skip_children_nodes_ = true;
13704 d->context()->mark_last_diff_visited_per_class_of_equivalence(d);
13708 visit_begin(corpus_diff*)
13715 if (skip_children_nodes_)
13716 // When visiting this node, we decided to skip its children
13717 // node. Now that we are done visiting the node, lets stop
13718 // avoiding the children nodes visiting for the other tree
13721 set_visiting_kind(get_visiting_kind() & (~SKIP_CHILDREN_VISITING_KIND));
13722 skip_children_nodes_ = false;
13726 // Propagate the redundancy categorization of the children nodes
13727 // to this node. But if this node has local changes, then it
13728 // doesn't inherit redundancy from its children nodes.
13729 if (!(d->get_category() & REDUNDANT_CATEGORY)
13730 && !d->has_local_changes_to_be_reported())
13732 bool has_non_redundant_child = false;
13733 bool has_non_empty_child = false;
13734 for (vector<diff_sptr>::const_iterator i =
13735 d->children_nodes().begin();
13736 i != d->children_nodes().end();
13739 if ((*i)->has_changes())
13741 has_non_empty_child = true;
13742 if ((*i)->to_be_reported()
13743 && ((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
13744 has_non_redundant_child = true;
13746 if (has_non_redundant_child)
13750 // A diff node for which at least a child node carries a
13751 // change, and for which all the children are redundant is
13752 // deemed redundant too, unless it has local changes.
13753 if (has_non_empty_child
13754 && !has_non_redundant_child)
13755 d->add_to_category(REDUNDANT_CATEGORY);
13761 visit_end(corpus_diff*)
13770 visit(corpus_diff*, bool)
13774 };// end struct redundancy_marking_visitor
13776 /// A visitor of @ref diff nodes that clears the REDUNDANT_CATEGORY
13777 /// category out of the nodes.
13778 struct redundancy_clearing_visitor : public diff_node_visitor
13781 visit(corpus_diff*, bool)
13785 visit(diff* d, bool)
13787 // clear the REDUNDANT_CATEGORY out of the current node.
13788 diff_category c = d->get_category();
13789 c &= ~REDUNDANT_CATEGORY;
13790 d->set_category(c);
13793 }; // end struct redundancy_clearing_visitor
13795 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13796 /// with respect to the REDUNDANT_CATEGORY.
13798 /// @param diff_tree the @ref diff sub-tree to walk.
13800 categorize_redundancy(diff* diff_tree)
13802 if (diff_tree->context()->show_redundant_changes())
13804 redundancy_marking_visitor v;
13805 diff_tree->context()->clear_last_diffs_visited_per_class_of_equivalence();
13806 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13807 diff_tree->context()->forbid_visiting_a_node_twice(false);
13808 diff_tree->traverse(v);
13809 diff_tree->context()->forbid_visiting_a_node_twice(s);
13810 diff_tree->context()->clear_last_diffs_visited_per_class_of_equivalence();
13813 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13814 /// with respect to the REDUNDANT_CATEGORY.
13816 /// @param diff_tree the @ref diff sub-tree to walk.
13818 categorize_redundancy(diff_sptr diff_tree)
13819 {categorize_redundancy(diff_tree.get());}
13821 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13822 /// with respect to the REDUNDANT_CATEGORY.
13824 /// @param diff_tree the @ref corpus_diff tree to walk.
13826 categorize_redundancy(corpus_diff* diff_tree)
13828 redundancy_marking_visitor v;
13829 diff_tree->context()->forget_visited_diffs();
13830 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13831 diff_tree->context()->forbid_visiting_a_node_twice(false);
13832 diff_tree->traverse(v);
13833 diff_tree->context()->forbid_visiting_a_node_twice(s);
13836 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13837 /// with respect to the REDUNDANT_CATEGORY.
13839 /// @param diff_tree the @ref corpus_diff tree to walk.
13841 categorize_redundancy(corpus_diff_sptr diff_tree)
13842 {categorize_redundancy(diff_tree.get());}
13844 // </redundancy_marking_visitor>
13846 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13847 /// out of the category of the nodes.
13849 /// @param diff_tree the @ref diff sub-tree to walk.
13851 clear_redundancy_categorization(diff* diff_tree)
13853 redundancy_clearing_visitor v;
13854 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13855 diff_tree->context()->forbid_visiting_a_node_twice(false);
13856 diff_tree->traverse(v);
13857 diff_tree->context()->forbid_visiting_a_node_twice(s);
13858 diff_tree->context()->forget_visited_diffs();
13861 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13862 /// out of the category of the nodes.
13864 /// @param diff_tree the @ref diff sub-tree to walk.
13866 clear_redundancy_categorization(diff_sptr diff_tree)
13867 {clear_redundancy_categorization(diff_tree.get());}
13869 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13870 /// out of the category of the nodes.
13872 /// @param diff_tree the @ref corpus_diff tree to walk.
13874 clear_redundancy_categorization(corpus_diff* diff_tree)
13876 redundancy_clearing_visitor v;
13877 bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
13878 diff_tree->context()->forbid_visiting_a_node_twice(false);
13879 diff_tree->traverse(v);
13880 diff_tree->context()->forbid_visiting_a_node_twice(s);
13881 diff_tree->context()->forget_visited_diffs();
13884 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13885 /// out of the category of the nodes.
13887 /// @param diff_tree the @ref corpus_diff tree to walk.
13889 clear_redundancy_categorization(corpus_diff_sptr diff_tree)
13890 {clear_redundancy_categorization(diff_tree.get());}
13892 /// Apply the @ref diff tree filters that have been associated to the
13893 /// context of the a given @ref corpus_diff tree. As a result, the
13894 /// nodes of the @diff tree are going to be categorized into one of
13895 /// several of the categories of @ref diff_category.
13897 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
13898 /// to be categorized.
13900 apply_filters(corpus_diff_sptr diff_tree)
13902 diff_tree->context()->maybe_apply_filters(diff_tree);
13903 propagate_categories(diff_tree);
13906 /// Test if a diff node represents the difference between a variadic
13907 /// parameter type and something else.
13909 /// @param d the diff node to consider.
13911 /// @return true iff @p d is a diff node that represents the
13912 /// difference between a variadic parameter type and something else.
13914 is_diff_of_variadic_parameter_type(const diff* d)
13919 type_base_sptr t = is_type(d->first_subject());
13920 if (t && t.get() == type_decl::get_variadic_parameter_type_decl().get())
13923 t = is_type(d->second_subject());
13924 if (t && t.get() == type_decl::get_variadic_parameter_type_decl().get())
13930 /// Test if a diff node represents the difference between a variadic
13931 /// parameter type and something else.
13933 /// @param d the diff node to consider.
13935 /// @return true iff @p d is a diff node that represents the
13936 /// difference between a variadic parameter type and something else.
13938 is_diff_of_variadic_parameter_type(const diff_sptr& d)
13939 {return is_diff_of_variadic_parameter_type(d.get());}
13941 /// Test if a diff node represents the difference between a variadic
13942 /// parameter and something else.
13944 /// @param d the diff node to consider.
13946 /// @return true iff @p d is a diff node that represents the
13947 /// difference between a variadic parameter and something else.
13949 is_diff_of_variadic_parameter(const diff* d)
13951 fn_parm_diff* diff =
13952 dynamic_cast<fn_parm_diff*>(const_cast<abigail::comparison::diff*>(d));
13953 return (diff && is_diff_of_variadic_parameter_type(diff->get_type_diff()));
13956 /// Test if a diff node represents the difference between a variadic
13957 /// parameter and something else.
13959 /// @param d the diff node to consider.
13961 /// @return true iff @p d is a diff node that represents the
13962 /// difference between a variadic parameter and something else.
13964 is_diff_of_variadic_parameter(const diff_sptr& d)
13965 {return is_diff_of_variadic_parameter(d.get());}
13966 }// end namespace comparison
13967 } // end namespace abigail