]> sourceware.org Git - libabigail.git/blob
ef7c6c9
[libabigail.git] /
1 // -*- Mode: C++ -*-
2 //
3 // Copyright (C) 2013-2015 Red Hat, Inc.
4 //
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
10 // later version.
11
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.
16
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/>.
20 //
21 // Author: Dodji Seketeli
22
23 /// @file
24 ///
25 /// This contains the implementation of the comparison engine of
26 /// libabigail.
27
28 #include <ctype.h>
29 #include <algorithm>
30 #include <sstream>
31 #include "abg-hash.h"
32 #include "abg-comparison.h"
33 #include "abg-comp-filter.h"
34 #include "abg-sptr-utils.h"
35 #include "abg-ini.h"
36
37 namespace abigail
38 {
39
40 namespace comparison
41 {
42
43 ///
44 ///
45 ///@defgroup DiffNode Internal Representation of the comparison engine
46 /// @{
47 ///
48 /// @brief How changes are represented in libabigail's comparison engine.
49 ///
50 ///@par diff nodes
51 ///
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>.
58 ///
59 /// The types of that IR are in the abigail::comparison namespace.
60 ///
61 ///@par comparing diff nodes
62 ///
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.
67 ///
68 ///@par diff reporting and context
69 ///
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.
77 ///
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.
84 ///
85 /// @}
86 ///
87
88 ///
89 ///@defgroup CanonicalDiff Canonical diff tree nodes
90 /// @{
91 ///
92 /// @brief How equivalent diff nodes are quickly spotted.
93 ///
94 /// @par Equivalence of diff nodes.
95 ///
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.
101 ///
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
104 /// equal.
105 ///
106 /// A canonical node is registereded for a given diff node by invoking
107 /// the method diff_context::initialize_canonical_diff().
108 ///
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.
113 ///
114 /// @}
115 ///
116
117 // Inject types from outside in here.
118 using std::vector;
119 using std::tr1::dynamic_pointer_cast;
120 using std::tr1::static_pointer_cast;
121 using abigail::sptr_utils::noop_deleter;
122
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;
126
127 /// A hashing functor for @ref types_or_decls_type.
128 struct types_or_decls_hash
129 {
130 size_t
131 operator()(const types_or_decls_type& d) const
132 {
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);
136 }
137 };
138
139 /// An equality functor for @ref types_or_decls_type.
140 struct types_or_decls_equal
141 {
142 bool
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;}
145 };
146
147 /// A convenience typedef for a map of @ref types_or_decls_type and
148 /// diff_sptr.
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;
152
153 /// The overloaded or operator for @ref visiting_kind.
154 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));}
158
159 /// The overloaded and operator for @ref visiting_kind.
160 visiting_kind
161 operator&(visiting_kind l, visiting_kind r)
162 {
163 return static_cast<visiting_kind>(static_cast<unsigned>(l)
164 & static_cast<unsigned>(r));
165 }
166
167 /// The overloaded 'bit inversion' operator for @ref visiting_kind.
168 visiting_kind
169 operator~(visiting_kind l)
170 {return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
171
172 /// This is a subroutine of a *::report() function.
173 ///
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.
177 ///
178 /// @param S1 the first diff subject to take in account.
179 ///
180 /// @param S2 the second diff subject to take in account.
181 #define RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(S1, S2) \
182 do { \
183 if (diff_sptr _diff_ = context()->get_canonical_diff_for(S1, S2)) \
184 if (_diff_->currently_reporting() || _diff_->reported_once()) \
185 { \
186 if (_diff_->currently_reporting()) \
187 out << indent << "details are being reported\n"; \
188 else \
189 out << indent << "details were reported earlier\n"; \
190 return ; \
191 } \
192 } while (false)
193
194 /// This is a subroutine of a *::report() function.
195 ///
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.
199 ///
200 /// @param S1 the first diff subject to take in account.
201 ///
202 /// @param S2 the second diff subject to take in account.
203 ///
204 /// @param INTRO_TEXT the introductory text that precedes the
205 /// diagnostic.
206 #define RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(D, INTRO_TEXT) \
207 do { \
208 if (diff_sptr _diff_ = context()->get_canonical_diff_for(D)) \
209 if (_diff_->currently_reporting() || _diff_->reported_once()) \
210 { \
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"; \
215 else \
216 out << indent << INTRO_TEXT << " '" << _name_ << "' changed, " \
217 "as reported earlier\n"; \
218 return ; \
219 } \
220 } while (false)
221
222 /// This is a subroutine of a *::report() function.
223 ///
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.
227 ///
228 ///
229 /// @param INTRO_TEXT the introductory text that precedes the
230 /// diagnostic.
231 #define RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(S1, S2, INTRO_TEXT) \
232 do { \
233 if (diff_sptr _diff_ = context()->get_canonical_diff_for(S1, S2)) \
234 if (_diff_->currently_reporting() || _diff_->reported_once()) \
235 { \
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"; \
240 else \
241 out << indent << INTRO_TEXT << " '" << _name_ << "' changed, " \
242 "as reported earlier\n"; \
243 return ; \
244 } \
245 } while (false)
246
247 static void
248 sort_string_function_decl_diff_sptr_map
249 (const string_function_decl_diff_sptr_map& map,
250 function_decl_diff_sptrs_type& sorted);
251
252 static void
253 sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
254 var_diff_sptrs_type& sorted);
255
256 static void
257 sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,
258 var_diff_sptrs_type& sorted);
259
260 static void
261 sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map,
262 var_diff_sptrs_type& sorted);
263
264 static void
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);
268
269 static void
270 sort_string_diff_sptr_map(const string_diff_sptr_map& map,
271 diff_sptrs_type& sorted);
272
273 static void
274 sort_string_base_diff_sptr_map(const string_base_diff_sptr_map& map,
275 base_diff_sptrs_type& sorted);
276
277 static void
278 sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map,
279 vector<fn_parm_diff_sptr>& sorted);
280
281 static void
282 sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map& map,
283 vector<fn_parm_diff_sptr>& sorted);
284
285 static void
286 sort_string_parm_map(const string_parm_map& map,
287 vector<function_decl::parameter_sptr>& sorted);
288
289 static type_base_sptr
290 get_leaf_type(qualified_type_def_sptr t);
291
292 /// Test if a diff node is about differences between types.
293 ///
294 /// @param diff the diff node to test.
295 ///
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);}
301
302 /// Test if a diff node is about differences between declarations.
303 ///
304 /// @param diff the diff node to test.
305 ///
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);}
311
312 /// Test if a diff node is about differences between variables.
313 ///
314 /// @param diff the diff node to test.
315 ///
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)
320 {
321 const var_diff* d = dynamic_cast<const var_diff*>(diff);
322 if (d)
323 assert(is_decl_diff(diff));
324 return d;
325 }
326
327 /// Test if a diff node is about differences between functions.
328 ///
329 /// @param diff the diff node to test.
330 ///
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)
335 {
336 const function_decl_diff *d = dynamic_cast<const function_decl_diff*>(diff);
337 if (d)
338 assert(is_decl_diff(diff));
339 return d;
340 }
341
342 /// Test if a diff node is about differences between two pointers.
343 ///
344 /// @param diff the diff node to consider.
345 ///
346 /// @return the @p diff converted into an instance of @ref
347 /// pointer_diff iff @p diff is about differences between two
348 /// pointers.
349 static const pointer_diff*
350 is_pointer_diff(const diff* diff)
351 {return dynamic_cast<const pointer_diff*>(diff);}
352
353 /// Test if a diff node is about differences between two references.
354 ///
355 /// @param diff the diff node to consider.
356 ///
357 /// @return the @p diff converted into an instance of @ref
358 /// reference_diff iff @p diff is about differences between two
359 /// references.
360 static const reference_diff*
361 is_reference_diff(const diff* diff)
362 {return dynamic_cast<const reference_diff*>(diff);}
363
364 /// Test if a diff node is either a reference diff node or a pointer
365 /// diff node.
366 ///
367 /// @param diff the diff node to test.
368 ///
369 /// @return true iff @p diff is either reference diff node or a
370 /// pointer diff node.
371 static bool
372 is_reference_or_pointer_diff(const diff* diff)
373 {return is_reference_diff(diff) || is_pointer_diff(diff);}
374
375 /// Test if a diff node is about differences between two function
376 /// parameters.
377 ///
378 /// @param diff the diff node to consider.
379 ///
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);}
386
387 /// Test if a diff node is about differences between two base class
388 /// specifiers.
389 ///
390 /// @param diff the diff node to consider.
391 ///
392 /// @return the @p diff converted into an instance of @ref base_diff
393 /// iff @p diff is about differences between two base class
394 /// specifiers.
395 static const base_diff*
396 is_base_diff(const diff* diff)
397 {return dynamic_cast<const base_diff*>(diff);}
398
399 /// Test if a diff node is a child node of a function parameter diff node.
400 ///
401 /// @param diff the diff node to test.
402 ///
403 /// @return true iff @p diff is a child node of a function parameter
404 /// diff node.
405 static bool
406 is_child_node_of_function_parm_diff(const diff* diff)
407 {return diff && is_fn_parm_diff(diff->parent_node());}
408
409 /// Test if a diff node is a child node of a base diff node.
410 ///
411 /// @param diff the diff node to test.
412 ///
413 /// @return true iff @p diff is a child node of a base diff node.
414 static bool
415 is_child_node_of_base_diff(const diff* diff)
416 {return diff && is_base_diff(diff->parent_node());}
417
418 /// Test if the current diff node has an ancestor node that has been
419 /// filtered out.
420 ///
421 /// @param diff the diff node to take into account.
422 ///
423 /// @return true iff the current diff node has an ancestor node that
424 /// has been filtered out.
425 static bool
426 diff_has_ancestor_filtered_out(const diff* diff)
427 {
428 if (!diff || !diff->parent_node())
429 return false;
430 if (diff->parent_node()->is_filtered_out())
431 return true;
432 return diff_has_ancestor_filtered_out(diff->parent_node());
433 }
434
435 /// The default traverse function.
436 ///
437 /// @return true.
438 bool
439 diff_traversable_base::traverse(diff_node_visitor&)
440 {return true;}
441
442 // <suppression_base stuff>
443
444 /// The private data of @ref suppression_base.
445 class suppression_base::priv
446 {
447 string label_;
448
449 public:
450 priv()
451 {}
452
453 priv(const string& label)
454 : label_(label)
455 {}
456
457 friend class suppression_base;
458 }; // end clas suppression_base::priv
459
460 /// Constructor for @ref suppression_base
461 ///
462 /// @param a label for the suppression. This represents just a
463 /// comment.
464 suppression_base::suppression_base(const string& label)
465 : priv_(new priv(label))
466 {}
467
468 /// Getter for the label associated to this suppression specification.
469 ///
470 /// @return the label.
471 const string
472 suppression_base::get_label() const
473 {return priv_->label_;}
474
475 /// Setter for the label associated to this suppression specification.
476 ///
477 /// @param label the new label.
478 void
479 suppression_base::set_label(const string& label)
480 {priv_->label_ = label;}
481
482 suppression_base::~suppression_base()
483 {}
484
485 static type_suppression_sptr
486 read_type_suppression(const ini::config::section& section);
487
488 static function_suppression_sptr
489 read_function_suppression(const ini::config::section& section);
490
491 static variable_suppression_sptr
492 read_variable_suppression(const ini::config::section& section);
493
494 /// Read a vector of suppression specifications from the sections of
495 /// an ini::config.
496 ///
497 /// Note that this function needs to be updated each time a new kind
498 /// of suppression specification is added.
499 ///
500 /// @param config the config to read from.
501 ///
502 /// @param suppressions out parameter. The vector of suppressions to
503 /// append the newly read suppressions to.
504 static void
505 read_suppressions(const ini::config& config,
506 suppressions_type& suppressions)
507 {
508 suppression_sptr s;
509 for (ini::config::sections_type::const_iterator i =
510 config.get_sections().begin();
511 i != config.get_sections().end();
512 ++i)
513 if ((s = read_type_suppression(**i))
514 || (s = read_function_suppression(**i))
515 || (s = read_variable_suppression(**i)))
516 suppressions.push_back(s);
517
518 }
519
520 /// Read suppressions specifications from an input stream.
521 ///
522 /// @param input the input stream to read from.
523 ///
524 /// @param suppressions the vector of suppressions to append the newly
525 /// read suppressions to.
526 void
527 read_suppressions(std::istream& input,
528 suppressions_type& suppressions)
529 {
530 if (ini::config_sptr config = ini::read_config(input))
531 read_suppressions(*config, suppressions);
532 }
533
534 /// Read suppressions specifications from an input file on disk.
535 ///
536 /// @param input the path to the input file to read from.
537 ///
538 /// @param suppressions the vector of suppressions to append the newly
539 /// read suppressions to.
540 void
541 read_suppressions(const string& file_path,
542 suppressions_type& suppressions)
543 {
544 if (ini::config_sptr config = ini::read_config(file_path))
545 read_suppressions(*config, suppressions);
546 }
547 // </suppression_base stuff>
548
549 // <type_suppression stuff>
550
551 /// The private data for @ref type_suppression.
552 class type_suppression::priv
553 {
554 string type_name_regex_str_;
555 mutable sptr_utils::regex_t_sptr type_name_regex_;
556 string type_name_;
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_;
562
563 priv();
564
565 public:
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)
578 {}
579
580 /// Get the regular expression object associated to the 'type_name_regex'
581 /// property of @ref type_suppression.
582 ///
583 /// If the regular expression object is not created, this method
584 /// creates it and returns it.
585 ///
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
590 {
591 if (!type_name_regex_)
592 {
593 if (!type_name_regex_str_.empty())
594 {
595 sptr_utils::regex_t_sptr r(new regex_t);
596 if (regcomp(r.get(),
597 type_name_regex_str_.c_str(),
598 REG_EXTENDED) == 0)
599 type_name_regex_ = r;
600 }
601 }
602 return type_name_regex_;
603 }
604
605 /// Setter for the type_name_regex object.
606 ///
607 /// @param r the new type_name_regex object.
608 void
609 set_type_name_regex(sptr_utils::regex_t_sptr r)
610 {type_name_regex_ = r;}
611
612 friend class type_suppression;
613 }; // class type_suppression::priv
614
615 /// Constructor for @ref type_suppression.
616 ///
617 /// @param label the label of the suppression. This is just a free
618 /// form comment explaining what the suppression is about.
619 ///
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.
623 ///
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
626 /// ignored.
627 ///
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,
636 type_name,
637 /*consider_type_kind=*/false,
638 /*type_kind=*/CLASS_TYPE_KIND,
639 /*consider_reach_kind=*/false,
640 /*reach_kind=*/DIRECT_REACH_KIND))
641 {}
642
643 type_suppression::~type_suppression()
644 {}
645
646 /// Setter for the "type_name_regex" property of the type suppression
647 /// specification.
648 ///
649 /// This sets a regular expression that specifies the family of types
650 /// about which diff reports should be suppressed.
651 ///
652 /// @param name_regex_str the new regular expression to set.
653 void
654 type_suppression::set_type_name_regex_str(const string& name_regex_str)
655 {priv_->type_name_regex_str_ = name_regex_str;}
656
657 /// Getter for the "type_name_regex" property of the type suppression
658 /// specification.
659 ///
660 /// This returns a regular expression that specifies the family of
661 /// types about which diff reports should be suppressed.
662 ///
663 /// @return the regular expression.
664 const string&
665 type_suppression::get_type_name_regex_str() const
666 {return priv_->type_name_regex_str_;}
667
668 /// Setter for the name of the type about which diff reports should be
669 /// suppressed.
670 ///
671 /// @param name the new type name.
672 void
673 type_suppression::set_type_name(const string& name)
674 {priv_->type_name_ = name;}
675
676 /// Getter for the name of the type about which diff reports should be
677 /// suppressed.
678 ///
679 /// @param return the type name.
680 const string&
681 type_suppression::get_type_name() const
682 {return priv_->type_name_;}
683
684 /// Getter of the property that says whether to consider the kind of
685 /// type this suppression is about.
686 ///
687 /// @return the boolean value of the property.
688 bool
689 type_suppression::get_consider_type_kind() const
690 {return priv_->consider_type_kind_;}
691
692 /// Setter of the property that says whether to consider the kind of
693 /// type this suppression is about.
694 ///
695 /// @param f the new boolean value of the property.
696 void
697 type_suppression::set_consider_type_kind(bool f)
698 {priv_->consider_type_kind_ = f;}
699
700
701 /// Setter of the kind of type this suppression is about.
702 ///
703 /// Note that this will be considered during evaluation of the
704 /// suppression only if type_suppression::get_consider_type_kind()
705 /// returns true.
706 ///
707 /// @param k the new kind of type this suppression is about.
708 void
709 type_suppression::set_type_kind(type_kind k)
710 {priv_->type_kind_ = k;}
711
712 /// Getter of the kind of type this suppression is about.
713 ///
714 /// Note that this will be considered during evaluation of the
715 /// suppression only if type_suppression::get_consider_type_kind()
716 /// returns true.
717 ///
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_;}
722
723 /// Test if the current type suppression specification
724 /// suggests to consider how the matching diff node is reached.
725 ///
726 /// @return true if the current type suppression specification
727 /// suggests to consider how the matching diff node is reached.
728 bool
729 type_suppression::get_consider_reach_kind() const
730 {return priv_->consider_reach_kind_;}
731
732 /// Set a flag saying if the current type suppression specification
733 /// suggests to consider how the matching diff node is reached.
734 ///
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.
738 void
739 type_suppression::set_consider_reach_kind(bool f)
740 {priv_->consider_reach_kind_ = f;}
741
742 /// Getter of the way the diff node matching the current suppression
743 /// specification is to be reached.
744 ///
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_;}
750
751 /// Setter of the way the diff node matching the current suppression
752 /// specification is to be reached.
753 ///
754 /// @param p the way the diff node matching the current suppression
755 /// specification is to be reached.
756 void
757 type_suppression::set_reach_kind(reach_kind k)
758 {priv_->reach_kind_ = k;}
759
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.
763 ///
764 /// @param r the new insertion range vector.
765 void
766 type_suppression::set_data_member_insertion_ranges(const insertion_ranges& r)
767 {priv_->insertion_ranges_ = r;}
768
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.
772 ///
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_;}
777
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.
781 ///
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_;}
786
787 /// Evaluate this suppression specification on a given diff node and
788 /// say if the diff node should be suppressed or not.
789 ///
790 /// @param diff the diff node to evaluate this suppression
791 /// specification against.
792 ///
793 /// @return true if @p diff should be suppressed.
794 bool
795 type_suppression::suppresses_diff(const diff* diff) const
796 {
797 const type_diff_base* d = is_type_diff(diff);
798 if (!d)
799 return false;
800
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())
804 {
805 if (get_reach_kind() == POINTER_REACH_KIND)
806 {
807 if (const pointer_diff* ptr_diff = is_pointer_diff(diff))
808 {
809 d = is_type_diff(ptr_diff->underlying_type_diff().get());
810 assert(d);
811 }
812 else
813 return false;
814 }
815 else if (get_reach_kind() == REFERENCE_REACH_KIND)
816 {
817 if (const reference_diff* ref_diff = is_reference_diff(diff))
818 {
819 d = is_type_diff(ref_diff->underlying_type_diff().get());
820 assert(d);
821 }
822 else
823 return false;
824 }
825 else if (get_reach_kind() == REFERENCE_OR_POINTER_REACH_KIND)
826 {
827 if (const pointer_diff* ptr_diff = is_pointer_diff(diff))
828 {
829 d = is_type_diff(ptr_diff->underlying_type_diff().get());
830 assert(d);
831 }
832 else if (const reference_diff* ref_diff = is_reference_diff(diff))
833 {
834 d = is_type_diff(ref_diff->underlying_type_diff().get());
835 assert(d);
836 }
837 else
838 return false;
839 }
840 }
841
842 type_base_sptr ft, st;
843 ft = is_type(d->first_subject());
844 st = is_type(d->second_subject());
845 assert(ft && st);
846
847 // If the suppression should consider type kind, then well, check
848 // for that.
849 if (get_consider_type_kind())
850 {
851 type_kind k = get_type_kind();
852 switch (k)
853 {
854 case type_suppression::UNKNOWN_TYPE_KIND:
855 case type_suppression::CLASS_TYPE_KIND:
856 if (!is_class_type(ft) && !is_class_type(st))
857 return false;
858 break;
859 case type_suppression::STRUCT_TYPE_KIND:
860 {
861 class_decl_sptr fc = is_class_type(ft), sc = is_class_type(st);
862 if ((!fc && !sc)
863 || (fc && !fc->is_struct() && sc && !sc->is_struct()))
864 return false;
865 }
866 break;
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.
870 abort();
871 case type_suppression::ENUM_TYPE_KIND:
872 if (!is_enum_type(ft) && !is_enum_type(st))
873 return false;
874 break;
875 case type_suppression::ARRAY_TYPE_KIND:
876 if (!is_array_type(ft) && !is_array_type(st))
877 return false;
878 break;
879 case type_suppression::TYPEDEF_TYPE_KIND:
880 if (!is_typedef(ft) && !is_typedef(st))
881 return false;
882 break;
883 case type_suppression::BUILTIN_TYPE_KIND:
884 if (!is_type_decl(ft) && !is_type_decl(st))
885 return false;
886 break;
887 }
888 }
889
890 string fn, sn;
891 fn = get_name(ft);
892 sn = get_name(st);
893
894 // Check if there is an exact type name match.
895 if (!get_type_name().empty())
896 {
897 if (get_type_name() != fn && get_type_name() != sn)
898 return false;
899 }
900 else
901 {
902 // So now check if there is a regular expression match.
903 //
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();
909 if (type_name_regex
910 && (regexec(type_name_regex.get(), fn.c_str(),
911 0, NULL, 0) != 0
912 && regexec(type_name_regex.get(), sn.c_str(),
913 0, NULL, 0) != 0))
914 return false;
915 }
916
917 const class_diff* klass_diff = dynamic_cast<const class_diff*>(diff);
918 if (// We are looking at a class diff ...
919 klass_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()))
928 {
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();
932 ++m)
933 {
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;
941
942 for (insertion_ranges::const_iterator i =
943 get_data_member_insertion_ranges().begin();
944 i != get_data_member_insertion_ranges().end();
945 ++i)
946 {
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
950 (range->begin(),
951 klass_diff->first_class_decl(),
952 range_begin_val))
953 break;
954 if (!type_suppression::insertion_range::eval_boundary
955 (range->end(),
956 klass_diff->first_class_decl(),
957 range_end_val))
958 break;
959
960
961 unsigned range_begin =
962 (range_begin_val < 0) ? first_type_size : range_begin_val;
963
964 unsigned range_end =
965 (range_end_val < 0) ? second_type_size : range_end_val;
966
967 if (range_begin > range_end)
968 continue;
969
970 if (range_begin_val < 0 || range_end_val < 0)
971 {
972 if (dm_offset < range_begin)
973 continue;
974 }
975 else
976 if (dm_offset < range_begin || dm_offset > range_end)
977 continue;
978
979 matched = true;
980 }
981 if (!matched)
982 return false;
983 }
984 }
985
986 return true;
987 }
988
989 /// The private data of type_suppression::insertion_range
990 struct type_suppression::insertion_range::priv
991 {
992 boundary_sptr begin_;
993 boundary_sptr end_;
994
995 priv()
996 {}
997
998 priv(boundary_sptr begin, boundary_sptr end)
999 : begin_(begin), end_(end)
1000 {}
1001 }; // end struct type_suppression::insertion_range::priv
1002
1003 /// Default Constructor of @ref type_suppression::insertion_range.
1004 type_suppression::insertion_range::insertion_range()
1005 : priv_(new priv)
1006 {}
1007
1008 /// Constructor of @ref type_suppression::insertion_range.
1009 ///
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.
1013 ///
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,
1018 boundary_sptr end)
1019 : priv_(new priv(begin, end))
1020 {}
1021
1022 /// Getter for the beginning of the range.
1023 ///
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_;}
1030
1031 /// Getter for the end of the range.
1032 ///
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_;}
1039
1040 /// Create an integer boundary.
1041 ///
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.
1045 ///
1046 /// @param value the value of the integer boundary.
1047 ///
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));}
1052
1053
1054 /// Create a function call expression boundary.
1055 ///
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
1060 /// class_decl.
1061 ///
1062 /// @param expr the function call expression to create the boundary from.
1063 ///
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));}
1068
1069 /// Create a function call expression boundary.
1070 ///
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
1075 /// class_decl.
1076 ///
1077 /// @param s a string representing the expression the function call
1078 /// expression to create the boundary from.
1079 ///
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)
1083 {
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));
1088 return result;
1089 }
1090
1091 /// Evaluate an insertion range boundary to get a resulting integer
1092 /// value.
1093 ///
1094 /// @param boundary the boundary to evaluate.
1095 ///
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
1098 /// it.
1099 ///
1100 /// @return true iff the evaluation was successful and @p value
1101 /// contains the resulting value.
1102 bool
1103 type_suppression::insertion_range::eval_boundary(boundary_sptr boundary,
1104 class_decl_sptr context,
1105 ssize_t& value)
1106 {
1107 if (integer_boundary_sptr b = is_integer_boundary(boundary))
1108 {
1109 value = b->as_integer();
1110 return true;
1111 }
1112 else if (fn_call_expr_boundary_sptr b = is_fn_call_expr_boundary(boundary))
1113 {
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)
1118 {
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();
1123 ++it)
1124 {
1125 if (!get_data_member_is_laid_out(**it))
1126 continue;
1127 if ((*it)->get_name() == member_name)
1128 {
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();
1134 else
1135 // We should not reach this point.
1136 abort();
1137 return true;
1138 }
1139 }
1140 }
1141 }
1142 return false;
1143 }
1144
1145 /// Tests if a given instance of @ref
1146 /// type_suppression::insertion_range::boundary is actually an integer boundary.
1147 ///
1148 /// @param b the boundary to test.
1149 ///
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);}
1156
1157 /// Tests if a given instance of @ref
1158 /// type_suppression::insertion_range::boundary is actually an function call expression boundary.
1159 ///
1160 /// @param b the boundary to test.
1161 ///
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);}
1169
1170 /// The private data type of @ref
1171 /// type_suppression::insertion_range::boundary.
1172 struct type_suppression::insertion_range::boundary::priv
1173 {
1174 priv()
1175 {}
1176 }; // end struct type_suppression::insertion_range::boundary::priv
1177
1178 /// Default constructor of @ref
1179 /// type_suppression::insertion_range::boundary
1180 type_suppression::insertion_range::boundary::boundary()
1181 : priv_(new priv())
1182 {}
1183
1184 /// Destructor of @ref type_suppression::insertion_range::boundary.
1185 type_suppression::insertion_range::boundary::~boundary()
1186 {}
1187
1188 /// Private data type for @ref
1189 /// type_suppression::insertion_range::integer_boundary.
1190 struct type_suppression::insertion_range::integer_boundary::priv
1191 {
1192 int value_;
1193
1194 priv()
1195 : value_()
1196 {}
1197
1198 priv(int value)
1199 : value_(value)
1200 {}
1201 }; // end type_suppression::insertion_range::integer_boundary::priv
1202
1203 /// Converting constructor of
1204 /// type_suppression::insertion_range::integer_boundary.
1205 ///
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))
1209 {}
1210
1211 /// Return the integer value of the current inace of @ref
1212 /// type_suppression::insertion_range::integer_boundary.
1213 ///
1214 /// @return the integer value of the current boundary.
1215 int
1216 type_suppression::insertion_range::integer_boundary::as_integer() const
1217 {return priv_->value_;}
1218
1219 /// Converts the current boundary into an integer value.
1220 ///
1221 /// @return the integer value of the current boundary.
1222 type_suppression::insertion_range::integer_boundary::operator int() const
1223 {return as_integer();}
1224
1225 /// Destructor of @ref type_suppression::insertion_range::integer_boundary.
1226 type_suppression::insertion_range::integer_boundary::~integer_boundary()
1227 {}
1228
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
1232 {
1233 ini::function_call_expr_sptr expr_;
1234
1235 priv()
1236 {}
1237
1238 priv(ini::function_call_expr_sptr expr)
1239 : expr_(expr)
1240 {}
1241 }; // end struct type_suppression::insertion_range::fn_call_expr_boundary::priv
1242
1243 /// Converting constructor for @ref
1244 /// type_suppression::insertion_range::fn_call_expr_boundary.
1245 ///
1246 /// @param expr the function call expression to build this boundary
1247 /// from.
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))
1251 {}
1252
1253 /// Returns the function call expression value of the current boundary.
1254 ///
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_;}
1259
1260 /// Converts the current boundary to its function call expression value.
1261 ///
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();}
1265
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()
1269 {}
1270
1271 // </type_suppression stuff>
1272
1273 /// Parse the value of the "type_kind" property in the "suppress_type"
1274 /// section.
1275 ///
1276 /// @param input the input string representing the value of the
1277 /// "type_kind" property.
1278 ///
1279 /// @return the @ref type_kind enumerator parsed.
1280 static type_suppression::type_kind
1281 read_type_kind_string(const string& input)
1282 {
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;
1297 else
1298 return type_suppression::UNKNOWN_TYPE_KIND;
1299 }
1300
1301 /// Parse the value of the "accessed_through" property in the
1302 /// "suppress_type" section.
1303 ///
1304 /// @param input the input string representing the value of the
1305 /// "accessed_through" property.
1306 ///
1307 /// @return the @ref type_suppression::reach_kind enumerator parsed.
1308 static type_suppression::reach_kind
1309 read_suppression_reach_kind(const string& input)
1310 {
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;
1319 else
1320 return type_suppression::DIRECT_REACH_KIND;
1321 }
1322
1323 /// Read a type suppression from an instance of ini::config::section
1324 /// and build a @ref type_suppression as a result.
1325 ///
1326 /// @param section the section of the ini config to read.
1327 ///
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)
1332 {
1333 type_suppression_sptr nil;
1334
1335 if (section.get_name() != "suppress_type")
1336 return nil;
1337
1338 ini::simple_property_sptr label =
1339 is_simple_property(section.find_property("label"));
1340 string label_str = label ? label->get_value()->as_string() : ":";
1341
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()
1346 : "";
1347
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()
1352 : "";
1353
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")))
1358 {
1359 consider_type_kind = true;
1360 type_kind =
1361 read_type_kind_string(type_kind_prop->get_value()->as_string());
1362 }
1363
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")))
1368 {
1369 consider_reach_kind = true;
1370 reach_kind =
1371 read_suppression_reach_kind(reach_kind_prop->get_value()->as_string());
1372 }
1373
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")))
1379 {
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)))
1391 begin = expr;
1392 else
1393 return nil;
1394
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;
1400 }
1401
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")))
1406 {
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]))
1415 {
1416 string str = prop->get_value()->get_value_items()[0]->as_string();
1417 if (str == "end")
1418 begin =
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)))
1425 begin = expr;
1426 else
1427 return nil;
1428
1429 str = prop->get_value()->get_value_items()[1]->as_string();
1430 if (str == "end")
1431 end =
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)))
1438 end = expr;
1439 else
1440 return nil;
1441
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;
1446 }
1447 else
1448 // the 'has_data_member_inserted_between' property has a wrong
1449 // value type, so let's discard the endire [suppress_type]
1450 // section.
1451 return nil;
1452 }
1453
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")))
1458 {
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();
1463 ++i)
1464 {
1465 ini::tuple_property_value_sptr tuple_value =
1466 is_tuple_property_value(*i);
1467 if (!tuple_value
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;
1472
1473 type_suppression::insertion_range::boundary_sptr begin, end;
1474 string str = tuple_value->get_value_items()[0]->as_string();
1475 if (str == "end")
1476 begin =
1477 type_suppression::insertion_range::create_integer_boundary(-1);
1478 else if (isdigit(str[0]))
1479 begin =
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)))
1484 begin = expr;
1485 else
1486 return nil;
1487
1488 str = tuple_value->get_value_items()[1]->as_string();
1489 if (str == "end")
1490 end =
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)))
1497 end = expr;
1498 else
1499 return nil;
1500
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;
1505 }
1506 if (!is_well_formed)
1507 return nil;
1508 }
1509
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)
1513 return nil;
1514
1515 type_suppression_sptr suppr(new type_suppression(label_str,
1516 name_regex_str,
1517 name_str));
1518 if (consider_type_kind)
1519 {
1520 suppr->set_consider_type_kind(true);
1521 suppr->set_type_kind(type_kind);
1522 }
1523
1524 if (consider_reach_kind)
1525 {
1526 suppr->set_consider_reach_kind(true);
1527 suppr->set_reach_kind(reach_kind);
1528 }
1529
1530 if (consider_data_member_insertion)
1531 suppr->set_data_member_insertion_ranges(insert_ranges);
1532
1533 return suppr;
1534 }
1535
1536 // <function_suppression stuff>
1537 class function_suppression::parameter_spec::priv
1538 {
1539 friend class function_suppression::parameter_spec;
1540 friend class function_suppression;
1541
1542 size_t index_;
1543 string type_name_;
1544 string type_name_regex_str_;
1545 mutable sptr_utils::regex_t_sptr type_name_regex_;
1546
1547 priv()
1548 : index_()
1549 {}
1550
1551 priv(size_t i, const string& tn)
1552 : index_(i), type_name_(tn)
1553 {}
1554
1555 priv(size_t i, const string& tn, const string& tn_regex)
1556 : index_(i), type_name_(tn), type_name_regex_str_(tn_regex)
1557 {}
1558
1559 const sptr_utils::regex_t_sptr
1560 get_type_name_regex() const
1561 {
1562 if (!type_name_regex_ && !type_name_regex_str_.empty())
1563 {
1564 sptr_utils::regex_t_sptr r(new regex_t);
1565 if (regcomp(r.get(),
1566 type_name_regex_str_.c_str(),
1567 REG_EXTENDED) == 0)
1568 type_name_regex_ = r;
1569 }
1570 return type_name_regex_;
1571 }
1572 }; // end class function_suppression::parameter_spec::priv
1573
1574 /// Constructor for the @ref the function_suppression::parameter_spec
1575 /// type.
1576 ///
1577 /// @param i the index of the parameter designated by this specification.
1578 ///
1579 /// @param tn the type name of the parameter designated by this specification.
1580 ///
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,
1586 const string& tn,
1587 const string& tn_regex)
1588 : priv_(new priv(i, tn, tn_regex))
1589 {}
1590
1591 /// Getter for the index of the parameter designated by this
1592 /// specification.
1593 ///
1594 /// @return the index of the parameter designated by this
1595 /// specification.
1596 size_t
1597 function_suppression::parameter_spec::get_index() const
1598 {return priv_->index_;}
1599
1600 /// Setter for the index of the parameter designated by this
1601 /// specification.
1602 ///
1603 /// @param i the new index to set.
1604 void
1605 function_suppression::parameter_spec::set_index(size_t i)
1606 {priv_->index_ = i;}
1607
1608 /// Getter for the type name of the parameter designated by this specification.
1609 ///
1610 /// @return the type name of the parameter.
1611 const string&
1612 function_suppression::parameter_spec::get_parameter_type_name() const
1613 {return priv_->type_name_;}
1614
1615 /// Setter for the type name of the parameter designated by this
1616 /// specification.
1617 ///
1618 /// @param tn new parameter type name to set.
1619 void
1620 function_suppression::parameter_spec::set_parameter_type_name(const string& tn)
1621 {priv_->type_name_ = tn;}
1622
1623 /// Getter for the regular expression that defines a set of type names
1624 /// for the parameter designated by this specification.
1625 ///
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
1629 /// empty.
1630 ///
1631 /// @return the regular expression or the parameter type name.
1632 const string&
1633 function_suppression::parameter_spec::get_parameter_type_name_regex_str() const
1634 {return priv_->type_name_regex_str_;}
1635
1636 /// Setter for the regular expression that defines a set of type names
1637 /// for the parameter designated by this specification.
1638 ///
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
1642 /// empty.
1643 ///
1644 /// @param type_name_regex_str the new type name regular expression to
1645 /// set.
1646 void
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;}
1650
1651 /// The type of the private data of the @ref function_suppression
1652 /// type.
1653 class function_suppression::priv
1654 {
1655 friend class function_suppression;
1656
1657 string name_;
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_;
1670
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)
1680 : name_(name),
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)
1689 {}
1690
1691
1692 /// Getter for a pointer to a regular expression object built from
1693 /// the regular expression string
1694 /// function_suppression::priv::name_regex_str_.
1695 ///
1696 /// If that string is empty, then an empty regular expression object
1697 /// pointer is returned.
1698 ///
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
1703 {
1704 if (!name_regex_ && !name_regex_str_.empty())
1705 {
1706 sptr_utils::regex_t_sptr r(new regex_t);
1707 if (regcomp(r.get(),
1708 name_regex_str_.c_str(),
1709 REG_EXTENDED) == 0)
1710 name_regex_ = r;
1711 }
1712 return name_regex_;
1713 }
1714
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_.
1718 ///
1719 /// If that string is empty, then an empty regular expression object
1720 /// pointer is returned.
1721 ///
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
1726 {
1727 if (!return_type_regex_ && !return_type_regex_str_.empty())
1728 {
1729 sptr_utils::regex_t_sptr r(new regex_t);
1730 if (regcomp(r.get(),
1731 return_type_regex_str_.c_str(),
1732 REG_EXTENDED) == 0)
1733 return_type_regex_ = r;
1734 }
1735 return return_type_regex_;
1736 }
1737
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_.
1741 ///
1742 /// If that string is empty, then an empty regular expression object
1743 /// pointer is returned.
1744 ///
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
1749 {
1750 if (!symbol_name_regex_ && !symbol_name_regex_str_.empty())
1751 {
1752 sptr_utils::regex_t_sptr r(new regex_t);
1753 if (regcomp(r.get(),
1754 symbol_name_regex_str_.c_str(),
1755 REG_EXTENDED) == 0)
1756 symbol_name_regex_ = r;
1757 }
1758 return symbol_name_regex_;
1759 }
1760
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_.
1764 ///
1765 /// If that string is empty, then an empty regular expression object
1766 /// pointer is returned.
1767 ///
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
1772 {
1773 if (!symbol_version_regex_ && ! symbol_version_regex_str_.empty())
1774 {
1775 sptr_utils::regex_t_sptr r(new regex_t);
1776 if (regcomp(r.get(),
1777 symbol_version_regex_str_.c_str(),
1778 REG_EXTENDED) == 0)
1779 symbol_version_regex_ = r;
1780 }
1781 return symbol_version_regex_;
1782 }
1783 }; // end class function_suppression::priv
1784
1785 /// Constructor for the @ref function_suppression type.
1786 ///
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.
1791 ///
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.
1795 ///
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
1801 /// time.
1802 ///
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.
1806 ///
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.
1813 ///
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.
1818 ///
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.
1822 ///
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.
1829 ///
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.
1833 ///
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,
1841 const string& name,
1842 const string& nr,
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))
1853 {}
1854
1855 function_suppression::~function_suppression()
1856 {}
1857
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.
1861 ///
1862 /// @return the name of the function.
1863 const string&
1864 function_suppression::get_function_name() const
1865 {return priv_->name_;}
1866
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.
1870 ///
1871 /// @param n the new function name to set.
1872 void
1873 function_suppression::set_function_name(const string& n)
1874 {priv_->name_ = n;}
1875
1876 /// Getter for a regular expression for a family of names of functions
1877 /// the user wants the current specification to designate.
1878 ///
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
1883 /// time.
1884 ///
1885 /// @return the regular expression for the possible names of the
1886 /// function(s).
1887 const string&
1888 function_suppression::get_function_name_regex_str() const
1889 {return priv_->name_regex_str_;}
1890
1891 /// Setter for a regular expression for a family of names of functions
1892 /// the user wants the current specification to designate.
1893 ///
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
1898 /// time.
1899 ///
1900 /// @param r the new the regular expression for the possible names of
1901 /// the function(s).
1902 void
1903 function_suppression::set_function_name_regex_str(const string& r)
1904 {priv_->name_regex_str_ = r;}
1905
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.
1909 ///
1910 /// @return the name of the return type of the function.
1911 const string&
1912 function_suppression::get_return_type_name() const
1913 {return priv_->return_type_name_;}
1914
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.
1918 ///
1919 /// @param tr the new name of the return type of the function to set.
1920 void
1921 function_suppression::set_return_type_name(const string& tr)
1922 {priv_->return_type_name_ = tr;}
1923
1924 /// Getter for a regular expression for a family of return type names
1925 /// for functions the user wants the current specification to
1926 /// designate.
1927 ///
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
1932 /// time.
1933 ///
1934 /// @return the regular expression for the possible names of the
1935 /// return types of the function(s).
1936 const string&
1937 function_suppression::get_return_type_regex_str() const
1938 {return priv_->return_type_regex_str_;}
1939
1940 /// Setter for a regular expression for a family of return type names
1941 /// for functions the user wants the current specification to
1942 /// designate.
1943 ///
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
1948 /// time.
1949 ///
1950 /// @param r the new regular expression for the possible names of the
1951 /// return types of the function(s) to set.
1952 void
1953 function_suppression::set_return_type_regex_str(const string& r)
1954 {priv_->return_type_regex_str_ = r;}
1955
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.
1959 ///
1960 /// This property might be empty, in which case it's ignored at
1961 /// evaluation time.
1962 ///
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_;}
1967
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.
1971 ///
1972 /// This property might be empty, in which case it's ignored at
1973 /// evaluation time.
1974 ///
1975 /// @param p the new specifications of the parameters of the
1976 /// function(s) to set.
1977 void
1978 function_suppression::set_parameter_specs(parameter_specs_type& p)
1979 {priv_->parm_specs_ = p;}
1980
1981 /// Append a specification of a parameter of the function specification.
1982 ///
1983 /// @param p the parameter specification to add.
1984 void
1985 function_suppression::append_parameter_specs(const parameter_spec_sptr p)
1986 {priv_->parm_specs_.push_back(p);}
1987
1988 /// Getter for the name of symbol of the function the user wants this
1989 /// specification to designate.
1990 ///
1991 /// This property might be empty, in which case it's ignored at
1992 /// evaluation time.
1993 ///
1994 /// @return name of the symbol of the function.
1995 const string&
1996 function_suppression::get_symbol_name() const
1997 {return priv_->symbol_name_;}
1998
1999 /// Setter for the name of symbol of the function the user wants this
2000 /// specification to designate.
2001 ///
2002 /// This property might be empty, in which case it's ignored at
2003 /// evaluation time.
2004 ///
2005 /// @return name of the symbol of the function.
2006 void
2007 function_suppression::set_symbol_name(const string& n)
2008 {priv_->symbol_name_ = n;}
2009
2010 /// Getter for a regular expression for a family of names of symbols
2011 /// of functions the user wants this specification to designate.
2012 ///
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.
2016 ///
2017 /// This property might be empty, in which case it's ignored at
2018 /// evaluation time.
2019 ///
2020 /// @return the regular expression for a family of names of symbols of
2021 /// functions to designate.
2022 const string&
2023 function_suppression::get_symbol_name_regex_str() const
2024 {return priv_->symbol_name_regex_str_;}
2025
2026 /// Setter for a regular expression for a family of names of symbols
2027 /// of functions the user wants this specification to designate.
2028 ///
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.
2032 ///
2033 /// This property might be empty, in which case it's ignored at
2034 /// evaluation time.
2035 ///
2036 /// @param r the new regular expression for a family of names of
2037 /// symbols of functions to set.
2038 void
2039 function_suppression::set_symbol_name_regex_str(const string& r)
2040 {priv_->symbol_name_regex_str_ = r;}
2041
2042 /// Getter for the name of the version of the symbol of the function
2043 /// the user wants this specification to designate.
2044 ///
2045 /// This property might be empty, in which case it's ignored at
2046 /// evaluation time.
2047 ///
2048 /// @return the symbol version of the function.
2049 const string&
2050 function_suppression::get_symbol_version() const
2051 {return priv_->symbol_version_;}
2052
2053 /// Setter for the name of the version of the symbol of the function
2054 /// the user wants this specification to designate.
2055 ///
2056 /// This property might be empty, in which case it's ignored at
2057 /// evaluation time.
2058 ///
2059 /// @param v the new symbol version of the function.
2060 void
2061 function_suppression::set_symbol_version(const string& v)
2062 {priv_->symbol_version_ = v;}
2063
2064 /// Getter for a regular expression for a family of versions of
2065 /// symbols of functions the user wants the current specification to
2066 /// designate.
2067 ///
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.
2072 ///
2073 /// @return the regular expression for the versions of symbols of
2074 /// functions to designate.
2075 const string&
2076 function_suppression::get_symbol_version_regex_str() const
2077 {return priv_->symbol_version_regex_str_;}
2078
2079 /// Setter for a regular expression for a family of versions of
2080 /// symbols of functions the user wants the current specification to
2081 /// designate.
2082 ///
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.
2087 ///
2088 /// @param the new regular expression for the versions of symbols of
2089 /// functions to designate.
2090 void
2091 function_suppression::set_symbol_version_regex_str(const string& r)
2092 {priv_->symbol_version_regex_str_ = r;}
2093
2094 /// Evaluate this suppression specification on a given diff node and
2095 /// say if the diff node should be suppressed or not.
2096 ///
2097 /// @param diff the diff node to evaluate this suppression
2098 /// specification against.
2099 ///
2100 /// @return true if @p diff should be suppressed.
2101 bool
2102 function_suppression::suppresses_diff(const diff* diff) const
2103 {
2104 const function_decl_diff* d = is_function_decl_diff(diff);
2105 if (!d)
2106 return false;
2107
2108 function_decl_sptr ff = is_function_decl(d->first_function_decl()),
2109 sf = is_function_decl(d->second_function_decl());
2110 assert(ff && sf);
2111
2112 string ff_name = ff->get_qualified_name(), sf_name = sf->get_qualified_name();
2113
2114 // Check if the "name" property matches.
2115 if (!get_function_name().empty())
2116 {
2117 string n = get_function_name();
2118 if (n != ff->get_qualified_name()
2119 && n != sf->get_qualified_name())
2120 return false;
2121 }
2122
2123 // Check if the "name_regexp" property matches.
2124 const sptr_utils::regex_t_sptr name_regex = priv_->get_name_regex();
2125 if (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))
2128 return false;
2129
2130 // Check if the "return_type_name" or "return_type_regexp"
2131 // properties matches.
2132
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())
2136 : "";
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())
2140 : "";
2141
2142 if (!get_return_type_name().empty())
2143 {
2144 if (ff_return_type_name != get_return_type_name()
2145 && sf_return_type_name != get_return_type_name())
2146 return false;
2147 }
2148 else
2149 {
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(),
2155 0, NULL, 0) != 0
2156 && regexec(return_type_regex.get(),
2157 sf_return_type_name.c_str(),
2158 0, NULL, 0) != 0))
2159 return false;
2160 }
2161
2162 // Check if the "symbol_name" and "symbol_name_regexp" properties
2163 // match.
2164
2165 string ff_sym_name, ff_sym_version, sf_sym_name, sf_sym_version;
2166 if (ff->get_symbol())
2167 {
2168 ff_sym_name = ff->get_symbol()->get_name();
2169 ff_sym_version = ff->get_symbol()->get_version().str();
2170 }
2171 if (sf->get_symbol())
2172 {
2173 sf_sym_name = sf->get_symbol()->get_name();
2174 sf_sym_version = sf->get_symbol()->get_version().str();
2175 }
2176
2177 if (!get_symbol_name().empty())
2178 {
2179 if (ff_sym_name != get_symbol_name()
2180 && sf_sym_name != get_symbol_name())
2181 return false;
2182 }
2183 else
2184 {
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(),
2190 0, NULL, 0) != 0
2191 && regexec(symbol_name_regex.get(),
2192 sf_sym_name.c_str(),
2193 0, NULL, 0) != 0))
2194 return false;
2195 }
2196
2197 // Check if the "symbol_version" and "symbol_version_regexp"
2198 // properties match.
2199 if (!get_symbol_version().empty())
2200 {
2201 if (ff_sym_version != get_symbol_version()
2202 && sf_sym_name != get_symbol_version())
2203 return false;
2204 }
2205 else
2206 {
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(),
2212 0, NULL, 0) != 0
2213 && regexec(symbol_version_regex.get(),
2214 sf_sym_version.c_str(),
2215 0, NULL, 0) != 0))
2216 return false;
2217 }
2218
2219 if (!get_parameter_specs().empty())
2220 {
2221 function_type_sptr ff_type = ff->get_type();
2222 function_type_sptr sf_type = sf->get_type();
2223 type_base_sptr parm_type;
2224
2225 for (parameter_specs_type::const_iterator p =
2226 get_parameter_specs().begin();
2227 p != get_parameter_specs().end();
2228 ++p)
2229 {
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)
2236 return false;
2237
2238 string ff_parm_type_qualified_name, sf_parm_type_qualified_name;
2239 if (ff_parm)
2240 {
2241 parm_type = ff_parm->get_type();
2242 ff_parm_type_qualified_name =
2243 get_type_declaration(parm_type)->get_qualified_name();
2244 }
2245
2246 if (sf_parm)
2247 {
2248 parm_type = sf_parm->get_type();
2249 sf_parm_type_qualified_name =
2250 get_type_declaration(parm_type)->get_qualified_name();
2251 }
2252
2253 const string& tn = (*p)->get_parameter_type_name();
2254 if (!tn.empty())
2255 {
2256 if (tn != ff_parm_type_qualified_name
2257 && tn != sf_parm_type_qualified_name)
2258 return false;
2259 }
2260 else
2261 {
2262 const sptr_utils::regex_t_sptr parm_type_name_regex =
2263 (*p)->priv_->get_type_name_regex();
2264 if (parm_type_name_regex)
2265 {
2266 if ((regexec(parm_type_name_regex.get(),
2267 ff_parm_type_qualified_name.c_str(),
2268 0, NULL, 0) != 0
2269 && regexec(parm_type_name_regex.get(),
2270 sf_parm_type_qualified_name.c_str(),
2271 0, NULL, 0) != 0))
2272 return false;
2273 }
2274 }
2275 }
2276 }
2277
2278 return true;
2279 }
2280
2281 /// Parse a string containing a parameter spec, build an instance of
2282 /// function_suppression::parameter_spec from it and return a pointer
2283 /// to that object.
2284 ///
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)
2290 {
2291 string::size_type cur = 0;
2292 function_suppression::parameter_spec_sptr result;
2293
2294 // skip leading white spaces.
2295 for (; cur < str.size(); ++cur)
2296 if (!isspace(str[cur]))
2297 break;
2298
2299 // look for the parameter index
2300 string index_str;
2301 if (str[cur] == '\'')
2302 {
2303 ++cur;
2304 for (; cur < str.size(); ++cur)
2305 if (!isdigit(str[cur]))
2306 break;
2307 else
2308 index_str += str[cur];
2309 }
2310
2311 // skip white spaces.
2312 for (; cur < str.size(); ++cur)
2313 if (!isspace(str[cur]))
2314 break;
2315
2316 bool is_regex = false;
2317 if (str[cur] == '/')
2318 {
2319 is_regex = true;
2320 ++ cur;
2321 }
2322
2323 // look for the type name (regex)
2324 string type_name;
2325 for (; cur < str.size(); ++cur)
2326 if (!isspace(str[cur]))
2327 {
2328 if (is_regex && str[cur] == '/')
2329 break;
2330 type_name += str[cur];
2331 }
2332
2333 if (is_regex && str[cur] == '/')
2334 ++cur;
2335
2336 if (!index_str.empty() || !type_name.empty())
2337 {
2338 function_suppression::parameter_spec* p;
2339 if (is_regex)
2340 p = new function_suppression::parameter_spec(atoi(index_str.c_str()),
2341 "", type_name);
2342 else
2343 p = new function_suppression::parameter_spec(atoi(index_str.c_str()),
2344 type_name, "");
2345 result.reset(p);
2346 }
2347
2348 return result;
2349 }
2350
2351 /// Parse function suppression specification, build a resulting @ref
2352 /// function_suppression type and return a shared pointer to that
2353 /// object.
2354 ///
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)
2360 {
2361 function_suppression_sptr nil;
2362
2363 if (section.get_name() != "suppress_function")
2364 return nil;
2365
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()
2370 : "";
2371
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()
2376 : "";
2377
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()
2382 : "";
2383
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()
2388 : "";
2389
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()
2394 : "";
2395
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()
2400 : "";
2401
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()
2406 : "";
2407
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()
2412 : "";
2413
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()
2418 : "";
2419
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();
2425 ++p)
2426 if ((*p)->get_name() == "parameter")
2427 {
2428 ini::simple_property_sptr prop = is_simple_property(*p);
2429 assert(prop);
2430 if (parm = read_parameter_spec_from_string
2431 (prop->get_value()->as_string()))
2432 parms.push_back(parm);
2433 }
2434
2435 function_suppression_sptr result;
2436 if (!label_str.empty()
2437 || !name.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()
2445 || !parms.empty())
2446 result.reset(new function_suppression(label_str, name,
2447 name_regex_str,
2448 return_type_name,
2449 return_type_regex_str,
2450 parms,
2451 sym_name,
2452 sym_name_regex_str,
2453 sym_version,
2454 sym_ver_regex_str));
2455
2456 return result;
2457 }
2458
2459 // </function_suppression stuff>
2460
2461 // <variable_suppression stuff>
2462
2463 /// The type of the private data of the @ref variable_suppression
2464 /// type.
2465 class variable_suppression::priv
2466 {
2467 friend class variable_suppression;
2468
2469 string name_;
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_;
2478 string type_name_;
2479 string type_name_regex_str_;
2480 mutable sptr_utils::regex_t_sptr type_name_regex_;
2481
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)
2490 : name_(name),
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)
2498 {}
2499
2500 /// Getter for a pointer to a regular expression object built from
2501 /// the regular expression string
2502 /// variable_suppression::priv::name_regex_str_.
2503 ///
2504 /// If that string is empty, then an empty regular expression object
2505 /// pointer is returned.
2506 ///
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
2511 {
2512 if (!name_regex_ && !name_regex_str_.empty())
2513 {
2514 sptr_utils::regex_t_sptr r(new regex_t);
2515 if (regcomp(r.get(),
2516 name_regex_str_.c_str(),
2517 REG_EXTENDED) == 0)
2518 name_regex_ = r;
2519 }
2520 return name_regex_;
2521 }
2522
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_.
2526 ///
2527 /// If that string is empty, then an empty regular expression object
2528 /// pointer is returned.
2529 ///
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
2534 {
2535 if (!symbol_name_regex_ && !symbol_name_regex_str_.empty())
2536 {
2537 sptr_utils::regex_t_sptr r(new regex_t);
2538 if (regcomp(r.get(),
2539 symbol_name_regex_str_.c_str(),
2540 REG_EXTENDED) == 0)
2541 symbol_name_regex_ = r;
2542 }
2543 return symbol_name_regex_;
2544 }
2545
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_.
2549 ///
2550 /// If that string is empty, then an empty regular expression object
2551 /// pointer is returned.
2552 ///
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
2557 {
2558 if (!symbol_version_regex_ && !symbol_version_regex_str_.empty())
2559 {
2560 sptr_utils::regex_t_sptr r(new regex_t);
2561 if (regcomp(r.get(),
2562 symbol_version_regex_str_.c_str(),
2563 REG_EXTENDED) == 0)
2564 symbol_version_regex_ = r;
2565 }
2566 return symbol_version_regex_;
2567 }
2568
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_.
2572 ///
2573 /// If that string is empty, then an empty regular expression object
2574 /// pointer is returned.
2575 ///
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
2580 {
2581 if (!type_name_regex_ && !type_name_regex_str_.empty())
2582 {
2583 sptr_utils::regex_t_sptr r(new regex_t);
2584 if (regcomp(r.get(),
2585 type_name_regex_str_.c_str(),
2586 REG_EXTENDED) == 0)
2587 type_name_regex_ = r;
2588 }
2589 return type_name_regex_;
2590 }
2591 };// end class variable_supppression::priv
2592
2593 /// Constructor for the @ref variable_suppression type.
2594 ///
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.
2599 ///
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.
2603 ///
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
2609 /// time.
2610 ///
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.
2614 ///
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.
2621 ///
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
2625 /// time.
2626 ///
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.
2633 ///
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.
2637 ///
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,
2645 const string& name,
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))
2658 {}
2659
2660 /// Virtual destructor for the @erf variable_suppression type.
2661 /// variable_suppression type.
2662 variable_suppression::~variable_suppression()
2663 {}
2664
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.
2668 ///
2669 /// @return the name of the variable.
2670 const string&
2671 variable_suppression::get_name() const
2672 {return priv_->name_;}
2673
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.
2677 ///
2678 /// @param n the new name of the variable to set.
2679 void
2680 variable_suppression::set_name(const string& n)
2681 {priv_->name_ = n;}
2682
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.
2689 ///
2690 /// @return the regular expression for the variable name.
2691 const string&
2692 variable_suppression::get_name_regex_str() const
2693 {return priv_->name_regex_str_;}
2694
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.
2701 ///
2702 /// @param r the new regular expression for the variable name.
2703 void
2704 variable_suppression::set_name_regex_str(const string& r)
2705 {priv_->name_regex_str_ = r;}
2706
2707 /// Getter for the name of the symbol of the variable the user wants
2708 /// the current specification to designate.
2709 ///
2710 /// This property might be empty, in which case it is ignored at
2711 /// evaluation time.
2712 ///
2713 /// @return the name of the symbol of the variable.
2714 const string&
2715 variable_suppression::get_symbol_name() const
2716 {return priv_->symbol_name_;}
2717
2718 /// Setter for the name of the symbol of the variable the user wants
2719 /// the current specification to designate.
2720 ///
2721 /// This property might be empty, in which case it is ignored at
2722 /// evaluation time.
2723 ///
2724 /// @param n the new name of the symbol of the variable.
2725 void
2726 variable_suppression::set_symbol_name(const string& n)
2727 {priv_->symbol_name_ = n;}
2728
2729 /// Getter of the regular expression for a family of symbol names of
2730 /// the variables this specification is about to designate.
2731 ///
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
2735 /// empty.
2736 ///
2737 /// @return the regular expression for a symbol name of the variable.
2738 const string&
2739 variable_suppression::get_symbol_name_regex_str() const
2740 {return priv_->symbol_name_regex_str_;}
2741
2742 /// Setter of the regular expression for a family of symbol names of
2743 /// the variables this specification is about to designate.
2744 ///
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
2748 /// empty.
2749 ///
2750 /// @param r the regular expression for a symbol name of the variable.
2751 void
2752 variable_suppression::set_symbol_name_regex_str(const string& r)
2753 {priv_->symbol_name_regex_str_ = r;}
2754
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.
2758 ///
2759 /// @return the symbol version of the variable.
2760 const string&
2761 variable_suppression::get_symbol_version() const
2762 {return priv_->symbol_version_;}
2763
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.
2767 ///
2768 /// @return the new symbol version of the variable.
2769 void
2770 variable_suppression::set_symbol_version(const string& v)
2771 {priv_->symbol_version_ = v;}
2772
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.
2778 ///
2779 /// @return the regular expression of the symbol version of the
2780 /// variable.
2781 const string&
2782 variable_suppression::get_symbol_version_regex_str() const
2783 {return priv_->symbol_version_regex_str_;}
2784
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.
2790 ///
2791 /// @param v the new regular expression of the symbol version of the
2792 /// variable.
2793 void
2794 variable_suppression::set_symbol_version_regex_str(const string& r)
2795 {priv_->symbol_version_regex_str_ = r;}
2796
2797 /// Getter for the name of the type of the variable the user wants the
2798 /// current specification to designate.
2799 ///
2800 /// This property might be empty, in which case it's ignored at
2801 /// evaluation time.
2802 ///
2803 /// @return the name of the variable type.
2804 const string&
2805 variable_suppression::get_type_name() const
2806 {return priv_->type_name_;}
2807
2808 /// Setter for the name of the type of the variable the user wants the
2809 /// current specification to designate.
2810 ///
2811 /// This property might be empty, in which case it's ignored at
2812 /// evaluation time.
2813 ///
2814 /// @param n the new name of the variable type.
2815 void
2816 variable_suppression::set_type_name(const string& n)
2817 {priv_->type_name_ = n;}
2818
2819 /// Getter for the regular expression for a family of type names of
2820 /// variables the user wants the current specification to designate.
2821 ///
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.
2826 ///
2827 /// @return the regular expression of the variable type name.
2828 const string&
2829 variable_suppression::get_type_name_regex_str() const
2830 {return priv_->type_name_regex_str_;}
2831
2832 /// Setter for the regular expression for a family of type names of
2833 /// variables the user wants the current specification to designate.
2834 ///
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.
2839 ///
2840 /// @param r the regular expression of the variable type name.
2841 void
2842 variable_suppression::set_type_name_regex_str(const string& r)
2843 {priv_->type_name_regex_str_ = r;}
2844
2845 /// Evaluate this suppression specification on a given diff node and
2846 /// say if the diff node should be suppressed or not.
2847 ///
2848 /// @param diff the diff node to evaluate this suppression
2849 /// specification against.
2850 ///
2851 /// @return true if @p diff should be suppressed.
2852 bool
2853 variable_suppression::suppresses_diff(const diff* diff) const
2854 {
2855 const var_diff* d = is_var_diff(diff);
2856 if (!d)
2857 return false;
2858
2859 var_decl_sptr fv = is_var_decl(is_decl(d->first_subject())),
2860 sv = is_var_decl(is_decl(d->second_subject()));
2861
2862 assert(fv && sv);
2863
2864 string fv_name = fv->get_name(), sv_name = sv->get_name();
2865
2866 // Check for "name" property match.
2867 if (!get_name().empty())
2868 {
2869 if (get_name() != fv_name && get_name () != sv_name)
2870 return false;
2871 }
2872 else
2873 {
2874 // If the "name" property is empty, then consider checking for the
2875 // "name_regex" property match
2876 if (get_name().empty())
2877 {
2878 const sptr_utils::regex_t_sptr name_regex = priv_->get_name_regex();
2879 if (name_regex
2880 && (regexec(name_regex.get(), fv_name.c_str(),
2881 0, NULL, 0) != 0
2882 && regexec(name_regex.get(), sv_name.c_str(),
2883 0, NULL, 0) != 0))
2884 return false;
2885 }
2886 }
2887
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())
2892 {
2893 if (get_symbol_name() != fv_sym_name && get_symbol_name() != sv_sym_name)
2894 return false;
2895 }
2896 else
2897 {
2898 const sptr_utils::regex_t_sptr sym_name_regex =
2899 priv_->get_symbol_name_regex();
2900 if (sym_name_regex
2901 && (regexec(sym_name_regex.get(), fv_sym_name.c_str(),
2902 0, NULL, 0) != 0
2903 && regexec(sym_name_regex.get(), sv_sym_name.c_str(),
2904 0, NULL, 0) != 0))
2905 return false;
2906 }
2907
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())
2914 {
2915 if (get_symbol_version() != fv_sym_version
2916 && get_symbol_version() != sv_sym_version)
2917 return false;
2918 }
2919 else
2920 {
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(),
2926 0, NULL, 0) != 0
2927 && regexec(symbol_version_regex.get(),
2928 sv_sym_version.c_str(),
2929 0, NULL, 0) != 0))
2930 return false;
2931 }
2932
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();
2937
2938 // Check for the "type_name" and tye_name_regex properties match.
2939 if (!get_type_name().empty())
2940 {
2941 if (get_type_name() != fv_type_name && get_type_name() != sv_type_name)
2942 return false;
2943 }
2944 else
2945 {
2946 if (get_type_name().empty())
2947 {
2948 const sptr_utils::regex_t_sptr type_name_regex =
2949 priv_->get_type_name_regex();
2950 if (type_name_regex
2951 && (regexec(type_name_regex.get(), fv_type_name.c_str(),
2952 0, NULL, 0) != 0
2953 && regexec(type_name_regex.get(), sv_type_name.c_str(),
2954 0, NULL, 0) != 0))
2955 return false;
2956 }
2957 }
2958
2959 return true;
2960 }
2961
2962 /// Parse variable suppression specification, build a resulting @ref
2963 /// variable_suppression type and return a shared pointer to that
2964 /// object.
2965 ///
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)
2971 {
2972 variable_suppression_sptr result;
2973
2974 if (section.get_name() != "suppress_variable")
2975 return result;
2976
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()
2981 : "");
2982
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()
2987 : "");
2988
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()
2993 : "");
2994
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()
2999 : "");
3000
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()
3005 : "";
3006
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()
3011 : "";
3012
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()
3017 : "";
3018
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()
3023 : "";
3024
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()
3029 : "";
3030
3031 if (label_str.empty()
3032 && name_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())
3040 return result;
3041
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));
3046 return result;
3047 }
3048
3049 // </variable_suppression stuff>
3050
3051 /// The private member (pimpl) for @ref diff_context.
3052 struct diff_context::priv
3053 {
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_;
3082
3083 priv()
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),
3101 dump_diff_tree_()
3102 {}
3103 };// end struct diff_context::priv
3104
3105 diff_context::diff_context()
3106 : priv_(new diff_context::priv)
3107 {
3108 // Setup all the diff output filters we have.
3109 filtering::filter_base_sptr f;
3110
3111 f.reset(new filtering::harmless_filter);
3112 add_diff_filter(f);
3113
3114 f.reset(new filtering::harmful_filter);
3115 add_diff_filter(f);
3116 }
3117
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
3120 /// them.
3121 ///
3122 /// @param corp1 the first corpus involved in the comparison.
3123 ///
3124 /// @param corp2 the second corpus involved in the comparison.
3125 void
3126 diff_context::set_corpora(const corpus_sptr corp1,
3127 const corpus_sptr corp2)
3128 {
3129 priv_->first_corpus_ = corp1;
3130 priv_->second_corpus_ = corp2;
3131 }
3132
3133 /// Get the first corpus of the comparison, from the current context.
3134 ///
3135 /// @return the first corpus of the comparison.
3136 const corpus_sptr
3137 diff_context::get_first_corpus() const
3138 {return priv_->first_corpus_;}
3139
3140 /// Get the second corpus of the comparison, from the current context.
3141 ///
3142 /// @return the second corpus of the comparison, from the current
3143 /// context.
3144 const corpus_sptr
3145 diff_context::get_second_corpus() const
3146 {return priv_->second_corpus_;}
3147
3148 /// Tests if the current diff context already has a diff for two decls.
3149 ///
3150 /// @param first the first decl to consider.
3151 ///
3152 /// @param second the second decl to consider.
3153 ///
3154 /// @return a pointer to the diff for @p first @p second if found,
3155 /// null otherwise.
3156 diff_sptr
3157 diff_context::has_diff_for(const type_or_decl_base_sptr first,
3158 const type_or_decl_base_sptr second) const
3159 {
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())
3163 return i->second;
3164 return diff_sptr();
3165 }
3166
3167 /// Tests if the current diff context already has a diff for two types.
3168 ///
3169 /// @param first the first type to consider.
3170 ///
3171 /// @param second the second type to consider.
3172 ///
3173 /// @return a pointer to the diff for @p first @p second if found,
3174 /// null otherwise.
3175 diff_sptr
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);}
3179
3180 /// Tests if the current diff context already has a given diff.
3181 ///
3182 ///@param d the diff to consider.
3183 ///
3184 /// @return a pointer to the diff found for @p d
3185 const diff*
3186 diff_context::has_diff_for(const diff* d) const
3187 {return has_diff_for(d->first_subject(), d->second_subject()).get();}
3188
3189 /// Tests if the current diff context already has a given diff.
3190 ///
3191 ///@param d the diff to consider.
3192 ///
3193 /// @return a pointer to the diff found for @p d
3194 diff_sptr
3195 diff_context::has_diff_for(const diff_sptr d) const
3196 {return has_diff_for(d->first_subject(), d->second_subject());}
3197
3198 /// Getter for the bitmap that represents the set of categories that
3199 /// the user wants to see reported.
3200 ///
3201 /// @return a bitmap that represents the set of categories that the
3202 /// user wants to see reported.
3203 diff_category
3204 diff_context::get_allowed_category() const
3205 {return priv_->allowed_category_;}
3206
3207 /// Setter for the bitmap that represents the set of categories that
3208 /// the user wants to see reported.
3209 ///
3210 /// @param c a bitmap that represents the set of categories that the
3211 /// user wants to see represented.
3212 void
3213 diff_context::set_allowed_category(diff_category c)
3214 {priv_->allowed_category_ = c;}
3215
3216 /// Setter for the bitmap that represents the set of categories that
3217 /// the user wants to see reported
3218 ///
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.
3222 ///
3223 /// @param c a bitmap that represents the set of categories that the
3224 /// user wants to see represented.
3225 void
3226 diff_context::switch_categories_on(diff_category c)
3227 {priv_->allowed_category_ = priv_->allowed_category_ | c;}
3228
3229 /// Setter for the bitmap that represents the set of categories that
3230 /// the user wants to see reported
3231 ///
3232 /// This function actually unsets bits from the current categories.
3233 ///
3234 /// @param c a bitmap that represents the set of categories to unset
3235 /// from the current categories.
3236 void
3237 diff_context::switch_categories_off(diff_category c)
3238 {priv_->allowed_category_ = priv_->allowed_category_ & ~c;}
3239
3240 /// Add a diff for two decls to the cache of the current diff_context
3241 ///
3242 /// @param first the first decl to consider.
3243 ///
3244 /// @param second the second decl to consider.
3245 ///
3246 /// @param the diff to add.
3247 void
3248 diff_context::add_diff(type_or_decl_base_sptr first,
3249 type_or_decl_base_sptr second,
3250 const diff_sptr d)
3251 {priv_->types_or_decls_diff_map[std::make_pair(first, second)] = d;}
3252
3253 /// Add a diff tree node to the cache of the current diff_context
3254 ///
3255 /// @param d the diff tree node to add.
3256 void
3257 diff_context::add_diff(const diff* d)
3258 {
3259 if (d)
3260 {
3261 diff_sptr dif(const_cast<diff*>(d), noop_deleter());
3262 add_diff(d->first_subject(), d->second_subject(), dif);
3263 }
3264 }
3265
3266 /// Add a diff tree node to the cache of the current diff_context
3267 ///
3268 /// @param d the diff tree node to add.
3269 void
3270 diff_context::add_diff(const diff_sptr d)
3271 {
3272 if (d)
3273 add_diff(d->first_subject(), d->second_subject(), d);
3274 }
3275
3276 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
3277 /// @ref diff represented by their two subjects.
3278 ///
3279 /// @param first the first subject of the diff.
3280 ///
3281 /// @param second the second subject of the diff.
3282 ///
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
3286 /// returned.
3287 diff_sptr
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);}
3291
3292 /// Getter for the @ref CanonicalDiff "canonical diff node" for the
3293 /// @ref diff represented by the two subjects of a given diff node.
3294 ///
3295 /// @param d the diff node to get the canonical node for.
3296 ///
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.
3300 diff_sptr
3301 diff_context::get_canonical_diff_for(const diff_sptr d) const
3302 {return has_diff_for(d);}
3303
3304 /// Setter for the @ref CanonicalDiff "canonical diff node" for the
3305 /// @ref diff represented by their two subjects.
3306 ///
3307 /// @param first the first subject of the diff.
3308 ///
3309 /// @param second the second subject of the diff.
3310 ///
3311 /// @param d the new canonical diff.
3312 void
3313 diff_context::set_canonical_diff_for(const type_or_decl_base_sptr first,
3314 const type_or_decl_base_sptr second,
3315 const diff_sptr d)
3316 {
3317 assert(d);
3318 if (!has_diff_for(first, second))
3319 {
3320 add_diff(first, second, d);
3321 priv_->canonical_diffs.push_back(d);
3322 }
3323 }
3324
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.
3328 ///
3329 /// @param first the first subject of the diff.
3330 ///
3331 /// @param second the second subject of the diff.
3332 ///
3333 /// @param d the new canonical diff node.
3334 ///
3335 /// @return the canonical diff node.
3336 diff_sptr
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)
3340 {
3341 assert(canonical_diff);
3342
3343 diff_sptr canonical = get_canonical_diff_for(first, second);
3344 if (!canonical)
3345 {
3346 canonical = canonical_diff;
3347 set_canonical_diff_for(first, second, canonical);
3348 }
3349 return canonical;
3350 }
3351
3352 /// Set the canonical diff node property of a given diff node
3353 /// appropriately.
3354 ///
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.
3364 ///
3365 /// @param diff the diff node to initialize the canonical diff node
3366 /// property for.
3367 void
3368 diff_context::initialize_canonical_diff(const diff_sptr diff)
3369 {
3370 if (diff->get_canonical_diff() == 0)
3371 {
3372 diff_sptr canonical =
3373 set_or_get_canonical_diff_for(diff->first_subject(),
3374 diff->second_subject(),
3375 diff);
3376 diff->set_canonical_diff(canonical.get());
3377 }
3378 }
3379
3380 /// Test if a diff node has been traversed.
3381 ///
3382 /// @param d the diff node to consider.
3383 ///
3384 /// @return the first diff node against which @p d is redundant.
3385 diff*
3386 diff_context::diff_has_been_visited(const diff* d) const
3387 {
3388 const diff* canonical = d->get_canonical_diff();
3389 assert(canonical);
3390
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);
3395 else
3396 return 0;
3397 }
3398
3399 /// Test if a diff node has been traversed.
3400 ///
3401 /// @param d the diff node to consider.
3402 ///
3403 /// @return the first diff node against which @p d is redundant.
3404 diff_sptr
3405 diff_context::diff_has_been_visited(const diff_sptr d) const
3406 {
3407 diff_sptr diff(diff_has_been_visited(d.get()));
3408 return diff;
3409 }
3410
3411 /// Mark a diff node as traversed by a traversing algorithm.
3412 ///
3413 /// Actually, it's the @ref CanonicalDiff "canonical diff" of this
3414 /// node that is marked as traversed.
3415 ///
3416 /// Subsequent invocations of diff_has_been_visited() on the diff node
3417 /// will yield true.
3418 void
3419 diff_context::mark_diff_as_visited(const diff* d)
3420 {
3421 if(diff_has_been_visited(d))
3422 return;
3423
3424 const diff* canonical = d->get_canonical_diff();
3425 assert(canonical);
3426
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;
3430 }
3431
3432 /// Unmark all the diff nodes that were marked as being traversed.
3433 void
3434 diff_context::forget_visited_diffs()
3435 {priv_->visited_diff_nodes_.clear();}
3436
3437 /// Mark a given diff node as being the last one that has been visited
3438 /// in its class of equivalence.
3439 ///
3440 /// @param d the diff node to mark.
3441 void
3442 diff_context::mark_last_diff_visited_per_class_of_equivalence(const diff* d)
3443 {
3444 if (!d->get_canonical_diff())
3445 return;
3446
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;
3450 }
3451
3452 /// Clear the marking about the diff diff nodes in a given class of
3453 /// equivalence.
3454 void
3455 diff_context::clear_last_diffs_visited_per_class_of_equivalence()
3456 {priv_->last_visited_diff_node_.clear();}
3457
3458 /// Return the last diff node visited in the class of equivalence of
3459 /// a given diff node.
3460 ///
3461 /// @param d the diff node which class of equivalence to consider.
3462 ///
3463 /// @return the last diff node visited in the class of equivalence of
3464 /// the diff node @p d.
3465 const diff*
3466 diff_context::get_last_visited_diff_of_class_of_equivalence(const diff* d)
3467 {
3468 size_t v0 = reinterpret_cast<size_t>(d);
3469
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);
3473 return 0;
3474 }
3475
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.
3478 ///
3479 /// @param f if true then during the traversing of a diff nodes tree
3480 /// each node is visited at most once.
3481 void
3482 diff_context::forbid_visiting_a_node_twice(bool f)
3483 {priv_->forbid_visiting_a_node_twice_ = f;}
3484
3485 /// Return a flag that, if true, then during the traversing of a diff
3486 /// nodes tree each node is visited at most once.
3487 ///
3488 /// @return the boolean flag.
3489 bool
3490 diff_context::visiting_a_node_twice_is_forbidden() const
3491 {return priv_->forbid_visiting_a_node_twice_;}
3492
3493 /// Getter for the diff tree nodes filters to apply to diff sub-trees.
3494 ///
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_;}
3499
3500 /// Setter for the diff filters to apply to a given diff sub-tree.
3501 ///
3502 /// @param f the new diff filter to add to the vector of diff filters
3503 /// to apply to diff sub-trees.
3504 void
3505 diff_context::add_diff_filter(filtering::filter_base_sptr f)
3506 {priv_->filters_.push_back(f);}
3507
3508 /// Apply the diff filters to a given diff sub-tree.
3509 ///
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.
3513 ///
3514 /// @param diff the diff sub-tree to apply the filters to.
3515 void
3516 diff_context::maybe_apply_filters(diff_sptr diff)
3517 {
3518 if (!diff)
3519 return;
3520
3521 if (get_allowed_category() == EVERYTHING_CATEGORY)
3522 return;
3523
3524 if (!diff->has_changes())
3525 return;
3526
3527 for (filtering::filters::const_iterator i = diff_filters().begin();
3528 i != diff_filters().end();
3529 ++i)
3530 {
3531 filtering::apply_filter(*i, diff);
3532 propagate_categories(diff);
3533 }
3534
3535 }
3536
3537 /// Apply the diff filters to the diff nodes of a @ref corpus_diff
3538 /// instance.
3539 ///
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.
3543 ///
3544 /// @param diff the corpus diff to apply the filters to.
3545 void
3546 diff_context::maybe_apply_filters(corpus_diff_sptr diff)
3547 {
3548
3549 if (!diff || !diff->has_changes())
3550 return;
3551
3552 for (filtering::filters::const_iterator i = diff_filters().begin();
3553 i != diff_filters().end();
3554 ++i)
3555 {
3556 filtering::apply_filter(**i, diff);
3557 propagate_categories(diff);
3558 }
3559 }
3560
3561 /// Getter for the vector of suppressions that specify which diff node
3562 /// reports should be dropped on the floor.
3563 ///
3564 /// @return the set of suppressions.
3565 suppressions_type&
3566 diff_context::suppressions() const
3567 {return priv_->suppressions_;}
3568
3569 /// Add a new suppression specification that specifies which diff node
3570 /// reports should be dropped on the floor.
3571 ///
3572 /// @param suppr the new suppression specification to add to the
3573 /// existing set of suppressions specifications of the diff context.
3574 void
3575 diff_context::add_suppression(const suppression_sptr suppr)
3576 {priv_->suppressions_.push_back(suppr);}
3577
3578 /// Add new suppression specifications that specify which diff node
3579 /// reports should be dropped on the floor.
3580 ///
3581 /// @param supprs the new suppression specifications to add to the
3582 /// existing set of suppression specifications of the diff context.
3583 void
3584 diff_context::add_suppressions(const suppressions_type& supprs)
3585 {
3586 priv_->suppressions_.insert(priv_->suppressions_.end(),
3587 supprs.begin(), supprs.end());
3588 }
3589
3590 /// Set a flag saying if the comparison module should only show the
3591 /// diff stats.
3592 ///
3593 /// @param f the flag to set.
3594 void
3595 diff_context::show_stats_only(bool f)
3596 {priv_->show_stats_only_ = f;}
3597
3598 /// Test if the comparison module should only show the diff stats.
3599 ///
3600 /// @return true if the comparison module should only show the diff
3601 /// stats, false otherwise.
3602 bool
3603 diff_context::show_stats_only() const
3604 {return priv_->show_stats_only_;}
3605
3606 /// Setter for the property that says if the comparison module should
3607 /// show the soname changes in its report.
3608 ///
3609 /// @param f the new value of the property.
3610 void
3611 diff_context::show_soname_change(bool f)
3612 {priv_->show_soname_change_ = f;}
3613
3614 /// Getter for the property that says if the comparison module should
3615 /// show the soname changes in its report.
3616 ///
3617 /// @return the value of the property.
3618 bool
3619 diff_context::show_soname_change() const
3620 {return priv_->show_soname_change_;}
3621
3622 /// Setter for the property that says if the comparison module should
3623 /// show the architecture changes in its report.
3624 ///
3625 /// @param f the new value of the property.
3626 void
3627 diff_context::show_architecture_change(bool f)
3628 {priv_->show_architecture_change_ = f;}
3629
3630 /// Getter for the property that says if the comparison module should
3631 /// show the architecture changes in its report.
3632 ///
3633 /// @return the value of the property.
3634 bool
3635 diff_context::show_architecture_change() const
3636 {return priv_->show_architecture_change_;}
3637
3638 /// Set a flag saying to show the deleted functions.
3639 ///
3640 /// @param f true to show deleted functions.
3641 void
3642 diff_context::show_deleted_fns(bool f)
3643 {priv_->show_deleted_fns_ = f;}
3644
3645 /// @return true if we want to show the deleted functions, false
3646 /// otherwise.
3647 bool
3648 diff_context::show_deleted_fns() const
3649 {return priv_->show_deleted_fns_;}
3650
3651 /// Set a flag saying to show the changed functions.
3652 ///
3653 /// @param f true to show the changed functions.
3654 void
3655 diff_context::show_changed_fns(bool f)
3656 {priv_->show_changed_fns_ = f;}
3657
3658 /// @return true if we want to show the changed functions, false otherwise.
3659 bool
3660 diff_context::show_changed_fns() const
3661 {return priv_->show_changed_fns_;}
3662
3663 /// Set a flag saying to show the added functions.
3664 ///
3665 /// @param f true to show the added functions.
3666 void
3667 diff_context::show_added_fns(bool f)
3668 {priv_->show_added_fns_ = f;}
3669
3670 /// @return true if we want to show the added functions, false
3671 /// otherwise.
3672 bool
3673 diff_context::show_added_fns() const
3674 {return priv_->show_added_fns_;}
3675
3676 /// Set a flag saying to show the deleted variables.
3677 ///
3678 /// @param f true to show the deleted variables.
3679 void
3680 diff_context::show_deleted_vars(bool f)
3681 {priv_->show_deleted_vars_ = f;}
3682
3683 /// @return true if we want to show the deleted variables, false
3684 /// otherwise.
3685 bool
3686 diff_context::show_deleted_vars() const
3687 {return priv_->show_deleted_vars_;}
3688
3689 /// Set a flag saying to show the changed variables.
3690 ///
3691 /// @param f true to show the changed variables.
3692 void
3693 diff_context::show_changed_vars(bool f)
3694 {priv_->show_changed_vars_ = f;}
3695
3696 /// @return true if we want to show the changed variables, false otherwise.
3697 bool
3698 diff_context::show_changed_vars() const
3699 {return priv_->show_changed_vars_;}
3700
3701 /// Set a flag saying to show the added variables.
3702 ///
3703 /// @param f true to show the added variables.
3704 void
3705 diff_context::show_added_vars(bool f)
3706 {priv_->show_added_vars_ = f;}
3707
3708 /// @return true if we want to show the added variables, false
3709 /// otherwise.
3710 bool
3711 diff_context::show_added_vars() const
3712 {return priv_->show_added_vars_;}
3713
3714 bool
3715 diff_context::show_linkage_names() const
3716 {return priv_->show_linkage_names_;}
3717
3718 void
3719 diff_context::show_linkage_names(bool f)
3720 {priv_->show_linkage_names_= f;}
3721
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.
3725 ///
3726 /// @return the flag.
3727 bool
3728 diff_context::show_redundant_changes() const
3729 {return priv_->show_redundant_changes_;}
3730
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.
3734 ///
3735 /// @param f the flag to set.
3736 void
3737 diff_context::show_redundant_changes(bool f)
3738 {priv_->show_redundant_changes_ = f;}
3739
3740 /// Getter for the flag that indicates if symbols not referenced by
3741 /// any debug info are to be compared and reported about.
3742 ///
3743 /// @return the boolean flag.
3744 bool
3745 diff_context::show_symbols_unreferenced_by_debug_info() const
3746 {return priv_->show_syms_unreferenced_by_di_;}
3747
3748 /// Setter for the flag that indicates if symbols not referenced by
3749 /// any debug info are to be compared and reported about.
3750 ///
3751 /// @param f the new flag to set.
3752 void
3753 diff_context::show_symbols_unreferenced_by_debug_info(bool f)
3754 {priv_->show_syms_unreferenced_by_di_ = f;}
3755
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.
3758 ///
3759 /// @return true iff symbols not referenced by any debug info and that
3760 /// got added are to be reported about.
3761 bool
3762 diff_context::show_added_symbols_unreferenced_by_debug_info() const
3763 {return priv_->show_added_syms_unreferenced_by_di_;}
3764
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.
3767 ///
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.
3770 void
3771 diff_context::show_added_symbols_unreferenced_by_debug_info(bool f)
3772 {priv_->show_added_syms_unreferenced_by_di_ = f;}
3773
3774 /// Setter for the default output stream used by code of the
3775 /// comparison engine. By default the default output stream is a NULL
3776 /// pointer.
3777 ///
3778 /// @param o a pointer to the default output stream.
3779 void
3780 diff_context::default_output_stream(ostream* o)
3781 {priv_->default_output_stream_ = o;}
3782
3783 /// Getter for the default output stream used by code of the
3784 /// comparison engine. By default the default output stream is a NULL
3785 /// pointer.
3786 ///
3787 /// @return a pointer to the default output stream.
3788 ostream*
3789 diff_context::default_output_stream()
3790 {return priv_->default_output_stream_;}
3791
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.
3794 ///
3795 /// @param o a pointer to the error output stream.
3796 void
3797 diff_context::error_output_stream(ostream* o)
3798 {priv_->error_output_stream_ = o;}
3799
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.
3802 ///
3803 /// @return a pointer to the error output stream.
3804 ostream*
3805 diff_context::error_output_stream() const
3806 {return priv_->error_output_stream_;}
3807
3808 /// Test if the comparison engine should dump the diff tree for the
3809 /// changed functions and variables it has.
3810 ///
3811 /// @return true if after the comparison, the engine should dump the
3812 /// diff tree for the changed functions and variables it has.
3813 bool
3814 diff_context::dump_diff_tree() const
3815 {return priv_->dump_diff_tree_;}
3816
3817 /// Set if the comparison engine should dump the diff tree for the
3818 /// changed functions and variables it has.
3819 ///
3820 /// @param f true if after the comparison, the engine should dump the
3821 /// diff tree for the changed functions and variables it has.
3822 void
3823 diff_context::dump_diff_tree(bool f)
3824 {priv_->dump_diff_tree_ = f;}
3825
3826 /// Emit a textual representation of a diff tree to the error output
3827 /// stream of the current context, for debugging purposes.
3828 ///
3829 /// @param d the diff tree to serialize to the error output associated
3830 /// to the current instance of @ref diff_context.
3831 void
3832 diff_context::do_dump_diff_tree(const diff_sptr d) const
3833 {
3834 if (error_output_stream())
3835 print_diff_tree(d, *error_output_stream());
3836 }
3837
3838 /// Emit a textual representation of a @ref corpus_diff tree to the error
3839 /// output stream of the current context, for debugging purposes.
3840 ///
3841 /// @param d the @ref corpus_diff tree to serialize to the error
3842 /// output associated to the current instance of @ref diff_context.
3843 void
3844 diff_context::do_dump_diff_tree(const corpus_diff_sptr d) const
3845 {
3846 if (error_output_stream())
3847 print_diff_tree(d, *error_output_stream());
3848 }
3849 // </diff_context stuff>
3850
3851 // <diff stuff>
3852
3853 /// Private data for the @ref diff type.
3854 struct diff::priv
3855 {
3856 bool finished_;
3857 bool traversing_;
3858 type_or_decl_base_sptr first_subject_;
3859 type_or_decl_base_sptr second_subject_;
3860 vector<diff_sptr> children_;
3861 diff* parent_;
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_;
3869
3870 priv();
3871
3872 public:
3873
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,
3878 bool reported_once,
3879 bool currently_reporting)
3880 : finished_(),
3881 traversing_(),
3882 first_subject_(first_subject),
3883 second_subject_(second_subject),
3884 parent_(),
3885 canonical_diff_(),
3886 ctxt_(ctxt),
3887 local_category_(category),
3888 category_(category),
3889 reported_once_(reported_once),
3890 currently_reporting_(currently_reporting)
3891 {}
3892
3893 /// Check if a given categorization of a diff node should make it be
3894 /// filtered out.
3895 ///
3896 /// @param category the categorization to take into account.
3897 bool
3898 is_filtered_out(diff_category category)
3899 {
3900 if (ctxt_->get_allowed_category() == EVERYTHING_CATEGORY)
3901 return false;
3902
3903 /// We don't want to display nodes suppressed by a user-provided
3904 /// suppression specification.
3905 if (category & SUPPRESSED_CATEGORY)
3906 return true;
3907
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))
3912 return true;
3913
3914 if (category == NO_CHANGE_CATEGORY)
3915 return false;
3916
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));
3922 }
3923 };// end class diff::priv
3924
3925 /// A functor to compare two instances of @ref diff_sptr.
3926 struct diff_less_than_functor
3927 {
3928 /// An operator that takes two instances of @ref diff_sptr returns
3929 /// true if its first operand compares less than its second operand.
3930 ///
3931 /// @param l the first operand to consider.
3932 ///
3933 /// @param r the second operand to consider.
3934 ///
3935 /// @return true if @p l compares less than @p r.
3936 bool
3937 operator()(const diff_sptr l, const diff_sptr r) const
3938 {
3939 if (!l || !r || !l->first_subject() || !r->first_subject())
3940 return false;
3941
3942 string l_qn = get_name(l->first_subject());
3943 string r_qn = get_name(r->first_subject());
3944
3945 return l_qn < r_qn;
3946 }
3947 };
3948
3949 /// Constructor for the @ref diff type.
3950 ///
3951 /// This constructs a diff between two subjects that are actually
3952 /// declarations; the first and the second one.
3953 ///
3954 /// @param first_subject the first decl (subject) of the diff.
3955 ///
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(),
3961 NO_CHANGE_CATEGORY,
3962 /*reported_once=*/false,
3963 /*currently_reporting=*/false))
3964 {}
3965
3966 /// Constructor for the @ref diff type.
3967 ///
3968 /// This constructs a diff between two subjects that are actually
3969 /// declarations; the first and the second one.
3970 ///
3971 /// @param first_subject the first decl (subject) of the diff.
3972 ///
3973 /// @param second_subject the second decl (subject) of the diff.
3974 ///
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))
3983 {}
3984
3985 /// Flag a given diff node as being traversed.
3986 ///
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.
3993 ///
3994 /// Note that traversing a node means visiting it *and* visiting its
3995 /// children nodes.
3996 ///
3997 /// The canonical node is marked as being traversed too.
3998 ///
3999 /// These functions are called by the traversing code.
4000 void
4001 diff::begin_traversing()
4002 {
4003 assert(!is_traversing());
4004 if (priv_->canonical_diff_)
4005 priv_->canonical_diff_->priv_->traversing_ = true;
4006 priv_->traversing_ = true;
4007 }
4008
4009 /// Tell if a given node is being traversed or not.
4010 ///
4011 /// Note that traversing a node means visiting it *and* visiting its
4012 /// children nodes.
4013 ///
4014 /// It's the canonical node which is looked at, actually.
4015 ///
4016 /// Please read the comments for the diff::begin_traversing() for mode
4017 /// context.
4018 ///
4019 /// @return true if the current instance of @diff is being traversed.
4020 bool
4021 diff::is_traversing() const
4022 {
4023 if (priv_->canonical_diff_)
4024 return priv_->canonical_diff_->priv_->traversing_;
4025 return priv_->traversing_;
4026 }
4027
4028 /// Flag a given diff node as not being traversed anymore.
4029 ///
4030 /// Note that traversing a node means visiting it *and* visiting its
4031 /// children nodes.
4032 ///
4033 /// Please read the comments of the function diff::begin_traversing()
4034 /// for mode context.
4035 void
4036 diff::end_traversing()
4037 {
4038 assert(is_traversing());
4039 if (priv_->canonical_diff_)
4040 priv_->canonical_diff_->priv_->traversing_ = false;
4041 priv_->traversing_ = false;
4042 }
4043
4044 /// Finish the building of a given kind of a diff tree node.
4045 ///
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.
4051 void
4052 diff::finish_diff_type()
4053 {
4054 }
4055
4056 /// Getter of the first subject of the diff.
4057 ///
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_);}
4062
4063 /// Getter of the second subject of the diff.
4064 ///
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_);}
4069
4070 /// Getter for the children nodes of the current @ref diff node.
4071 ///
4072 /// @return a vector of the children nodes.
4073 const vector<diff_sptr>&
4074 diff::children_nodes() const
4075 {return priv_->children_;}
4076
4077 /// Getter for the parent node of the current @ref diff node.
4078 ///
4079 /// @return the parent node of the current @ref diff node.
4080 const diff*
4081 diff::parent_node() const
4082 {return priv_->parent_;}
4083
4084 /// Getter for the canonical diff of the current instance of @ref
4085 /// diff.
4086 ///
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
4090 /// diff node.
4091 ///
4092 /// @return the canonical diff node or null if none was set.
4093 diff*
4094 diff::get_canonical_diff() const
4095 {return priv_->canonical_diff_;}
4096
4097 /// Setter for the canonical diff of the current instance of @ref
4098 /// diff.
4099 ///
4100 /// @param d the new canonical node to set.
4101 void
4102 diff::set_canonical_diff(diff * d)
4103 {priv_->canonical_diff_ = d;}
4104
4105 /// Add a new child node to the vector of children nodes for the
4106 /// current @ref diff node.
4107 ///
4108 /// @param d the new child node to add to the children nodes.
4109 void
4110 diff::append_child_node(diff_sptr d)
4111 {
4112 assert(d);
4113 priv_->children_.push_back(d);
4114
4115 diff_less_than_functor comp;
4116 std::sort(priv_->children_.begin(),
4117 priv_->children_.end(),
4118 comp);
4119
4120 d->priv_->parent_ = this;
4121 }
4122
4123 /// Getter of the context of the current diff.
4124 ///
4125 /// @return the context of the current diff.
4126 const diff_context_sptr
4127 diff::context() const
4128 {return priv_->ctxt_;}
4129
4130 /// Setter of the context of the current diff.
4131 ///
4132 /// @param c the new context to set.
4133 void
4134 diff::context(diff_context_sptr c)
4135 {priv_->ctxt_ = c;}
4136
4137 /// Tests if we are currently in the middle of emitting a report for
4138 /// this diff.
4139 ///
4140 /// @return true if we are currently emitting a report for the
4141 /// current diff, false otherwise.
4142 bool
4143 diff::currently_reporting() const
4144 {
4145 if (priv_->canonical_diff_)
4146 return priv_->canonical_diff_->priv_->currently_reporting_;
4147 return priv_->currently_reporting_;
4148 }
4149
4150 /// Sets a flag saying if we are currently in the middle of emitting
4151 /// a report for this diff.
4152 ///
4153 /// @param f true if we are currently emitting a report for the
4154 /// current diff, false otherwise.
4155 void
4156 diff::currently_reporting(bool f) const
4157 {
4158 if (priv_->canonical_diff_)
4159 priv_->canonical_diff_->priv_->currently_reporting_ = f;
4160 priv_->currently_reporting_ = f;
4161 }
4162
4163 /// Tests if a report has already been emitted for the current diff.
4164 ///
4165 /// @return true if a report has already been emitted for the
4166 /// current diff, false otherwise.
4167 bool
4168 diff::reported_once() const
4169 {
4170 assert(priv_->canonical_diff_);
4171 return priv_->canonical_diff_->priv_->reported_once_;
4172 }
4173
4174 /// The generic traversing code that walks a given diff sub-tree.
4175 ///
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.
4181 ///
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.
4189 ///
4190 /// When a diff node is encountered, the
4191 /// diff_node_visitor::visit_begin() method is invoked on the diff
4192 /// node first.
4193 ///
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
4197 /// case.
4198 ///
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.
4205
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.
4210 ///
4211 /// @param v the entity that visits each node of the diff sub-tree.
4212 ///
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.
4216 bool
4217 diff::traverse(diff_node_visitor& v)
4218 {
4219 finish_diff_type();
4220
4221 v.visit_begin(this);
4222
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;
4227
4228 bool mark_visited_nodes_as_traversed =
4229 !(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_VISITED);
4230
4231 if (!already_visited && !v.visit(this, /*pre=*/true))
4232 {
4233 v.visit_end(this);
4234 if (mark_visited_nodes_as_traversed)
4235 context()->mark_diff_as_visited(this);
4236 return false;
4237 }
4238
4239 if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND)
4240 && !is_traversing()
4241 && !already_visited)
4242 {
4243 begin_traversing();
4244 for (vector<diff_sptr>::const_iterator i = children_nodes().begin();
4245 i != children_nodes().end();
4246 ++i)
4247 {
4248 if (!(*i)->traverse(v))
4249 {
4250 v.visit_end(this);
4251 if (mark_visited_nodes_as_traversed)
4252 context()->mark_diff_as_visited(this);
4253 end_traversing();
4254 return false;
4255 }
4256 }
4257 end_traversing();
4258 }
4259
4260 if (!v.visit(this, /*pref=*/false))
4261 {
4262 v.visit_end(this);
4263 if (mark_visited_nodes_as_traversed)
4264 context()->mark_diff_as_visited(this);
4265 return false;
4266 }
4267
4268 v.visit_end(this);
4269 if (!already_visited && mark_visited_nodes_as_traversed)
4270 context()->mark_diff_as_visited(this);
4271
4272 return true;
4273 }
4274
4275 /// Sets a flag saying if a report has already been emitted for the
4276 /// current diff.
4277 ///
4278 /// @param f true if a report has already been emitted for the
4279 /// current diff, false otherwise.
4280 void
4281 diff::reported_once(bool f) const
4282 {
4283 assert(priv_->canonical_diff_);
4284 priv_->canonical_diff_->priv_->reported_once_ = f;
4285 priv_->reported_once_ = f;
4286 }
4287
4288 /// Getter for the local category of the current diff tree node.
4289 ///
4290 /// The local category represents the set of categories of a diff
4291 /// node, not taking in account the categories inherited from its
4292 /// children nodes.
4293 ///
4294 /// @return the local category of the current diff tree node.
4295 diff_category
4296 diff::get_local_category() const
4297 {return priv_->local_category_;}
4298
4299 /// Getter for the category of the current diff tree node.
4300 ///
4301 /// This category represents the union of the local category and the
4302 /// categories inherited from the children diff nodes.
4303 ///
4304 /// @return the category of the current diff tree node.
4305 diff_category
4306 diff::get_category() const
4307 {return priv_->category_;}
4308
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.
4312 ///
4313 /// @param c a bit-map representing the set of categories to add the
4314 /// current diff tree node to.
4315 ///
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.
4319 diff_category
4320 diff::add_to_category(diff_category c)
4321 {
4322 priv_->category_ = priv_->category_ | c;
4323 return priv_->category_;
4324 }
4325
4326 /// Adds the current diff tree node to the categories resulting from
4327 /// the local changes of the current diff node.
4328 ///
4329 /// @param c a bit-map representing the set of categories to add the
4330 /// current diff tree node to.
4331 ///
4332 /// @return the resulting bit-map representing the categories this
4333 /// current diff tree node belongs to.
4334 diff_category
4335 diff::add_to_local_category(diff_category c)
4336 {
4337 priv_->local_category_ = priv_->local_category_ | c;
4338 return priv_->local_category_;
4339 }
4340
4341 /// Adds the current diff tree node to the categories resulting from
4342 /// the local and inherited changes of the current diff node.
4343 ///
4344 /// @param c a bit-map representing the set of categories to add the
4345 /// current diff tree node to.
4346 void
4347 diff::add_to_local_and_inherited_categories(diff_category c)
4348 {
4349 add_to_local_category(c);
4350 add_to_category(c);
4351 }
4352
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.
4356 ///
4357 /// @param c a bit-map representing the set of categories to add the
4358 /// current diff tree node to.
4359 ///
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.
4363 diff_category
4364 diff::remove_from_category(diff_category c)
4365 {
4366 priv_->category_ = priv_->category_ & ~c;
4367 return priv_->category_;
4368 }
4369
4370 /// Remove the current diff tree node from the categories resulting
4371 /// from the local changes.
4372 ///
4373 /// @param c a bit-map representing the set of categories to add the
4374 /// current diff tree node to.
4375 ///
4376 /// @return the resulting bit-map representing the categories this
4377 /// current diff tree onde belongs to.
4378 diff_category
4379 diff::remove_from_local_category(diff_category c)
4380 {
4381 priv_->local_category_ = priv_->local_category_ & ~c;
4382 return priv_->local_category_;
4383 }
4384
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.
4388 ///
4389 /// @param c the new category for the current diff node.
4390 void
4391 diff::set_category(diff_category c)
4392 {priv_->category_ = c;}
4393
4394 /// Set the local category of the current @ref diff node.
4395 ///
4396 /// @param c the new category for the current diff node.
4397 void
4398 diff::set_local_category(diff_category c)
4399 {priv_->local_category_ = c;}
4400
4401 /// Test if this diff tree node is to be filtered out for reporting
4402 /// purposes.
4403 ///
4404 /// The function tests if the categories of the diff tree node are
4405 /// "forbidden" by the context or not.
4406 ///
4407 /// @return true iff the current diff node should NOT be reported.
4408 bool
4409 diff::is_filtered_out() const
4410 {return priv_->is_filtered_out(get_category());}
4411
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.
4415 ///
4416 /// The function tests if the local categories of the diff tree node
4417 /// are "forbidden" by the context or not.
4418 ///
4419 /// @return true iff the current diff node should NOT be reported,
4420 /// with respect to its local categories.
4421 bool
4422 diff::is_filtered_out_wrt_non_inherited_categories() const
4423 {return priv_->is_filtered_out(get_local_category());}
4424
4425 /// Test if the current diff node has been suppressed by a
4426 /// user-provided suppression specification.
4427 ///
4428 /// @return true if the current diff node has been suppressed by a
4429 /// user-provided suppression list.
4430 bool
4431 diff::is_suppressed() const
4432 {
4433 const suppressions_type& suppressions = context()->suppressions();
4434 for (suppressions_type::const_iterator i = suppressions.begin();
4435 i != suppressions.end();
4436 ++i)
4437 if ((*i)->suppresses_diff(this))
4438 return true;
4439 return false;
4440 }
4441
4442 /// Test if this diff tree node should be reported.
4443 ///
4444 /// @return true iff the current node should be reported.
4445 bool
4446 diff::to_be_reported() const
4447 {
4448 if (has_changes() && !is_filtered_out())
4449 return true;
4450 return false;
4451 }
4452
4453 /// Test if this diff tree node should be reported when considering
4454 /// the categories that were *NOT* inherited from its children nodes.
4455 ///
4456 /// @return true iff the current node should be reported.
4457 bool
4458 diff::has_local_changes_to_be_reported() const
4459 {
4460 if (has_local_changes()
4461 && !is_filtered_out_wrt_non_inherited_categories())
4462 return true;
4463 return false;
4464 }
4465
4466 /// Get a pretty representation of the current @ref diff node.
4467 ///
4468 /// This is suitable for e.g. emitting debugging traces for the diff
4469 /// tree nodes.
4470 ///
4471 /// @return the pretty representation of the diff node.
4472 const string&
4473 diff::get_pretty_representation() const
4474 {
4475 if (priv_->pretty_representation_.empty())
4476 priv_->pretty_representation_ = "empty_diff";
4477 return priv_->pretty_representation_;
4478 }
4479
4480 /// Default implementation of the hierachy chaining virtual function.
4481 ///
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.
4486 ///
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.
4492 ///
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.
4496 void
4497 diff::chain_into_hierarchy()
4498 {}
4499
4500 // </diff stuff>
4501
4502 static bool
4503 report_size_and_alignment_changes(type_or_decl_base_sptr first,
4504 type_or_decl_base_sptr second,
4505 diff_context_sptr ctxt,
4506 ostream& out,
4507 const string& indent,
4508 bool nl);
4509
4510 // <type_diff_base stuff>
4511 class type_diff_base::priv
4512 {
4513 public:
4514 friend class type_diff_base;
4515 }; // end class type_diff_base
4516
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),
4521 priv_(new priv)
4522 {}
4523
4524 type_diff_base::~type_diff_base()
4525 {}
4526 // </type_diff_base stuff>
4527
4528 // <decl_diff_base stuff>
4529 class decl_diff_base::priv
4530 {
4531 public:
4532 friend class decl_diff_base;
4533 };//end class priv
4534
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),
4539 priv_(new priv)
4540 {}
4541
4542 decl_diff_base::~decl_diff_base()
4543 {}
4544
4545 // </decl_diff_base stuff>
4546 // <distinct_diff stuff>
4547
4548 /// The private data structure for @ref distinct_diff.
4549 struct distinct_diff::priv
4550 {
4551 diff_sptr compatible_child_diff;
4552 };// end struct distinct_diff
4553
4554 /// @return a pretty representation for the @ref distinct_diff node.
4555 const string&
4556 distinct_diff::get_pretty_representation() const
4557 {
4558 if (diff::priv_->pretty_representation_.empty())
4559 {
4560 std::ostringstream o;
4561 o << "distinct_diff[";
4562 if (first_subject())
4563 o << first_subject()->get_pretty_representation();
4564 else
4565 o << "null";
4566 o << ", ";
4567 if (second_subject())
4568 o << second_subject()->get_pretty_representation() ;
4569 else
4570 o << "null";
4571 o << "]" ;
4572 diff::priv_->pretty_representation_ = o.str();
4573 }
4574 return diff::priv_->pretty_representation_;
4575 }
4576
4577 /// Populate the vector of children node of the @ref diff base type
4578 /// sub-object of this instance of @distinct_diff.
4579 ///
4580 /// The children nodes can then later be retrieved using
4581 /// diff::children_nodes().
4582 void
4583 distinct_diff::chain_into_hierarchy()
4584 {
4585 assert(entities_are_of_distinct_kinds(first(), second()));
4586
4587 if (diff_sptr d = compatible_child_diff())
4588 append_child_node(d);
4589 }
4590
4591 /// Constructor for @ref distinct_diff.
4592 ///
4593 /// Note that the two entities considered for the diff (and passed in
4594 /// parameter) must be of different kinds.
4595 ///
4596 /// @param first the first entity to consider for the diff.
4597 ///
4598 /// @param second the second entity to consider for the diff.
4599 ///
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),
4605 priv_(new priv)
4606 {assert(entities_are_of_distinct_kinds(first, second));}
4607
4608 /// Finish building the current instance of @ref distinct_diff.
4609 void
4610 distinct_diff::finish_diff_type()
4611 {
4612 if (diff::priv_->finished_)
4613 return;
4614
4615 chain_into_hierarchy();
4616 diff::priv_->finished_ = true;
4617 }
4618
4619 /// Getter for the first subject of the diff.
4620 ///
4621 /// @return the first subject of the diff.
4622 const type_or_decl_base_sptr
4623 distinct_diff::first() const
4624 {return first_subject();}
4625
4626 /// Getter for the second subject of the diff.
4627 ///
4628 /// @return the second subject of the diff.
4629 const type_or_decl_base_sptr
4630 distinct_diff::second() const
4631 {return second_subject();}
4632
4633 /// Getter for the child diff of this distinct_diff instance.
4634 ///
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.
4640 ///
4641 /// Note that two diff subjects (that compare different) are
4642 /// considered compatible if stripping typedefs out of them makes them
4643 /// comparing equal.
4644 ///
4645 /// @return the compatible child diff node, if any. Otherwise, null.
4646 const diff_sptr
4647 distinct_diff::compatible_child_diff() const
4648 {
4649 if (!priv_->compatible_child_diff)
4650 {
4651 type_base_sptr fs = strip_typedef(is_type(first())),
4652 ss = strip_typedef(is_type(second()));
4653
4654 if (fs && ss
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),
4659 context());
4660 }
4661 return priv_->compatible_child_diff;
4662 }
4663
4664 /// Test if the two arguments are of different kind, or that are both
4665 /// NULL.
4666 ///
4667 /// @param first the first argument to test for similarity in kind.
4668 ///
4669 /// @param second the second argument to test for similarity in kind.
4670 ///
4671 /// @return true iff the two arguments are of different kind.
4672 bool
4673 distinct_diff::entities_are_of_distinct_kinds(type_or_decl_base_sptr first,
4674 type_or_decl_base_sptr second)
4675 {
4676 if (!!first != !!second)
4677 return true;
4678 if (!first && !second)
4679 // We do consider diffs of two empty decls as a diff of distinct
4680 // kinds, for now.
4681 return true;
4682 if (first == second)
4683 return false;
4684
4685 return typeid(*first.get()) != typeid(*second.get());
4686 }
4687
4688 /// @return true if the two subjects of the diff are different, false
4689 /// otherwise.
4690 bool
4691 distinct_diff::has_changes() const
4692 {return first() != second();}
4693
4694 /// @return true iff the current diff node carries local changes.
4695 bool
4696 distinct_diff::has_local_changes() const
4697 {
4698 // The changes on a distinct_diff are all local.
4699 if (has_changes())
4700 return true;
4701 return false;
4702 }
4703
4704 /// Emit a report about the current diff instance.
4705 ///
4706 /// @param out the output stream to send the diff report to.
4707 ///
4708 /// @param indent the indentation string to use in the report.
4709 void
4710 distinct_diff::report(ostream& out, const string& indent) const
4711 {
4712 if (!to_be_reported())
4713 return;
4714
4715 type_or_decl_base_sptr f = first(), s = second();
4716
4717 string f_repr = f ? f->get_pretty_representation() : "'void'";
4718 string s_repr = s ? s->get_pretty_representation() : "'void'";
4719
4720 diff_sptr diff = compatible_child_diff();
4721
4722 if (diff)
4723 {
4724 out << indent
4725 << "entity changed from '" << f_repr
4726 << "' to compatible type '" << s_repr << "'\n";
4727 }
4728 else
4729 {
4730 out << indent
4731 << "entity changed from '" << f_repr
4732 << "' to '" << s_repr << "'\n";
4733 }
4734
4735 type_base_sptr fs = strip_typedef(is_type(f)),
4736 ss = strip_typedef(is_type(s));
4737
4738 if (diff_sptr diff = compatible_child_diff())
4739 diff->report(out, indent + " ");
4740 else
4741 if (report_size_and_alignment_changes(f, s, context(), out, indent,
4742 /*start_with_new_line=*/false))
4743 out << "\n";
4744 }
4745
4746 /// Try to diff entities that are of distinct kinds.
4747 ///
4748 /// @param first the first entity to consider for the diff.
4749 ///
4750 /// @param second the second entity to consider for the diff.
4751 ///
4752 /// @param ctxt the context of the diff.
4753 ///
4754 /// @return a non-null diff if a diff object could be built, null
4755 /// otherwise.
4756 distinct_diff_sptr
4757 compute_diff_for_distinct_kinds(const decl_base_sptr first,
4758 const decl_base_sptr second,
4759 diff_context_sptr ctxt)
4760 {
4761 if (!distinct_diff::entities_are_of_distinct_kinds(first, second))
4762 return distinct_diff_sptr();
4763
4764 distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
4765
4766 ctxt->initialize_canonical_diff(result);
4767
4768 return result;
4769 }
4770
4771 /// </distinct_diff stuff>
4772
4773 /// Try to compute a diff on two instances of DiffType representation.
4774 ///
4775 /// The function template performs the diff if and only if the decl
4776 /// representations are of a DiffType.
4777 ///
4778 /// @tparm DiffType the type of instances to diff.
4779 ///
4780 /// @param first the first representation of decl to consider in the
4781 /// diff computation.
4782 ///
4783 /// @param second the second representation of decl to consider in the
4784 /// diff computation.
4785 ///
4786 /// @param ctxt the diff context to use.
4787 ///
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>
4792 diff_sptr
4793 try_to_diff(const decl_base_sptr first,
4794 const decl_base_sptr second,
4795 diff_context_sptr ctxt)
4796 {
4797 if (shared_ptr<DiffType> f =
4798 dynamic_pointer_cast<DiffType>(first))
4799 {
4800 shared_ptr<DiffType> s =
4801 dynamic_pointer_cast<DiffType>(second);
4802 if (!s)
4803 return diff_sptr();
4804 return compute_diff(f, s, ctxt);
4805 }
4806 return diff_sptr();
4807 }
4808
4809
4810 /// This is a specialization of @ref try_to_diff() template to diff
4811 /// instances of @ref class_decl.
4812 ///
4813 /// @param first the first representation of decl to consider in the
4814 /// diff computation.
4815 ///
4816 /// @param second the second representation of decl to consider in the
4817 /// diff computation.
4818 ///
4819 /// @param ctxt the diff context to use.
4820 template<>
4821 diff_sptr
4822 try_to_diff<class_decl>(const decl_base_sptr first,
4823 const decl_base_sptr second,
4824 diff_context_sptr ctxt)
4825 {
4826 if (class_decl_sptr f =
4827 dynamic_pointer_cast<class_decl>(first))
4828 {
4829 class_decl_sptr s = dynamic_pointer_cast<class_decl>(second);
4830 if (!s)
4831 return diff_sptr();
4832
4833 if (f->get_is_declaration_only())
4834 {
4835 class_decl_sptr f2 = f->get_definition_of_declaration();
4836 if (f2)
4837 f = f2;
4838 }
4839 if (s->get_is_declaration_only())
4840 {
4841 class_decl_sptr s2 = s->get_definition_of_declaration();
4842 if (s2)
4843 s = s2;
4844 }
4845 return compute_diff(f, s, ctxt);
4846 }
4847 return diff_sptr();
4848 }
4849
4850 /// Try to diff entities that are of distinct kinds.
4851 ///
4852 /// @param first the first entity to consider for the diff.
4853 ///
4854 /// @param second the second entity to consider for the diff.
4855 ///
4856 /// @param ctxt the context of the diff.
4857 ///
4858 /// @return a non-null diff if a diff object could be built, null
4859 /// otherwise.
4860 static diff_sptr
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);}
4865
4866 /// Compute the difference between two types.
4867 ///
4868 /// The function considers every possible types known to libabigail
4869 /// and runs the appropriate diff function on them.
4870 ///
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.
4874 ///
4875 /// @param first the first type decl to consider for the diff
4876 ///
4877 /// @param second the second type decl to consider for the diff.
4878 ///
4879 /// @param ctxt the diff context to use.
4880 ///
4881 /// @return the resulting diff. It's a pointer to a descendent of
4882 /// abigail::comparison::diff.
4883 static diff_sptr
4884 compute_diff_for_types(const decl_base_sptr first,
4885 const decl_base_sptr second,
4886 diff_context_sptr ctxt)
4887 {
4888 diff_sptr d;
4889
4890 const decl_base_sptr f = first;
4891 const decl_base_sptr s = second;
4892
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)));
4903
4904 assert(d);
4905
4906 return d;
4907 }
4908
4909 diff_category
4910 operator|(diff_category c1, diff_category c2)
4911 {return static_cast<diff_category>(static_cast<unsigned>(c1)
4912 | static_cast<unsigned>(c2));}
4913
4914 diff_category&
4915 operator|=(diff_category& c1, diff_category c2)
4916 {
4917 c1 = c1 | c2;
4918 return c1;
4919 }
4920
4921 diff_category&
4922 operator&=(diff_category& c1, diff_category c2)
4923 {
4924 c1 = c1 & c2;
4925 return c1;
4926 }
4927
4928 diff_category
4929 operator^(diff_category c1, diff_category c2)
4930 {return static_cast<diff_category>(static_cast<unsigned>(c1)
4931 ^ static_cast<unsigned>(c2));}
4932
4933 diff_category
4934 operator&(diff_category c1, diff_category c2)
4935 {return static_cast<diff_category>(static_cast<unsigned>(c1)
4936 & static_cast<unsigned>(c2));}
4937
4938 diff_category
4939 operator~(diff_category c)
4940 {return static_cast<diff_category>(~static_cast<unsigned>(c));}
4941
4942 /// Serialize an instance of @ref diff_category to an output stream.
4943 ///
4944 /// @param o the output stream to serialize @p c to.
4945 ///
4946 /// @param c the instance of diff_category to serialize.
4947 ///
4948 /// @return the output stream to serialize @p c to.
4949 ostream&
4950 operator<<(ostream& o, diff_category c)
4951 {
4952 bool emitted_a_category = false;
4953
4954 if (c == NO_CHANGE_CATEGORY)
4955 {
4956 o << "NO_CHANGE_CATEGORY";
4957 emitted_a_category = true;
4958 }
4959
4960 if (c & ACCESS_CHANGE_CATEGORY)
4961 {
4962 if (emitted_a_category)
4963 o << "|";
4964 o << "ACCESS_CHANGE_CATEGORY";
4965 emitted_a_category |= true;
4966 }
4967
4968 if (c & COMPATIBLE_TYPE_CHANGE_CATEGORY)
4969 {
4970 if (emitted_a_category)
4971 o << "|";
4972 o << "COMPATIBLE_TYPE_CHANGE_CATEGORY";
4973 emitted_a_category |= true;
4974 }
4975
4976 if (c & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
4977 {
4978 if (emitted_a_category)
4979 o << "|";
4980 o << "HARMLESS_DECL_NAME_CHANGE_CATEGORY";
4981 emitted_a_category |= true;
4982 }
4983
4984 if (c & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
4985 {
4986 if (emitted_a_category)
4987 o << "|";
4988 o << "NON_VIRT_MEM_FUN_CHANGE_CATEGORY";
4989 emitted_a_category |= true;
4990 }
4991
4992 if (c & STATIC_DATA_MEMBER_CHANGE_CATEGORY)
4993 {
4994 if (emitted_a_category)
4995 o << "|";
4996 o << "STATIC_DATA_MEMBER_CHANGE_CATEGORY";
4997 emitted_a_category |= true;
4998 }
4999 else if (c & HARMLESS_ENUM_CHANGE_CATEGORY)
5000 {
5001 if (emitted_a_category)
5002 o << "|";
5003 o << "HARMLESS_ENUM_CHANGE_CATEGORY";
5004 emitted_a_category |= true;
5005 }
5006
5007 if (c & HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY)
5008 {
5009 if (emitted_a_category)
5010 o << "|";
5011 o << "HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY";
5012 emitted_a_category |= true;
5013 }
5014
5015 if (c & SIZE_OR_OFFSET_CHANGE_CATEGORY)
5016 {
5017 if (emitted_a_category)
5018 o << "|";
5019 o << "SIZE_OR_OFFSET_CHANGE_CATEGORY";
5020 emitted_a_category |= true;
5021 }
5022
5023 if (c & VIRTUAL_MEMBER_CHANGE_CATEGORY)
5024 {
5025 if (emitted_a_category)
5026 o << "|";
5027 o << "VIRTUAL_MEMBER_CHANGE_CATEGORY";
5028 emitted_a_category |= true;
5029 }
5030
5031 if (c & REDUNDANT_CATEGORY)
5032 {
5033 if (emitted_a_category)
5034 o << "|";
5035 o << "REDUNDANT_CATEGORY";
5036 emitted_a_category |= true;
5037 }
5038
5039 if (c & SUPPRESSED_CATEGORY)
5040 {
5041 if (emitted_a_category)
5042 o << "|";
5043 o << "SUPPRESSED_CATEGORY";
5044 emitted_a_category |= true;
5045 }
5046
5047 return o;
5048 }
5049
5050 /// Compute the difference between two types.
5051 ///
5052 /// The function considers every possible types known to libabigail
5053 /// and runs the appropriate diff function on them.
5054 ///
5055 /// @param first the first construct to consider for the diff
5056 ///
5057 /// @param second the second construct to consider for the diff.
5058 ///
5059 /// @param ctxt the diff context to use.
5060 ///
5061 /// @return the resulting diff. It's a pointer to a descendent of
5062 /// abigail::comparison::diff.
5063 static diff_sptr
5064 compute_diff_for_types(const type_base_sptr first,
5065 const type_base_sptr second,
5066 diff_context_sptr ctxt)
5067 {
5068 diff_sptr d;
5069
5070 decl_base_sptr f = dynamic_pointer_cast<decl_base>(first);
5071 decl_base_sptr s = dynamic_pointer_cast<decl_base>(second);
5072
5073 d = compute_diff_for_types(f, s, ctxt);
5074
5075 return d;
5076 }
5077
5078 /// Compute the difference between two decls.
5079 ///
5080 /// The function consider every possible decls known to libabigail and
5081 /// runs the appropriate diff function on them.
5082 ///
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.
5086 ///
5087 /// @param first the first decl to consider for the diff
5088 ///
5089 /// @param second the second decl to consider for the diff.
5090 ///
5091 /// @param ctxt the diff context to use.
5092 ///
5093 /// @return the resulting diff.
5094 static diff_sptr
5095 compute_diff_for_decls(const decl_base_sptr first,
5096 const decl_base_sptr second,
5097 diff_context_sptr ctxt)
5098 {
5099
5100 diff_sptr d;
5101
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)));
5105
5106 assert(d);
5107
5108 return d;
5109 }
5110
5111 /// Compute the difference between two decls. The decls can represent
5112 /// either type declarations, or non-type declaration.
5113 ///
5114 /// @param first the first decl to consider.
5115 ///
5116 /// @param second the second decl to consider.
5117 ///
5118 /// @param ctxt the diff context to use.
5119 ///
5120 /// @return the resulting diff, or NULL if the diff could not be
5121 /// computed.
5122 diff_sptr
5123 compute_diff(const decl_base_sptr first,
5124 const decl_base_sptr second,
5125 diff_context_sptr ctxt)
5126 {
5127 if (!first || !second)
5128 return diff_sptr();
5129
5130 diff_sptr d;
5131 if (is_type(first) && is_type(second))
5132 d = compute_diff_for_types(first, second, ctxt);
5133 else
5134 d = compute_diff_for_decls(first, second, ctxt);
5135 assert(d);
5136 return d;
5137 }
5138
5139 /// Compute the difference between two types.
5140 ///
5141 /// @param first the first type to consider.
5142 ///
5143 /// @param second the second type to consider.
5144 ///
5145 /// @param ctxt the diff context to use.
5146 ///
5147 /// @return the resulting diff, or NULL if the diff couldn't be
5148 /// computed.
5149 diff_sptr
5150 compute_diff(const type_base_sptr first,
5151 const type_base_sptr second,
5152 diff_context_sptr ctxt)
5153 {
5154 assert(first && second);
5155
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);
5159 assert(d);
5160 return d;
5161 }
5162
5163 /// Get a copy of the pretty representation of a diff node.
5164 ///
5165 /// @param d the diff node to consider.
5166 ///
5167 /// @return the pretty representation string.
5168 string
5169 get_pretty_representation(diff* d)
5170 {
5171 if (!d)
5172 return "";
5173 string prefix= "diff of ";
5174 return prefix + get_pretty_representation(d->first_subject());
5175 }
5176
5177 static bool
5178 maybe_report_diff_for_member(decl_base_sptr decl1,
5179 decl_base_sptr decl2,
5180 diff_context_sptr ctxt,
5181 ostream& out,
5182 const string& indent);
5183
5184 /// Stream a string representation for a member function.
5185 ///
5186 /// @param ctxt the current diff context.
5187 ///
5188 /// @param mem_fn the member function to stream
5189 ///
5190 /// @param out the output stream to send the representation to
5191 static void
5192 represent(diff_context& ctxt,
5193 class_decl::method_decl_sptr mem_fn,
5194 ostream& out)
5195 {
5196 if (!mem_fn || !is_member_function(mem_fn))
5197 return;
5198
5199 class_decl::method_decl_sptr meth =
5200 dynamic_pointer_cast<class_decl::method_decl>(mem_fn);
5201 assert(meth);
5202
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)
5207 << "/"
5208 << meth->get_type()->get_class_type()->get_virtual_mem_fns().size();
5209
5210 if (ctxt.show_linkage_names()
5211 && (mem_fn->get_symbol()))
5212 {
5213 out << " {"
5214 << mem_fn->get_symbol()->get_id_string()
5215 << "}";
5216 }
5217 out << "\n";
5218 }
5219
5220 /// Stream a string representation for a data member.
5221 ///
5222 /// @param d the data member to stream
5223 ///
5224 /// @param out the output stream to send the representation to
5225 static void
5226 represent_data_member(var_decl_sptr d, ostream& out)
5227 {
5228 if (!is_data_member(d)
5229 || (!get_member_is_static(d) && !get_data_member_is_laid_out(d)))
5230 return;
5231
5232 out << "'" << d->get_pretty_representation() << "'";
5233 if (!get_member_is_static(d))
5234 out << ", at offset "
5235 << get_data_member_offset(d)
5236 << " (in bits)\n";
5237 }
5238
5239 /// Represent the changes carried by an instance of @ref var_diff that
5240 /// represent a difference between two class data members.
5241 ///
5242 /// @param diff diff the diff node to represent.
5243 ///
5244 /// @param ctxt the diff context to use.
5245 ///
5246 /// @param out the output stream to send the representation to.
5247 ///
5248 /// @param indent the indentation string to use for the change report.
5249 static void
5250 represent(var_diff_sptr diff,
5251 diff_context_sptr ctxt,
5252 ostream& out,
5253 const string& indent = "")
5254 {
5255 if (!diff->to_be_reported())
5256 return;
5257
5258 var_decl_sptr o = diff->first_var();
5259 var_decl_sptr n = diff->second_var();
5260
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();
5266
5267 if (diff_sptr d = diff->type_diff())
5268 {
5269 if (d->to_be_reported())
5270 {
5271 out << indent
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";
5277 else
5278 d->report(out, indent + " ");
5279 begin_with_and = true;
5280 }
5281 }
5282
5283 if (name1 != name2)
5284 {
5285 if (filtering::has_harmless_name_change(o, n)
5286 && !(ctxt->get_allowed_category()
5287 & HARMLESS_DECL_NAME_CHANGE_CATEGORY))
5288 ;
5289 else
5290 {
5291 out << indent;
5292 if (begin_with_and)
5293 {
5294 out << "and ";
5295 begin_with_and = false;
5296 }
5297 out << "name of '" << name1 << "' changed to '" << name2 << "'";
5298 emitted = true;
5299 }
5300 }
5301
5302 if (get_data_member_is_laid_out(o)
5303 != get_data_member_is_laid_out(n))
5304 {
5305 if (begin_with_and)
5306 {
5307 out << indent << "and ";
5308 begin_with_and = false;
5309 }
5310 else if (!emitted)
5311 out << indent << "'" << pretty_representation << "' ";
5312 else
5313 out << ", ";
5314 if (get_data_member_is_laid_out(o))
5315 out << "is no more laid out";
5316 else
5317 out << "now becomes laid out";
5318 emitted = true;
5319 }
5320 if ((ctxt->get_allowed_category() & SIZE_OR_OFFSET_CHANGE_CATEGORY)
5321 && (get_data_member_offset(o)
5322 != get_data_member_offset(n)))
5323 {
5324 if (begin_with_and)
5325 {
5326 out << indent << "and ";
5327 begin_with_and = false;
5328 }
5329 else if (!emitted)
5330 out << indent << "'" << pretty_representation << "' ";
5331 else
5332 out << ", ";
5333 out << "offset changed from "
5334 << get_data_member_offset(o)
5335 << " to " << get_data_member_offset(n)
5336 << " (in bits)";
5337 emitted = true;
5338 }
5339 if (o->get_binding() != n->get_binding())
5340 {
5341 if (begin_with_and)
5342 {
5343 out << indent << "and ";
5344 begin_with_and = false;
5345 }
5346 else if (!emitted)
5347 out << indent << "'" << pretty_representation << "' ";
5348 else
5349 out << ", ";
5350 out << "elf binding changed from " << o->get_binding()
5351 << " to " << n->get_binding();
5352 emitted = true;
5353 }
5354 if (o->get_visibility() != n->get_visibility())
5355 {
5356 if (begin_with_and)
5357 {
5358 out << indent << "and ";
5359 begin_with_and = false;
5360 }
5361 else if (!emitted)
5362 out << indent << "'" << pretty_representation << "' ";
5363 else
5364 out << ", ";
5365 out << "visibility changed from " << o->get_visibility()
5366 << " to " << n->get_visibility();
5367 }
5368 if ((ctxt->get_allowed_category() & ACCESS_CHANGE_CATEGORY)
5369 && (get_member_access_specifier(o)
5370 != get_member_access_specifier(n)))
5371 {
5372 if (begin_with_and)
5373 {
5374 out << indent << "and ";
5375 begin_with_and = false;
5376 }
5377 else if (!emitted)
5378 out << indent << "'" << pretty_representation << "' ";
5379 else
5380 out << ", ";
5381
5382 out << "access changed from '"
5383 << get_member_access_specifier(o)
5384 << "' to '"
5385 << get_member_access_specifier(n) << "'";
5386 emitted = true;
5387 }
5388 if (get_member_is_static(o)
5389 != get_member_is_static(n))
5390 {
5391 if (begin_with_and)
5392 {
5393 out << indent << "and ";
5394 begin_with_and = false;
5395 }
5396 else if (!emitted)
5397 out << indent << "'" << pretty_representation << "' ";
5398 else
5399 out << ", ";
5400
5401 if (get_member_is_static(o))
5402 out << "is no more static";
5403 else
5404 out << "now becomes static";
5405 }
5406 }
5407
5408 /// Report the size and alignment changes of a type.
5409 ///
5410 /// @param first the first type to consider.
5411 ///
5412 /// @param second the second type to consider.
5413 ///
5414 /// @param ctxt the content of the current diff.
5415 ///
5416 /// @param out the output stream to report the change to.
5417 ///
5418 /// @param indent the string to use for indentation.
5419 ///
5420 /// @param nl whether to start the first report line with a new line.
5421 ///
5422 /// @return true iff something was reported.
5423 static bool
5424 report_size_and_alignment_changes(type_or_decl_base_sptr first,
5425 type_or_decl_base_sptr second,
5426 diff_context_sptr ctxt,
5427 ostream& out,
5428 const string& indent,
5429 bool nl)
5430 {
5431 type_base_sptr f = dynamic_pointer_cast<type_base>(first),
5432 s = dynamic_pointer_cast<type_base>(second);
5433
5434 if (!s || !f)
5435 return false;
5436
5437 bool n = false;
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;
5444
5445 if (nl)
5446 out << "\n";
5447
5448 if ((ctxt->get_allowed_category() & SIZE_OR_OFFSET_CHANGE_CATEGORY)
5449 && (fs != ss || fdc != sdc))
5450 {
5451 if (first_array && second_array)
5452 {
5453 // We are looking at size or alignment changes between two
5454 // arrays ...
5455 out << indent << "array type size changed from ";
5456 if (first_array->is_infinite())
5457 out << "infinity";
5458 else
5459 out << first_array->get_size_in_bits();
5460 out << " to ";
5461 if (second_array->is_infinite())
5462 out << "infinity";
5463 else
5464 out << second_array->get_size_in_bits();
5465 out << " bits:\n";
5466
5467 if (sdc != fdc)
5468 {
5469 out << indent + " "
5470 << "number of dimensions changed from "
5471 << fdc
5472 << " to "
5473 << sdc
5474 << "\n";
5475 }
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());
5481 ++i, ++j)
5482 {
5483 if ((*i)->get_length() != (*j)->get_length())
5484 {
5485 out << indent
5486 << "array type subrange "
5487 << i - first_array->get_subranges().begin() + 1
5488 << " changed length from ";
5489
5490 if ((*i)->is_infinite())
5491 out << "infinity";
5492 else
5493 out << (*i)->get_length();
5494
5495 out << " to ";
5496
5497 if ((*j)->is_infinite())
5498 out << "infinity";
5499 else
5500 out << (*j)->get_length();
5501 out << "\n";
5502 }
5503 }
5504 }
5505 else
5506 {
5507 out << indent
5508 << "type size changed from " << fs << " to " << ss << " bits";
5509 n = true;
5510 }
5511 }
5512 if ((ctxt->get_allowed_category() & SIZE_OR_OFFSET_CHANGE_CATEGORY)
5513 && (fa != sa))
5514 {
5515 if (n)
5516 out << "\n";
5517 out << indent
5518 << "type alignment changed from " << fa << " to " << sa << " bits";
5519 n = true;
5520 }
5521
5522 if (n)
5523 return true;
5524 return false;
5525 }
5526
5527 /// Report the name, size and alignment changes of a type.
5528 ///
5529 /// @param first the first type to consider.
5530 ///
5531 /// @param second the second type to consider.
5532 ///
5533 /// @param ctxt the content of the current diff.
5534 ///
5535 /// @param out the output stream to report the change to.
5536 ///
5537 /// @param indent the string to use for indentation.
5538 ///
5539 /// @param nl whether to start the first report line with a new line.
5540 ///
5541 /// @return true iff something was reported.
5542 static bool
5543 report_name_size_and_alignment_changes(decl_base_sptr first,
5544 decl_base_sptr second,
5545 diff_context_sptr ctxt,
5546 ostream& out,
5547 const string& indent,
5548 bool nl)
5549 {
5550 string fn = first->get_qualified_name(),
5551 sn = second->get_qualified_name();
5552
5553 if (fn != sn)
5554 {
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.
5559 ;
5560 else
5561 {
5562 if (nl)
5563 out << "\n";
5564 out << indent;
5565 if (is_type(first))
5566 out << "type";
5567 else
5568 out << "declaration";
5569 out << " name changed from '" << fn << "' to '" << sn << "'";
5570 nl = true;
5571 }
5572 }
5573
5574 nl |= report_size_and_alignment_changes(first, second, ctxt,
5575 out, indent, nl);
5576 return nl;
5577 }
5578
5579 /// Represent the kind of difference we want report_mem_header() to
5580 /// report.
5581 enum diff_kind
5582 {
5583 del_kind,
5584 ins_kind,
5585 subtype_change_kind,
5586 change_kind
5587 };
5588
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.
5592 ///
5593 /// @param out the output stream to output the report to.
5594 ///
5595 /// @param number the number of insertion/deletion to refer to in the
5596 /// header.
5597 ///
5598 /// @param k the kind of diff (insertion/deletion/change) we want the
5599 /// head to introduce.
5600 ///
5601 /// @param section_name the name of the sub-part of the class to
5602 /// report about.
5603 ///
5604 /// @param indent the string to use as indentation prefix in the
5605 /// header.
5606 static void
5607 report_mem_header(ostream& out,
5608 size_t number,
5609 size_t num_filtered,
5610 diff_kind k,
5611 const string& section_name,
5612 const string& indent)
5613 {
5614 size_t net_number = number - num_filtered;
5615 string change;
5616 char colon_or_semi_colon = ':';
5617
5618 switch (k)
5619 {
5620 case del_kind:
5621 change = (number > 1) ? "deletions" : "deletion";
5622 break;
5623 case ins_kind:
5624 change = (number > 1) ? "insertions" : "insertion";
5625 break;
5626 case subtype_change_kind:
5627 case change_kind:
5628 change = (number > 1) ? "changes" : "change";
5629 break;
5630 }
5631
5632 if (net_number == 0)
5633 {
5634 out << indent << "no " << section_name << " " << change;
5635 colon_or_semi_colon = ';';
5636 }
5637 else if (net_number == 1)
5638 out << indent << "1 " << section_name << " " << change;
5639 else
5640 out << indent << net_number << " " << section_name
5641 << " " << change;
5642
5643 if (num_filtered)
5644 out << " (" << num_filtered << " filtered)";
5645 out << colon_or_semi_colon << '\n';
5646 }
5647
5648 // <var_diff stuff>
5649
5650 /// The internal type for the impl idiom implementation of @ref
5651 /// var_diff.
5652 struct var_diff::priv
5653 {
5654 diff_sptr type_diff_;
5655 };//end struct var_diff
5656
5657 /// Populate the vector of children node of the @ref diff base type
5658 /// sub-object of this instance of @ref var_diff.
5659 ///
5660 /// The children node can then later be retrieved using
5661 /// diff::children_node().
5662 void
5663 var_diff::chain_into_hierarchy()
5664 {append_child_node(type_diff());}
5665
5666 /// @return the pretty representation for this current instance of
5667 /// @ref var_diff.
5668 const string&
5669 var_diff::get_pretty_representation() const
5670 {
5671 if (diff::priv_->pretty_representation_.empty())
5672 {
5673 std::ostringstream o;
5674 o << "var_diff["
5675 << first_subject()->get_pretty_representation()
5676 << ", "
5677 << second_subject()->get_pretty_representation()
5678 << "]";
5679 diff::priv_->pretty_representation_ = o.str();
5680 }
5681 return diff::priv_->pretty_representation_;
5682 }
5683 /// Constructor for @ref var_diff.
5684 ///
5685 /// @param first the first instance of @ref var_decl to consider in
5686 /// the diff.
5687 ///
5688 /// @param second the second instance of @ref var_decl to consider in
5689 /// the diff.
5690 ///
5691 /// @param type_diff the diff between types of the instances of
5692 /// var_decl.
5693 ///
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),
5700 priv_(new priv)
5701 {priv_->type_diff_ = type_diff;}
5702
5703 /// Finish building the current instance of @ref var_diff.
5704 void
5705 var_diff::finish_diff_type()
5706 {
5707 if (diff::priv_->finished_)
5708 return;
5709 chain_into_hierarchy();
5710 diff::priv_->finished_ = true;
5711 }
5712
5713 /// Getter for the first @ref var_decl of the diff.
5714 ///
5715 /// @return the first @ref var_decl of the diff.
5716 var_decl_sptr
5717 var_diff::first_var() const
5718 {return dynamic_pointer_cast<var_decl>(first_subject());}
5719
5720 /// Getter for the second @ref var_decl of the diff.
5721 ///
5722 /// @return the second @ref var_decl of the diff.
5723 var_decl_sptr
5724 var_diff::second_var() const
5725 {return dynamic_pointer_cast<var_decl>(second_subject());}
5726
5727 /// Getter for the diff of the types of the instances of @ref
5728 /// var_decl.
5729 ///
5730 /// @return the diff of the types of the instances of @ref var_decl.
5731 diff_sptr
5732 var_diff::type_diff() const
5733 {
5734 if (!priv_->type_diff_)
5735 priv_->type_diff_ = compute_diff(first_var()->get_type(),
5736 second_var()->get_type(),
5737 context());
5738 return priv_->type_diff_;
5739 }
5740
5741 /// Return true iff the diff node has a change.
5742 ///
5743 /// @return true iff the diff node has a change.
5744 bool
5745 var_diff::has_changes() const
5746 {
5747 if (!!first_var() != !!second_var())
5748 return true;
5749
5750 if (first_var().get() == second_var().get())
5751 return false;
5752
5753 if (first_var()->get_hash() && second_var()->get_hash()
5754 && first_var()->get_hash() != second_var()->get_hash())
5755 return true;
5756
5757 return *first_var() != *second_var();
5758 }
5759
5760 /// @return true iff the current diff node carries local changes.
5761 bool
5762 var_diff::has_local_changes() const
5763 {
5764 ir::change_kind k = ir::NO_CHANGE_KIND;
5765 if (!equals(*first_var(), *second_var(), &k))
5766 return k & LOCAL_CHANGE_KIND;
5767 return false;
5768 }
5769
5770 /// Report the diff in a serialized form.
5771 ///
5772 /// @param out the stream to serialize the diff to.
5773 ///
5774 /// @param indent the prefix to use for the indentation of this
5775 /// serialization.
5776 void
5777 var_diff::report(ostream& out, const string& indent) const
5778 {
5779 if (!to_be_reported())
5780 return;
5781
5782 decl_base_sptr first = first_var(), second = second_var();
5783 string n = first->get_pretty_representation();
5784
5785 if (report_name_size_and_alignment_changes(first, second,
5786 context(),
5787 out, indent,
5788 /*start_with_new_line=*/false))
5789 out << "\n";
5790
5791 maybe_report_diff_for_member(first, second, context(), out, indent);
5792
5793 if (diff_sptr d = type_diff())
5794 {
5795 if (d->to_be_reported())
5796 {
5797 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(d, "type");
5798 out << indent << "type of variable changed:\n";
5799 d->report(out, indent + " ");
5800 }
5801 }
5802 }
5803
5804 /// Compute the diff between two instances of @ref var_decl.
5805 ///
5806 /// @param first the first @ref var_decl to consider for the diff.
5807 ///
5808 /// @param second the second @ref var_decl to consider for the diff.
5809 ///
5810 /// @param ctxt the diff context to use.
5811 ///
5812 /// @return the resulting diff between the two @ref var_decl.
5813 var_diff_sptr
5814 compute_diff(const var_decl_sptr first,
5815 const var_decl_sptr second,
5816 diff_context_sptr ctxt)
5817 {
5818 var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
5819 ctxt->initialize_canonical_diff(d);
5820 return d;
5821 }
5822
5823 // </var_diff stuff>
5824
5825 /// Report the differences in access specifiers and static-ness for
5826 /// class members.
5827 ///
5828 /// @param decl1 the first class member to consider.
5829 ///
5830 /// @param decl2 the second class member to consider.
5831 ///
5832 /// @param out the output stream to send the report to.
5833 ///
5834 /// @param indent the indentation string to use for the report.
5835 ///
5836 /// @return true if something was reported, false otherwise.
5837 static bool
5838 maybe_report_diff_for_member(decl_base_sptr decl1,
5839 decl_base_sptr decl2,
5840 diff_context_sptr ctxt,
5841 ostream& out,
5842 const string& indent)
5843
5844 {
5845 bool reported = false;
5846 if (!is_member_decl(decl1) || !is_member_decl(decl2))
5847 return reported;
5848
5849 string decl1_repr = decl1->get_pretty_representation(),
5850 decl2_repr = decl2->get_pretty_representation();
5851
5852 if (get_member_is_static(decl1) != get_member_is_static(decl2))
5853 {
5854 bool lost = get_member_is_static(decl1);
5855 out << indent << "'" << decl1_repr << "' ";
5856 if (lost)
5857 out << "became non-static";
5858 else
5859 out << "became static";
5860 out << "\n";
5861 reported = true;
5862 }
5863 if ((ctxt->get_allowed_category() & ACCESS_CHANGE_CATEGORY)
5864 && (get_member_access_specifier(decl1)
5865 != get_member_access_specifier(decl2)))
5866 {
5867 out << indent << "'" << decl1_repr << "' access changed from '"
5868 << get_member_access_specifier(decl1)
5869 << "' to '"
5870 << get_member_access_specifier(decl2)
5871 << "'\n";
5872 reported = true;
5873 }
5874 return reported;
5875 }
5876
5877 // <pointer_type_def stuff>
5878 struct pointer_diff::priv
5879 {
5880 diff_sptr underlying_type_diff_;
5881
5882 priv(diff_sptr ud)
5883 : underlying_type_diff_(ud)
5884 {}
5885 };//end struct pointer_diff::priv
5886
5887
5888 /// Populate the vector of children node of the @ref diff base type
5889 /// sub-object of this instance of @ref pointer_diff.
5890 ///
5891 /// The children node can then later be retrieved using
5892 /// diff::children_node().
5893 void
5894 pointer_diff::chain_into_hierarchy()
5895 {append_child_node(underlying_type_diff());}
5896
5897 /// Constructor for a pointer_diff.
5898 ///
5899 /// @param first the first pointer to consider for the diff.
5900 ///
5901 /// @param second the secon pointer to consider for the diff.
5902 ///
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))
5910 {}
5911
5912 /// Finish building the current instance of @ref pointer_diff.
5913 void
5914 pointer_diff::finish_diff_type()
5915 {
5916 if (diff::priv_->finished_)
5917 return;
5918 chain_into_hierarchy();
5919 diff::priv_->finished_ = true;
5920 }
5921
5922 /// Getter for the first subject of a pointer diff
5923 ///
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());}
5928
5929 /// Getter for the second subject of a pointer diff
5930 ///
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());}
5935
5936 /// @return the pretty represenation for the current instance of @ref
5937 /// pointer_diff.
5938 const string&
5939 pointer_diff::get_pretty_representation() const
5940 {
5941 if (diff::priv_->pretty_representation_.empty())
5942 {
5943 std::ostringstream o;
5944 o << "pointer_diff["
5945 << first_subject()->get_pretty_representation()
5946 << ", "
5947 << second_subject()->get_pretty_representation()
5948 << "]";
5949 diff::priv_->pretty_representation_ = o.str();
5950 }
5951 return diff::priv_->pretty_representation_;
5952 }
5953
5954 /// Return true iff the current diff node carries a change.
5955 ///
5956 /// @return true iff the current diff node carries a change.
5957 bool
5958 pointer_diff::has_changes() const
5959 {
5960 return underlying_type_diff()
5961 ? underlying_type_diff()->has_changes()
5962 : false;
5963 }
5964
5965 /// @return true iff the current diff node carries local changes.
5966 bool
5967 pointer_diff::has_local_changes() const
5968 {
5969 ir::change_kind k = ir::NO_CHANGE_KIND;
5970 if (!equals(*first_pointer(), *second_pointer(), &k))
5971 return k & LOCAL_CHANGE_KIND;
5972 return false;
5973 }
5974
5975 /// Getter for the diff between the pointed-to types of the pointers
5976 /// of this diff.
5977 ///
5978 /// @return the diff between the pointed-to types.
5979 diff_sptr
5980 pointer_diff::underlying_type_diff() const
5981 {return priv_->underlying_type_diff_;}
5982
5983 /// Setter for the diff between the pointed-to types of the pointers
5984 /// of this diff.
5985 ///
5986 /// @param d the new diff between the pointed-to types of the pointers
5987 /// of this diff.
5988 void
5989 pointer_diff::underlying_type_diff(const diff_sptr d)
5990 {priv_->underlying_type_diff_ = d;}
5991
5992 /// Report the diff in a serialized form.
5993 ///
5994 /// @param out the stream to serialize the diff to.
5995 ///
5996 /// @param indent the prefix to use for the indentation of this
5997 /// serialization.
5998 void
5999 pointer_diff::report(ostream& out, const string& indent) const
6000 {
6001 if (!to_be_reported())
6002 return;
6003
6004 if (diff_sptr d = underlying_type_diff())
6005 {
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()
6009 : string("void");
6010
6011 out << indent
6012 << "in pointed to type '" << repr << "':\n";
6013 d->report(out, indent + " ");
6014 }
6015 }
6016
6017 /// Compute the diff between between two pointers.
6018 ///
6019 /// @param first the pointer to consider for the diff.
6020 ///
6021 /// @param second the pointer to consider for the diff.
6022 ///
6023 /// @return the resulting diff between the two pointers.
6024 ///
6025 /// @param ctxt the diff context to use.
6026 pointer_diff_sptr
6027 compute_diff(pointer_type_def_sptr first,
6028 pointer_type_def_sptr second,
6029 diff_context_sptr ctxt)
6030 {
6031 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
6032 second->get_pointed_to_type(),
6033 ctxt);
6034 pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
6035 ctxt->initialize_canonical_diff(result);
6036
6037 return result;
6038 }
6039
6040 // </pointer_type_def>
6041
6042 // <array_type_def>
6043 struct array_diff::priv
6044 {
6045 /// The diff between the two array element types.
6046 diff_sptr element_type_diff_;
6047
6048 priv(diff_sptr element_type_diff)
6049 : element_type_diff_(element_type_diff)
6050 {}
6051 };//end struct array_diff::priv
6052
6053 /// Populate the vector of children node of the @ref diff base type
6054 /// sub-object of this instance of @ref array_diff.
6055 ///
6056 /// The children node can then later be retrieved using
6057 /// diff::children_node().
6058 void
6059 array_diff::chain_into_hierarchy()
6060 {append_child_node(element_type_diff());}
6061
6062 /// Constructor for array_diff
6063 ///
6064 /// @param first the first array_type of the diff.
6065 ///
6066 /// @param second the second array_type of the diff.
6067 ///
6068 /// @param element_type_diff the diff between the two array element
6069 /// types.
6070 ///
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))
6078 {}
6079
6080 /// Finish building the current instance of @ref array_diff.
6081 void
6082 array_diff::finish_diff_type()
6083 {
6084 if (diff::priv_->finished_)
6085 return;
6086 chain_into_hierarchy();
6087 diff::priv_->finished_ = true;
6088 }
6089
6090 /// Getter for the first array of the diff.
6091 ///
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());}
6096
6097 /// Getter for the second array of the diff.
6098 ///
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());}
6103
6104 /// Getter for the diff between the two types of array elements.
6105 ///
6106 /// @return the diff between the two types of array elements.
6107 const diff_sptr&
6108 array_diff::element_type_diff() const
6109 {return priv_->element_type_diff_;}
6110
6111 /// Setter for the diff between the two array element types.
6112 ///
6113 /// @param d the new diff betweend the two array element types.
6114 void
6115 array_diff::element_type_diff(diff_sptr d)
6116 {priv_->element_type_diff_ = d;}
6117
6118 /// @return the pretty representation for the current instance of @ref
6119 /// array_diff.
6120 const string&
6121 array_diff::get_pretty_representation() const
6122 {
6123 if (diff::priv_->pretty_representation_.empty())
6124 {
6125 std::ostringstream o;
6126 o << "array_diff["
6127 << first_subject()->get_pretty_representation()
6128 << ", "
6129 << second_subject()->get_pretty_representation()
6130 << "]";
6131 diff::priv_->pretty_representation_ = o.str();
6132 }
6133 return diff::priv_->pretty_representation_;
6134 }
6135
6136 /// Return true iff the current diff node carries a change.
6137 ///
6138 /// @return true iff the current diff node carries a change.
6139 bool
6140 array_diff::has_changes() const
6141 {
6142 bool l = false;
6143
6144 // the array element types match check for differing dimensions
6145 // etc...
6146 array_type_def_sptr
6147 f = dynamic_pointer_cast<array_type_def>(first_subject()),
6148 s = dynamic_pointer_cast<array_type_def>(second_subject());
6149
6150 if (f->get_name() != s->get_name())
6151 l |= true;
6152 if (f->get_size_in_bits() != s->get_size_in_bits())
6153 l |= true;
6154 if (f->get_alignment_in_bits() != s->get_alignment_in_bits())
6155 l |= true;
6156
6157 l |= element_type_diff()
6158 ? element_type_diff()->has_changes()
6159 : false;
6160
6161 return l;
6162 }
6163
6164 /// @return true iff the current diff node carries local changes.
6165 bool
6166 array_diff::has_local_changes() const
6167 {
6168 ir::change_kind k = ir::NO_CHANGE_KIND;
6169 if (!equals(*first_array(), *second_array(), &k))
6170 return k & LOCAL_CHANGE_KIND;
6171 return false;
6172 }
6173
6174 /// Report the diff in a serialized form.
6175 ///
6176 /// @param out the output stream to serialize the dif to.
6177 ///
6178 /// @param indent the string to use for indenting the report.
6179 void
6180 array_diff::report(ostream& out, const string& indent) const
6181 {
6182 if (!to_be_reported())
6183 return;
6184
6185 string name = first_array()->get_pretty_representation();
6186 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(first_array(),
6187 second_array(),
6188 "array type");
6189
6190 diff_sptr d = element_type_diff();
6191 if (d->to_be_reported())
6192 {
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 + " ");
6198 }
6199
6200 report_name_size_and_alignment_changes(first_array(),
6201 second_array(),
6202 context(),
6203 out, indent,
6204 /*new line=*/false);
6205 }
6206
6207 /// Compute the diff between two arrays.
6208 ///
6209 /// @param first the first array to consider for the diff.
6210 ///
6211 /// @param second the second array to consider for the diff.
6212 ///
6213 /// @param ctxt the diff context to use.
6214 array_diff_sptr
6215 compute_diff(array_type_def_sptr first,
6216 array_type_def_sptr second,
6217 diff_context_sptr ctxt)
6218 {
6219 diff_sptr d = compute_diff_for_types(first->get_element_type(),
6220 second->get_element_type(),
6221 ctxt);
6222 array_diff_sptr result(new array_diff(first, second, d, ctxt));
6223 ctxt->initialize_canonical_diff(result);
6224 return result;
6225 }
6226 // </array_type_def>
6227
6228 // <reference_type_def>
6229 struct reference_diff::priv
6230 {
6231 diff_sptr underlying_type_diff_;
6232 priv(diff_sptr underlying)
6233 : underlying_type_diff_(underlying)
6234 {}
6235 };//end struct reference_diff::priv
6236
6237 /// Populate the vector of children node of the @ref diff base type
6238 /// sub-object of this instance of @ref reference_diff.
6239 ///
6240 /// The children node can then later be retrieved using
6241 /// diff::children_node().
6242 void
6243 reference_diff::chain_into_hierarchy()
6244 {append_child_node(underlying_type_diff());}
6245
6246 /// Constructor for reference_diff
6247 ///
6248 /// @param first the first reference_type of the diff.
6249 ///
6250 /// @param second the second reference_type of the diff.
6251 ///
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))
6259 {}
6260
6261 /// Finish building the current instance of @ref reference_diff.
6262 void
6263 reference_diff::finish_diff_type()
6264 {
6265 if (diff::priv_->finished_)
6266 return;
6267 chain_into_hierarchy();
6268 diff::priv_->finished_ = true;
6269 }
6270
6271 /// Getter for the first reference of the diff.
6272 ///
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());}
6277
6278 /// Getter for the second reference of the diff.
6279 ///
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());}
6284
6285
6286 /// Getter for the diff between the two referred-to types.
6287 ///
6288 /// @return the diff between the two referred-to types.
6289 const diff_sptr&
6290 reference_diff::underlying_type_diff() const
6291 {return priv_->underlying_type_diff_;}
6292
6293 /// Setter for the diff between the two referred-to types.
6294 ///
6295 /// @param d the new diff betweend the two referred-to types.
6296 diff_sptr&
6297 reference_diff::underlying_type_diff(diff_sptr d)
6298 {
6299 priv_->underlying_type_diff_ = d;
6300 return priv_->underlying_type_diff_;
6301 }
6302
6303 /// @return the pretty representation for the current instance of @ref
6304 /// reference_diff.
6305 const string&
6306 reference_diff::get_pretty_representation() const
6307 {
6308 if (diff::priv_->pretty_representation_.empty())
6309 {
6310 std::ostringstream o;
6311 o << "reference_diff["
6312 << first_subject()->get_pretty_representation()
6313 << ", "
6314 << second_subject()->get_pretty_representation()
6315 << "]";
6316 diff::priv_->pretty_representation_ = o.str();
6317 }
6318 return diff::priv_->pretty_representation_;
6319 }
6320
6321 /// Return true iff the current diff node carries a change.
6322 ///
6323 /// @return true iff the current diff node carries a change.
6324 bool
6325 reference_diff::has_changes() const
6326 {
6327 return underlying_type_diff()
6328 ? underlying_type_diff()->has_changes()
6329 : false;
6330 }
6331
6332 /// @return true iff the current diff node carries local changes.
6333 bool
6334 reference_diff::has_local_changes() const
6335 {
6336 ir::change_kind k = ir::NO_CHANGE_KIND;
6337 if (!equals(*first_reference(), *second_reference(), &k))
6338 return k & LOCAL_CHANGE_KIND;
6339 return false;
6340 }
6341
6342 /// Report the diff in a serialized form.
6343 ///
6344 /// @param out the output stream to serialize the dif to.
6345 ///
6346 /// @param indent the string to use for indenting the report.
6347 void
6348 reference_diff::report(ostream& out, const string& indent) const
6349 {
6350 if (!to_be_reported())
6351 return;
6352
6353 if (diff_sptr d = underlying_type_diff())
6354 {
6355 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(d, "referenced type");
6356 out << indent
6357 << "in referenced type '"
6358 << d->first_subject()->get_pretty_representation()
6359 << "':\n";
6360 d->report(out, indent + " ");
6361 }
6362 }
6363
6364 /// Compute the diff between two references.
6365 ///
6366 /// @param first the first reference to consider for the diff.
6367 ///
6368 /// @param second the second reference to consider for the diff.
6369 ///
6370 /// @param ctxt the diff context to use.
6371 reference_diff_sptr
6372 compute_diff(reference_type_def_sptr first,
6373 reference_type_def_sptr second,
6374 diff_context_sptr ctxt)
6375 {
6376 diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
6377 second->get_pointed_to_type(),
6378 ctxt);
6379 reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
6380 ctxt->initialize_canonical_diff(result);
6381 return result;
6382 }
6383 // </reference_type_def>
6384
6385 // <qualified_type_diff stuff>
6386
6387 struct qualified_type_diff::priv
6388 {
6389 diff_sptr underlying_type_diff;
6390 mutable diff_sptr leaf_underlying_type_diff;
6391
6392 priv(diff_sptr underlying)
6393 : underlying_type_diff(underlying)
6394 {}
6395 };// end struct qualified_type_diff::priv
6396
6397 /// Populate the vector of children node of the @ref diff base type
6398 /// sub-object of this instance of @ref qualified_type_diff.
6399 ///
6400 /// The children node can then later be retrieved using
6401 /// diff::children_node().
6402 void
6403 qualified_type_diff::chain_into_hierarchy()
6404 {append_child_node(leaf_underlying_type_diff());}
6405
6406 /// Constructor for qualified_type_diff.
6407 ///
6408 /// @param first the first qualified type of the diff.
6409 ///
6410 /// @param second the second qualified type of the diff.
6411 ///
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,
6415 diff_sptr under,
6416 diff_context_sptr ctxt)
6417 : type_diff_base(first, second, ctxt),
6418 priv_(new priv(under))
6419 {}
6420
6421 /// Finish building the current instance of @ref qualified_type_diff.
6422 void
6423 qualified_type_diff::finish_diff_type()
6424 {
6425 if (diff::priv_->finished_)
6426 return;
6427 chain_into_hierarchy();
6428 diff::priv_->finished_ = true;
6429 }
6430
6431 /// Getter for the first qualified type of the diff.
6432 ///
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());}
6437
6438 /// Getter for the second qualified type of the diff.
6439 ///
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());}
6444
6445 /// Getter for the diff between the underlying types of the two
6446 /// qualified types.
6447 ///
6448 /// @return the diff between the underlying types of the two qualified
6449 /// types.
6450 diff_sptr
6451 qualified_type_diff::underlying_type_diff() const
6452 {return priv_->underlying_type_diff;}
6453
6454 /// Getter for the diff between the most underlying non-qualified
6455 /// types of two qualified types.
6456 ///
6457 /// @return the diff between the most underlying non-qualified types
6458 /// of two qualified types.
6459 diff_sptr
6460 qualified_type_diff::leaf_underlying_type_diff() const
6461 {
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()),
6466 context());
6467
6468 return priv_->leaf_underlying_type_diff;
6469 }
6470
6471 /// Setter for the diff between the underlying types of the two
6472 /// qualified types.
6473 ///
6474 /// @return the diff between the underlying types of the two qualified
6475 /// types.
6476 void
6477 qualified_type_diff::underlying_type_diff(const diff_sptr d)
6478 {priv_->underlying_type_diff = d;}
6479
6480 /// @return the pretty representation of the current instance of @ref
6481 /// qualified_type_diff.
6482 const string&
6483 qualified_type_diff::get_pretty_representation() const
6484 {
6485 if (diff::priv_->pretty_representation_.empty())
6486 {
6487 std::ostringstream o;
6488 o << "qualified_type_diff["
6489 << first_subject()->get_pretty_representation()
6490 << ", "
6491 << second_subject()->get_pretty_representation()
6492 << "]";
6493 diff::priv_->pretty_representation_ = o.str();
6494 }
6495 return diff::priv_->pretty_representation_;
6496 }
6497
6498 /// Return true iff the current diff node carries a change.
6499 ///
6500 /// @return true iff the current diff node carries a change.
6501 bool
6502 qualified_type_diff::has_changes() const
6503 {
6504 bool l = false;
6505 char fcv = first_qualified_type()->get_cv_quals(),
6506 scv = second_qualified_type()->get_cv_quals();
6507
6508 if (fcv != scv)
6509 {
6510 if ((fcv & qualified_type_def::CV_CONST)
6511 != (scv & qualified_type_def::CV_CONST))
6512 l |= true;
6513 if ((fcv & qualified_type_def::CV_VOLATILE)
6514 != (scv & qualified_type_def::CV_RESTRICT))
6515 l |= true;
6516 if ((fcv & qualified_type_def::CV_RESTRICT)
6517 != (scv & qualified_type_def::CV_RESTRICT))
6518 l |= true;
6519 }
6520
6521 return (underlying_type_diff()
6522 ? underlying_type_diff()->has_changes() || l
6523 : l);
6524 }
6525
6526 /// @return true iff the current diff node carries local changes.
6527 bool
6528 qualified_type_diff::has_local_changes() const
6529 {
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;
6533 return false;
6534 }
6535
6536 /// Return the first underlying type that is not a qualified type.
6537 /// @param t the qualified type to consider.
6538 ///
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)
6543 {
6544 if (!t)
6545 return type_base_sptr();
6546
6547 type_base_sptr ut = t->get_underlying_type();
6548 qualified_type_def_sptr qut = dynamic_pointer_cast<qualified_type_def>(ut);
6549
6550 if (!qut)
6551 return ut;
6552 return get_leaf_type(qut);
6553 }
6554
6555 /// Report the diff in a serialized form.
6556 ///
6557 /// @param out the output stream to serialize to.
6558 ///
6559 /// @param indent the string to use to indent the lines of the report.
6560 void
6561 qualified_type_diff::report(ostream& out, const string& indent) const
6562 {
6563 if (!to_be_reported())
6564 return;
6565
6566 string fname = first_qualified_type()->get_pretty_representation(),
6567 sname = second_qualified_type()->get_pretty_representation();
6568
6569 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(first_qualified_type(),
6570 second_qualified_type());
6571
6572 if (fname != sname)
6573 {
6574 out << indent << "'" << fname << "' changed to '" << sname << "'\n";
6575 return;
6576 }
6577
6578 diff_sptr d = leaf_underlying_type_diff();
6579 assert(d);
6580 assert(d->to_be_reported());
6581 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(d,
6582 "unqualified "
6583 "underlying type");
6584
6585 string fltname = d->first_subject()->get_pretty_representation();
6586 out << indent << "in unqualified underlying type '" << fltname << "':\n";
6587 d->report(out, indent + " ");
6588 }
6589
6590 /// Compute the diff between two qualified types.
6591 ///
6592 /// @param first the first qualified type to consider for the diff.
6593 ///
6594 /// @param second the second qualified type to consider for the diff.
6595 ///
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)
6601 {
6602 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
6603 second->get_underlying_type(),
6604 ctxt);
6605 qualified_type_diff_sptr result(new qualified_type_diff(first, second,
6606 d, ctxt));
6607 ctxt->initialize_canonical_diff(result);
6608 return result;
6609 }
6610
6611 // </qualified_type_diff stuff>
6612
6613 // <enum_diff stuff>
6614 struct enum_diff::priv
6615 {
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_;
6621
6622 priv(diff_sptr underlying)
6623 : underlying_type_diff_(underlying)
6624 {}
6625 };//end struct enum_diff::priv
6626
6627 /// Clear the lookup tables useful for reporting an enum_diff.
6628 ///
6629 /// This function must be updated each time a lookup table is added or
6630 /// removed from the class_diff::priv.
6631 void
6632 enum_diff::clear_lookup_tables()
6633 {
6634 priv_->deleted_enumerators_.clear();
6635 priv_->inserted_enumerators_.clear();
6636 priv_->changed_enumerators_.clear();
6637 }
6638
6639 /// Tests if the lookup tables are empty.
6640 ///
6641 /// @return true if the lookup tables are empty, false otherwise.
6642 bool
6643 enum_diff::lookup_tables_empty() const
6644 {
6645 return (priv_->deleted_enumerators_.empty()
6646 && priv_->inserted_enumerators_.empty()
6647 && priv_->changed_enumerators_.empty());
6648 }
6649
6650 /// If the lookup tables are not yet built, walk the differences and
6651 /// fill the lookup tables.
6652 void
6653 enum_diff::ensure_lookup_tables_populated()
6654 {
6655 if (!lookup_tables_empty())
6656 return;
6657
6658 {
6659 edit_script e = priv_->enumerators_changes_;
6660
6661 for (vector<deletion>::const_iterator it = e.deletions().begin();
6662 it != e.deletions().end();
6663 ++it)
6664 {
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;
6672 }
6673
6674 for (vector<insertion>::const_iterator it = e.insertions().begin();
6675 it != e.insertions().end();
6676 ++it)
6677 {
6678 for (vector<unsigned>::const_iterator iit =
6679 it->inserted_indexes().begin();
6680 iit != it->inserted_indexes().end();
6681 ++iit)
6682 {
6683 unsigned i = *iit;
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;
6693 else
6694 {
6695 if (j->second != n)
6696 priv_->changed_enumerators_[j->first] =
6697 std::make_pair(j->second, n);
6698 priv_->deleted_enumerators_.erase(j);
6699 }
6700 }
6701 }
6702 }
6703 }
6704
6705 /// Populate the vector of children node of the @ref diff base type
6706 /// sub-object of this instance of @ref enum_diff.
6707 ///
6708 /// The children node can then later be retrieved using
6709 /// diff::children_node().
6710 void
6711 enum_diff::chain_into_hierarchy()
6712 {append_child_node(underlying_type_diff());}
6713
6714 /// Constructor for enum_diff.
6715 ///
6716 /// @param first the first enum type of the diff.
6717 ///
6718 /// @param second the second enum type of the diff.
6719 ///
6720 /// @param underlying_type_diff the diff of the two underlying types
6721 /// of the two enum types.
6722 ///
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))
6730 {}
6731
6732 /// Finish building the current instance of @ref enum_diff.
6733 void
6734 enum_diff::finish_diff_type()
6735 {
6736 if (diff::priv_->finished_)
6737 return;
6738 chain_into_hierarchy();
6739 diff::priv_->finished_ = true;
6740 }
6741
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());}
6746
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());}
6751
6752 /// @return the diff of the two underlying enum types.
6753 diff_sptr
6754 enum_diff::underlying_type_diff() const
6755 {return priv_->underlying_type_diff_;}
6756
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_;}
6761
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_;}
6766
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_;}
6771
6772 /// @return the pretty representation of the current instance of @ref
6773 /// enum_diff.
6774 const string&
6775 enum_diff::get_pretty_representation() const
6776 {
6777 if (diff::priv_->pretty_representation_.empty())
6778 {
6779 std::ostringstream o;
6780 o << "enum_diff["
6781 << first_subject()->get_pretty_representation()
6782 << ", "
6783 << second_subject()->get_pretty_representation()
6784 << "]";
6785 diff::priv_->pretty_representation_ = o.str();
6786 }
6787 return diff::priv_->pretty_representation_;
6788 }
6789
6790 /// Return true iff the current diff node carries a change.
6791 ///
6792 /// @return true iff the current diff node carries a change.
6793 bool
6794 enum_diff::has_changes() const
6795 {return first_enum() != second_enum();}
6796
6797 /// @return true iff the current diff node carries local changes.
6798 bool
6799 enum_diff::has_local_changes() const
6800 {
6801 ir::change_kind k = ir::NO_CHANGE_KIND;
6802 if (!equals(*first_enum(), *second_enum(), &k))
6803 return k & LOCAL_CHANGE_KIND;
6804 return false;
6805 }
6806
6807 /// A functor to compare two enumerators based on their value. This
6808 /// implements the "less than" operator.
6809 struct enumerator_value_comp
6810 {
6811 bool
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
6816
6817 /// Sort a map of enumerators by their value.
6818 ///
6819 /// @param enumerators_map the map to sort.
6820 ///
6821 /// @param sorted the resulting vector of sorted enumerators.
6822 static void
6823 sort_enumerators(const string_enumerator_map& enumerators_map,
6824 enum_type_decl::enumerators& sorted)
6825 {
6826 for (string_enumerator_map::const_iterator i = enumerators_map.begin();
6827 i != enumerators_map.end();
6828 ++i)
6829 sorted.push_back(i->second);
6830 enumerator_value_comp comp;
6831 std::sort(sorted.begin(), sorted.end(), comp);
6832 }
6833
6834 /// A functor to compare two changed enumerators, based on their
6835 /// initial value.
6836 struct changed_enumerator_comp
6837 {
6838 bool
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.
6843
6844 /// Sort a map of changed enumerators.
6845 ///
6846 /// @param enumerators_map the map to sort.
6847 ///
6848 ///@param output parameter. The resulting sorted enumerators.
6849 void
6850 sort_changed_enumerators(const string_changed_enumerator_map& enumerators_map,
6851 changed_enumerators_type& sorted)
6852 {
6853 for (string_changed_enumerator_map::const_iterator i =
6854 enumerators_map.begin();
6855 i != enumerators_map.end();
6856 ++i)
6857 sorted.push_back(i->second);
6858
6859 changed_enumerator_comp comp;
6860 std::sort(sorted.begin(), sorted.end(), comp);
6861 }
6862
6863 /// Report the differences between the two enums.
6864 ///
6865 /// @param out the output stream to send the report to.
6866 ///
6867 /// @param indent the string to use for indentation.
6868 void
6869 enum_diff::report(ostream& out, const string& indent) const
6870 {
6871 if (!to_be_reported())
6872 return;
6873
6874 string name = first_enum()->get_pretty_representation();
6875
6876 enum_type_decl_sptr first = first_enum(), second = second_enum();
6877
6878 if (report_name_size_and_alignment_changes(first, second, context(),
6879 out, indent,
6880 /*start_with_num_line=*/false))
6881 out << "\n";
6882 maybe_report_diff_for_member(first, second, context(), out, indent);
6883
6884 //underlying type
6885 underlying_type_diff()->report(out, indent);
6886
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();
6891
6892 if (numdels)
6893 {
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();
6900 ++i)
6901 {
6902 if (i != sorted_deleted_enumerators.begin())
6903 out << "\n";
6904 out << indent
6905 << " '"
6906 << i->get_qualified_name()
6907 << "' value '"
6908 << i->get_value()
6909 << "'";
6910 }
6911 out << "\n\n";
6912 }
6913 if (numins)
6914 {
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();
6921 ++i)
6922 {
6923 if (i != sorted_inserted_enumerators.begin())
6924 out << "\n";
6925 out << indent
6926 << " '"
6927 << i->get_qualified_name()
6928 << "' value '"
6929 << i->get_value()
6930 << "'";
6931 }
6932 out << "\n\n";
6933 }
6934 if (numchanges)
6935 {
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();
6943 ++i)
6944 {
6945 if (i != sorted_changed_enumerators.begin())
6946 out << "\n";
6947 out << indent
6948 << " '"
6949 << i->first.get_qualified_name()
6950 << "' from value '"
6951 << i->first.get_value() << "' to '"
6952 << i->second.get_value() << "'";
6953 }
6954 out << "\n\n";
6955 }
6956 }
6957
6958 /// Compute the set of changes between two instances of @ref
6959 /// enum_type_decl.
6960 ///
6961 /// @param first a pointer to the first enum_type_decl to consider.
6962 ///
6963 /// @param second a pointer to the second enum_type_decl to consider.
6964 ///
6965 /// @return the resulting diff of the two enums @p first and @p
6966 /// second.
6967 ///
6968 /// @param ctxt the diff context to use.
6969 enum_diff_sptr
6970 compute_diff(const enum_type_decl_sptr first,
6971 const enum_type_decl_sptr second,
6972 diff_context_sptr ctxt)
6973 {
6974 diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
6975 second->get_underlying_type(),
6976 ctxt);
6977 enum_diff_sptr d(new enum_diff(first, second, ud, ctxt));
6978
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_);
6984
6985 d->ensure_lookup_tables_populated();
6986
6987 ctxt->initialize_canonical_diff(d);
6988
6989 return d;
6990 }
6991 // </enum_diff stuff>
6992
6993 //<class_diff stuff>
6994
6995 struct class_diff::priv
6996 {
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_;
7003
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_;
7034
7035 class_decl::base_spec_sptr
7036 base_has_changed(class_decl::base_spec_sptr) const;
7037
7038 type_or_decl_base_sptr
7039 member_type_has_changed(decl_base_sptr) const;
7040
7041 decl_base_sptr
7042 subtype_changed_dm(decl_base_sptr) const;
7043
7044 decl_base_sptr
7045 member_class_tmpl_has_changed(decl_base_sptr) const;
7046
7047 size_t
7048 get_deleted_non_static_data_members_number() const;
7049
7050 size_t
7051 get_inserted_non_static_data_members_number() const;
7052
7053 size_t
7054 count_filtered_bases();
7055
7056 size_t
7057 count_filtered_subtype_changed_dm();
7058
7059 size_t
7060 count_filtered_changed_dm();
7061
7062 size_t
7063 count_filtered_changed_mem_fns(const diff_context_sptr&);
7064
7065 size_t
7066 count_filtered_inserted_mem_fns(const diff_context_sptr&);
7067
7068 size_t
7069 count_filtered_deleted_mem_fns(const diff_context_sptr&);
7070
7071 priv()
7072 {}
7073 };//end struct class_diff::priv
7074
7075 /// Clear the lookup tables useful for reporting.
7076 ///
7077 /// This function must be updated each time a lookup table is added or
7078 /// removed from the class_diff::priv.
7079 void
7080 class_diff::clear_lookup_tables(void)
7081 {
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();
7097 }
7098
7099 /// Tests if the lookup tables are empty.
7100 ///
7101 /// @return true if the lookup tables are empty, false otherwise.
7102 bool
7103 class_diff::lookup_tables_empty(void) const
7104 {
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());
7120 }
7121
7122 /// If the lookup tables are not yet built, walk the differences and
7123 /// fill the lookup tables.
7124 void
7125 class_diff::ensure_lookup_tables_populated(void) const
7126 {
7127 if (!lookup_tables_empty())
7128 return;
7129
7130 {
7131 edit_script& e = priv_->base_changes_;
7132
7133 for (vector<deletion>::const_iterator it = e.deletions().begin();
7134 it != e.deletions().end();
7135 ++it)
7136 {
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;
7144 }
7145
7146 for (vector<insertion>::const_iterator it = e.insertions().begin();
7147 it != e.insertions().end();
7148 ++it)
7149 {
7150 for (vector<unsigned>::const_iterator iit =
7151 it->inserted_indexes().begin();
7152 iit != it->inserted_indexes().end();
7153 ++iit)
7154 {
7155 unsigned i = *iit;
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())
7164 {
7165 if (j->second != b)
7166 priv_->changed_bases_[qname] =
7167 compute_diff(j->second, b, context());
7168 priv_->deleted_bases_.erase(j);
7169 }
7170 else
7171 priv_->inserted_bases_[qname] = b;
7172 }
7173 }
7174 }
7175
7176 sort_string_base_diff_sptr_map(priv_->changed_bases_,
7177 priv_->sorted_changed_bases_);
7178
7179 {
7180 edit_script& e = priv_->member_types_changes_;
7181
7182 for (vector<deletion>::const_iterator it = e.deletions().begin();
7183 it != e.deletions().end();
7184 ++it)
7185 {
7186 unsigned i = it->index();
7187 decl_base_sptr d =
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())
7191 continue;
7192 string qname = d->get_qualified_name();
7193 priv_->deleted_member_types_[qname] = d;
7194 }
7195
7196 for (vector<insertion>::const_iterator it = e.insertions().begin();
7197 it != e.insertions().end();
7198 ++it)
7199 {
7200 for (vector<unsigned>::const_iterator iit =
7201 it->inserted_indexes().begin();
7202 iit != it->inserted_indexes().end();
7203 ++iit)
7204 {
7205 unsigned i = *iit;
7206 decl_base_sptr d =
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())
7210 continue;
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())
7215 {
7216 if (*j->second != *d)
7217 priv_->changed_member_types_[qname] =
7218 compute_diff(j->second, d, context());
7219
7220 priv_->deleted_member_types_.erase(j);
7221 }
7222 else
7223 priv_->inserted_member_types_[qname] = d;
7224 }
7225 }
7226 }
7227
7228 {
7229 edit_script& e = priv_->data_members_changes_;
7230
7231 for (vector<deletion>::const_iterator it = e.deletions().begin();
7232 it != e.deletions().end();
7233 ++it)
7234 {
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;
7241 }
7242
7243 for (vector<insertion>::const_iterator it = e.insertions().begin();
7244 it != e.insertions().end();
7245 ++it)
7246 {
7247 for (vector<unsigned>::const_iterator iit =
7248 it->inserted_indexes().begin();
7249 iit != it->inserted_indexes().end();
7250 ++iit)
7251 {
7252 unsigned i = *iit;
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())
7261 {
7262 if (*j->second != *d)
7263 {
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());
7268 }
7269 priv_->deleted_data_members_.erase(j);
7270 }
7271 else
7272 priv_->inserted_data_members_[qname] = d;
7273 }
7274 }
7275
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();
7282 ++i)
7283 {
7284 unsigned offset = get_data_member_offset(i->second);
7285 priv_->deleted_dm_by_offset_[offset] = i->second;
7286 }
7287
7288 for (string_decl_base_sptr_map::const_iterator i =
7289 priv_->inserted_data_members_.begin();
7290 i != priv_->inserted_data_members_.end();
7291 ++i)
7292 {
7293 unsigned offset = get_data_member_offset(i->second);
7294 priv_->inserted_dm_by_offset_[offset] = i->second;
7295 }
7296
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();
7300 ++i)
7301 {
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())
7305 {
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());
7310 }
7311 }
7312
7313 for (unsigned_var_diff_sptr_map::const_iterator i =
7314 priv_->changed_dm_.begin();
7315 i != priv_->changed_dm_.end();
7316 ++i)
7317 {
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());
7324 }
7325 }
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_);
7330
7331
7332 {
7333 edit_script& e = priv_->member_fns_changes_;
7334
7335 for (vector<deletion>::const_iterator it = e.deletions().begin();
7336 it != e.deletions().end();
7337 ++it)
7338 {
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();
7343 if (name.empty())
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())
7348 continue;
7349 priv_->deleted_member_functions_[name] = mem_fn;
7350 }
7351
7352 for (vector<insertion>::const_iterator it = e.insertions().begin();
7353 it != e.insertions().end();
7354 ++it)
7355 {
7356 for (vector<unsigned>::const_iterator iit =
7357 it->inserted_indexes().begin();
7358 iit != it->inserted_indexes().end();
7359 ++iit)
7360 {
7361 unsigned i = *iit;
7362
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();
7366 if (name.empty())
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())
7371 continue;
7372 string_member_function_sptr_map::const_iterator j =
7373 priv_->deleted_member_functions_.find(name);
7374
7375 if (j != priv_->deleted_member_functions_.end())
7376 {
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),
7381 context());
7382 priv_->deleted_member_functions_.erase(j);
7383 }
7384 else
7385 priv_->inserted_member_functions_[name] = mem_fn;
7386 }
7387 }
7388
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.
7392
7393 vector<string> to_delete;
7394 corpus_sptr f = context()->get_first_corpus(),
7395 s = context()->get_second_corpus();;
7396 if (s)
7397 for (string_member_function_sptr_map::const_iterator i =
7398 deleted_member_fns().begin();
7399 i != deleted_member_fns().end();
7400 ++i)
7401 // We assume that all the functions we look at here have ELF
7402 // symbols.
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);
7408
7409
7410 for (vector<string>::const_iterator i = to_delete.begin();
7411 i != to_delete.end();
7412 ++i)
7413 priv_->deleted_member_functions_.erase(*i);
7414
7415 // Do something similar for added functions.
7416 to_delete.clear();
7417 if (f)
7418 for (string_member_function_sptr_map::const_iterator i =
7419 inserted_member_fns().begin();
7420 i != inserted_member_fns().end();
7421 ++i)
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);
7426
7427 for (vector<string>::const_iterator i = to_delete.begin();
7428 i != to_delete.end();
7429 ++i)
7430 priv_->inserted_member_functions_.erase(*i);
7431 }
7432
7433 sort_string_virtual_member_function_diff_sptr_map
7434 (priv_->changed_member_functions_,
7435 priv_->sorted_changed_member_functions_);
7436
7437 {
7438 edit_script& e = priv_->member_class_tmpls_changes_;
7439
7440 for (vector<deletion>::const_iterator it = e.deletions().begin();
7441 it != e.deletions().end();
7442 ++it)
7443 {
7444 unsigned i = it->index();
7445 decl_base_sptr d =
7446 first_class_decl()->get_member_class_templates()[i]->
7447 as_class_tdecl();
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;
7452 }
7453
7454 for (vector<insertion>::const_iterator it = e.insertions().begin();
7455 it != e.insertions().end();
7456 ++it)
7457 {
7458 for (vector<unsigned>::const_iterator iit =
7459 it->inserted_indexes().begin();
7460 iit != it->inserted_indexes().end();
7461 ++iit)
7462 {
7463 unsigned i = *iit;
7464 decl_base_sptr d =
7465 second_class_decl()->get_member_class_templates()[i]->
7466 as_class_tdecl();
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())
7473 {
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);
7478 }
7479 else
7480 priv_->inserted_member_class_tmpls_[qname] = d;
7481 }
7482 }
7483 }
7484 sort_string_diff_sptr_map(priv_->changed_member_types_,
7485 priv_->sorted_changed_member_types_);
7486 }
7487
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.
7490 ///
7491 ///@param d the declaration for the base class to consider.
7492 ///
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
7497 {
7498 string qname = d->get_base_class()->get_qualified_name();
7499 string_base_diff_sptr_map::const_iterator it =
7500 changed_bases_.find(qname);
7501
7502 return (it == changed_bases_.end())
7503 ? class_decl::base_spec_sptr()
7504 : it->second->second_base();
7505
7506 }
7507
7508 /// Test whether a given member type has changed.
7509 ///
7510 /// @param d the declaration for the member type to consider.
7511 ///
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
7516 {
7517 string qname = d->get_qualified_name();
7518 string_diff_sptr_map::const_iterator it =
7519 changed_member_types_.find(qname);
7520
7521 return ((it == changed_member_types_.end())
7522 ? type_or_decl_base_sptr()
7523 : it->second->second_subject());
7524 }
7525
7526 /// Test whether a given data member has changed.
7527 ///
7528 /// @param d the declaration for the data member to consider.
7529 ///
7530 /// @return the new data member if the given data member has changed,
7531 /// or NULL if if hasn't.
7532 decl_base_sptr
7533 class_diff::priv::subtype_changed_dm(decl_base_sptr d) const
7534 {
7535 string qname = d->get_qualified_name();
7536 string_var_diff_sptr_map::const_iterator it =
7537 subtype_changed_dm_.find(qname);
7538
7539 if (it == subtype_changed_dm_.end())
7540 return decl_base_sptr();
7541 return it->second->second_var();
7542 }
7543
7544 /// Test whether a given member class template has changed.
7545 ///
7546 /// @param d the declaration for the given member class template to consider.
7547 ///
7548 /// @return the new member class template if the given one has
7549 /// changed, or NULL if it hasn't.
7550 decl_base_sptr
7551 class_diff::priv::member_class_tmpl_has_changed(decl_base_sptr d) const
7552 {
7553 string qname = d->get_qualified_name();
7554 string_diff_sptr_map::const_iterator it =
7555 changed_member_class_tmpls_.find(qname);
7556
7557 return ((it == changed_member_class_tmpls_.end())
7558 ? decl_base_sptr()
7559 : dynamic_pointer_cast<decl_base>(it->second->second_subject()));
7560 }
7561
7562 /// Get the number of non-static data member that were deleted from
7563 /// the class which diff we are looking at.
7564 ///
7565 /// @return the number of deleted non-static data members.
7566 size_t
7567 class_diff::priv::get_deleted_non_static_data_members_number() const
7568 {
7569 size_t result = 0;
7570
7571 for (string_decl_base_sptr_map::const_iterator i =
7572 deleted_data_members_.begin();
7573 i != deleted_data_members_.end();
7574 ++i)
7575 if (is_member_decl(i->second)
7576 && !get_member_is_static(i->second))
7577 ++result;
7578
7579 return result;
7580 }
7581
7582 /// Get the number of non-static data member that were inserted to the
7583 /// class which diff we are looking at.
7584 ///
7585 /// @return the number of inserted non-static data members.
7586 size_t
7587 class_diff::priv::get_inserted_non_static_data_members_number() const
7588 {
7589 size_t result = 0;
7590
7591 for (string_decl_base_sptr_map::const_iterator i =
7592 inserted_data_members_.begin();
7593 i != inserted_data_members_.end();
7594 ++i)
7595 if (is_member_decl(i->second)
7596 && !get_member_is_static(i->second))
7597 ++result;
7598
7599 return result;
7600 }
7601
7602 /// Count the number of bases classes whose changes got filtered out.
7603 ///
7604 /// @return the number of bases classes whose changes got filtered
7605 /// out.
7606 size_t
7607 class_diff::priv::count_filtered_bases()
7608 {
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();
7612 ++i)
7613 {
7614 diff_sptr diff = *i;
7615 if (diff && diff->is_filtered_out())
7616 ++num_filtered;
7617 }
7618 return num_filtered;
7619 }
7620
7621 /// Count the number of data members whose changes got filtered out.
7622 ///
7623 /// @param ctxt the diff context to use to get the filtering settings
7624 /// from the user.
7625 ///
7626 /// @return the number of data members whose changes got filtered out.
7627 size_t
7628 class_diff::priv::count_filtered_subtype_changed_dm()
7629 {
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();
7634 ++i)
7635 {
7636 if ((*i)->is_filtered_out())
7637 ++num_filtered;
7638 }
7639 return num_filtered;
7640 }
7641
7642 /// Count the number of data member offsets that have changed.
7643 ///
7644 /// @return the number of filtered changed data members.
7645 size_t
7646 class_diff::priv::count_filtered_changed_dm()
7647 {
7648 size_t num_filtered= 0;
7649
7650 for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
7651 i != changed_dm_.end();
7652 ++i)
7653 {
7654 diff_sptr diff = i->second;
7655 if (diff->is_filtered_out())
7656 ++num_filtered;
7657 }
7658 return num_filtered;
7659
7660 }
7661
7662 /// Skip the processing of the current member function if its
7663 /// virtual-ness is disallowed by the user.
7664 ///
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
7667 /// functions.
7668 #define SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED \
7669 do { \
7670 if (get_member_function_is_virtual(f) \
7671 || get_member_function_is_virtual(s)) \
7672 { \
7673 if (!(allowed_category | VIRTUAL_MEMBER_CHANGE_CATEGORY)) \
7674 continue; \
7675 } \
7676 else \
7677 { \
7678 if (!(allowed_category | NON_VIRT_MEM_FUN_CHANGE_CATEGORY)) \
7679 continue; \
7680 } \
7681 } while (false)
7682
7683 /// Count the number of member functions whose changes got filtered
7684 /// out.
7685 ///
7686 /// @param ctxt the diff context to use to get the filtering settings
7687 /// from the user.
7688 ///
7689 /// @return the number of member functions whose changes got filtered
7690 /// out.
7691 size_t
7692 class_diff::priv::count_filtered_changed_mem_fns(const diff_context_sptr& ctxt)
7693 {
7694 size_t count = 0;
7695 diff_category allowed_category = ctxt->get_allowed_category();
7696
7697 for (function_decl_diff_sptrs_type::const_iterator i =
7698 sorted_changed_member_functions_.begin();
7699 i != sorted_changed_member_functions_.end();
7700 ++i)
7701 {
7702 class_decl::method_decl_sptr f =
7703 dynamic_pointer_cast<class_decl::method_decl>
7704 ((*i)->first_function_decl());
7705 assert(f);
7706
7707 class_decl::method_decl_sptr s =
7708 dynamic_pointer_cast<class_decl::method_decl>
7709 ((*i)->second_function_decl());
7710 assert(s);
7711
7712 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
7713
7714 diff_sptr diff = *i;
7715 ctxt->maybe_apply_filters(diff);
7716
7717 if (diff->is_filtered_out())
7718 ++count;
7719 }
7720
7721 return count;
7722 }
7723
7724 /// Count the number of inserted member functions whose got filtered
7725 /// out.
7726 ///
7727 /// @param ctxt the diff context to use to get the filtering settings
7728 /// from the user.
7729 ///
7730 /// @return the number of inserted member functions whose got filtered
7731 /// out.
7732 size_t
7733 class_diff::priv::count_filtered_inserted_mem_fns(const diff_context_sptr& ctxt)
7734 {
7735 size_t count = 0;
7736 diff_category allowed_category = ctxt->get_allowed_category();
7737
7738 for (string_member_function_sptr_map::const_iterator i =
7739 inserted_member_functions_.begin();
7740 i != inserted_member_functions_.end();
7741 ++i)
7742 {
7743 class_decl::method_decl_sptr f = i->second,
7744 s = i->second;
7745
7746 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
7747
7748 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
7749 ctxt->maybe_apply_filters(diff);
7750
7751 if (diff->get_category() != NO_CHANGE_CATEGORY
7752 && diff->is_filtered_out())
7753 ++count;
7754 }
7755
7756 return count;
7757 }
7758
7759 /// Count the number of deleted member functions whose got filtered
7760 /// out.
7761 ///
7762 /// @param ctxt the diff context to use to get the filtering settings
7763 /// from the user.
7764 ///
7765 /// @return the number of deleted member functions whose got filtered
7766 /// out.
7767 size_t
7768 class_diff::priv::count_filtered_deleted_mem_fns(const diff_context_sptr& ctxt)
7769 {
7770 size_t count = 0;
7771 diff_category allowed_category = ctxt->get_allowed_category();
7772
7773 for (string_member_function_sptr_map::const_iterator i =
7774 deleted_member_functions_.begin();
7775 i != deleted_member_functions_.end();
7776 ++i)
7777 {
7778 class_decl::method_decl_sptr f = i->second,
7779 s = i->second;
7780
7781 SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
7782
7783 diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
7784 ctxt->maybe_apply_filters(diff);
7785
7786 if (diff->get_category() != NO_CHANGE_CATEGORY
7787 && diff->is_filtered_out())
7788 ++count;
7789 }
7790
7791 return count;
7792 }
7793
7794 /// Populate the vector of children node of the @ref diff base type
7795 /// sub-object of this instance of @ref class_diff.
7796 ///
7797 /// The children node can then later be retrieved using
7798 /// diff::children_node().
7799 void
7800 class_diff::chain_into_hierarchy()
7801 {
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();
7806 ++i)
7807 if (diff_sptr d = *i)
7808 append_child_node(d);
7809
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();
7814 ++i)
7815 if (diff_sptr d = *i)
7816 append_child_node(d);
7817
7818 for (unsigned_var_diff_sptr_map::const_iterator i =
7819 priv_->changed_dm_.begin();
7820 i != priv_->changed_dm_.end();
7821 ++i)
7822 if (diff_sptr d = i->second)
7823 append_child_node(d);
7824
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();
7829 ++i)
7830 if (diff_sptr d = *i)
7831 append_child_node(d);
7832
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();
7837 ++i)
7838 if (diff_sptr d = *i)
7839 append_child_node(d);
7840 }
7841
7842 /// Constructor of class_diff
7843 ///
7844 /// @param first_scope the first class of the diff.
7845 ///
7846 /// @param second_scope the second class of the diff.
7847 ///
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.
7859 {}
7860
7861 class_diff::~class_diff()
7862 {}
7863
7864 /// Finish building the current instance of @ref class_diff.
7865 void
7866 class_diff::finish_diff_type()
7867 {
7868 if (diff::priv_->finished_)
7869 return;
7870 chain_into_hierarchy();
7871 diff::priv_->finished_ = true;
7872 }
7873
7874 /// @return the pretty representation of the current instance of @ref
7875 /// class_diff.
7876 const string&
7877 class_diff::get_pretty_representation() const
7878 {
7879 if (diff::priv_->pretty_representation_.empty())
7880 {
7881 std::ostringstream o;
7882 o << "class_diff["
7883 << first_subject()->get_pretty_representation()
7884 << ", "
7885 << second_subject()->get_pretty_representation()
7886 << "]";
7887 diff::priv_->pretty_representation_ = o.str();
7888 }
7889 return diff::priv_->pretty_representation_;
7890 }
7891
7892 /// Return true iff the current diff node carries a change.
7893 ///
7894 /// @return true iff the current diff node carries a change.
7895 bool
7896 class_diff::has_changes() const
7897 {return (first_class_decl() != second_class_decl());}
7898
7899 /// @return true iff the current diff node carries local changes.
7900 bool
7901 class_diff::has_local_changes() const
7902 {
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;
7906 return false;
7907 }
7908
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());}
7913
7914 /// Getter of the second class involved in the diff.
7915 ///
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());}
7920
7921 /// @return the edit script of the bases of the two classes.
7922 const edit_script&
7923 class_diff::base_changes() const
7924 {return priv_->base_changes_;}
7925
7926 /// Getter for the deleted base classes of the diff.
7927 ///
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_;}
7933
7934 /// Getter for the inserted base classes of the diff.
7935 ///
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_;}
7941
7942 /// Getter for the changed base classes of the diff.
7943 ///
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_;}
7948
7949 /// @return the edit script of the bases of the two classes.
7950 edit_script&
7951 class_diff::base_changes()
7952 {return priv_->base_changes_;}
7953
7954 /// @return the edit script of the member types of the two classes.
7955 const edit_script&
7956 class_diff::member_types_changes() const
7957 {return priv_->member_types_changes_;}
7958
7959 /// @return the edit script of the member types of the two classes.
7960 edit_script&
7961 class_diff::member_types_changes()
7962 {return priv_->member_types_changes_;}
7963
7964 /// @return the edit script of the data members of the two classes.
7965 const edit_script&
7966 class_diff::data_members_changes() const
7967 {return priv_->data_members_changes_;}
7968
7969 /// @return the edit script of the data members of the two classes.
7970 edit_script&
7971 class_diff::data_members_changes()
7972 {return priv_->data_members_changes_;}
7973
7974 /// Getter for the data members that got inserted.
7975 ///
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_;}
7980
7981 /// Getter for the data members that got deleted.
7982 ///
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_;}
7987
7988 /// @return the edit script of the member functions of the two
7989 /// classes.
7990 const edit_script&
7991 class_diff::member_fns_changes() const
7992 {return priv_->member_fns_changes_;}
7993
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.
7996 ///
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_;}
8002
8003 /// @return the edit script of the member functions of the two
8004 /// classes.
8005 edit_script&
8006 class_diff::member_fns_changes()
8007 {return priv_->member_fns_changes_;}
8008
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_;}
8013
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_;}
8018
8019 ///@return the edit script of the member function templates of the two
8020 ///classes.
8021 const edit_script&
8022 class_diff::member_fn_tmpls_changes() const
8023 {return priv_->member_fn_tmpls_changes_;}
8024
8025 /// @return the edit script of the member function templates of the
8026 /// two classes.
8027 edit_script&
8028 class_diff::member_fn_tmpls_changes()
8029 {return priv_->member_fn_tmpls_changes_;}
8030
8031 /// @return the edit script of the member class templates of the two
8032 /// classes.
8033 const edit_script&
8034 class_diff::member_class_tmpls_changes() const
8035 {return priv_->member_class_tmpls_changes_;}
8036
8037 /// @return the edit script of the member class templates of the two
8038 /// classes.
8039 edit_script&
8040 class_diff::member_class_tmpls_changes()
8041 {return priv_->member_class_tmpls_changes_;}
8042
8043 /// A comparison function for instances of @ref base_diff.
8044 struct base_diff_comp
8045 {
8046 bool
8047 operator()(const base_diff& l, const base_diff& r) const
8048 {
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();
8053 else
8054 return (f->get_base_class()->get_pretty_representation()
8055 < s->get_base_class()->get_pretty_representation());
8056 }
8057
8058 bool
8059 operator()(const base_diff* l, const base_diff* r) const
8060 {return operator()(*l, *r);}
8061
8062 bool
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
8066
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.
8070 ///
8071 /// @param map the input map to sort.
8072 ///
8073 /// @param sorted the resulting sorted vector.
8074 static void
8075 sort_string_base_diff_sptr_map(const string_base_diff_sptr_map& map,
8076 base_diff_sptrs_type& sorted)
8077 {
8078 for (string_base_diff_sptr_map::const_iterator i = map.begin();
8079 i != map.end();
8080 ++i)
8081 sorted.push_back(i->second);
8082 base_diff_comp comp;
8083 sort(sorted.begin(), sorted.end(), comp);
8084 }
8085
8086 /// A comparison functor to compare two instances of @ref var_diff
8087 /// that represent changed data members based on the offset of their
8088 /// initial value.
8089 struct data_member_diff_comp
8090 {
8091 /// @param f the first change to data member to take into account
8092 ///
8093 /// @param s the second change to data member to take into account.
8094 ///
8095 /// @return true iff f is before s.
8096 bool
8097 operator()(const var_diff_sptr f,
8098 const var_diff_sptr s) const
8099 {
8100 var_decl_sptr first_dm = f->first_var();
8101 var_decl_sptr second_dm = s->first_var();
8102
8103 assert(is_data_member(first_dm));
8104 assert(is_data_member(second_dm));
8105
8106 return get_data_member_offset(first_dm) < get_data_member_offset(second_dm);
8107 }
8108 }; // end struct var_diff_comp
8109
8110 /// Sort the values of a unsigned_var_diff_sptr_map map and store the
8111 /// result into a vector of var_diff_sptr.
8112 ///
8113 /// @param map the map of changed data members to sort.
8114 ///
8115 /// @param sorted the resulting vector of sorted var_diff_sptr.
8116 static void
8117 sort_unsigned_data_member_diff_sptr_map(const unsigned_var_diff_sptr_map map,
8118 var_diff_sptrs_type& sorted)
8119 {
8120 sorted.reserve(map.size());
8121 for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
8122 i != map.end();
8123 ++i)
8124 sorted.push_back(i->second);
8125 data_member_diff_comp comp;
8126 std::sort(sorted.begin(), sorted.end(), comp);
8127 }
8128
8129 /// Sort the values of a string_var_diff_sptr_map and store the result
8130 /// in a vector of var_diff_sptr.
8131 ///
8132 /// @param map the map of changed data members to sort.
8133 ///
8134 /// @param sorted the resulting vector of var_diff_sptr.
8135 static void
8136 sort_string_data_member_diff_sptr_map(const string_var_diff_sptr_map& map,
8137 var_diff_sptrs_type& sorted)
8138 {
8139 sorted.reserve(map.size());
8140 for (string_var_diff_sptr_map::const_iterator i = map.begin();
8141 i != map.end();
8142 ++i)
8143 sorted.push_back(i->second);
8144 data_member_diff_comp comp;
8145 std::sort(sorted.begin(), sorted.end(), comp);
8146 }
8147
8148 /// A comparison functor to compare two data members based on their
8149 /// offset.
8150 struct data_member_comp
8151 {
8152 /// @param f the first data member to take into account.
8153 ///
8154 /// @param s the second data member to take into account.
8155 ///
8156 /// @return true iff f is before s.
8157 bool
8158 operator()(const decl_base_sptr& f,
8159 const decl_base_sptr& s) const
8160 {
8161 var_decl_sptr first_dm = is_data_member(f);
8162 var_decl_sptr second_dm = is_data_member(s);
8163
8164 assert(first_dm);
8165 assert(second_dm);
8166
8167 return get_data_member_offset(first_dm) < get_data_member_offset(second_dm);
8168 }
8169 };//end struct data_member_comp
8170
8171 /// Sort a map of data members by the offset of their initial value.
8172 ///
8173 /// @param data_members the map of changed data members to sort.
8174 ///
8175 /// @param sorted the resulting vector of sorted changed data members.
8176 static void
8177 sort_data_members(const string_decl_base_sptr_map &data_members,
8178 vector<decl_base_sptr>& sorted)
8179 {
8180 sorted.reserve(data_members.size());
8181 for (string_decl_base_sptr_map::const_iterator i = data_members.begin();
8182 i != data_members.end();
8183 ++i)
8184 sorted.push_back(i->second);
8185
8186 data_member_comp comp;
8187 std::sort(sorted.begin(), sorted.end(), comp);
8188 }
8189
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
8193 {
8194 bool
8195 operator()(const function_decl_diff& l,
8196 const function_decl_diff& r) const
8197 {
8198 assert(get_member_function_is_virtual(l.first_function_decl()));
8199 assert(get_member_function_is_virtual(r.first_function_decl()));
8200
8201 return (get_member_function_vtable_offset(l.first_function_decl())
8202 < get_member_function_vtable_offset(r.first_function_decl()));
8203 }
8204
8205 bool
8206 operator()(const function_decl_diff* l,
8207 const function_decl_diff* r)
8208 {return operator()(*l, *r);}
8209
8210 bool
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
8215
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.
8219 ///
8220 /// @param map the input map.
8221 ///
8222 /// @param sorted the resulting sorted vector of virtual function
8223 /// member.
8224 static void
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)
8228 {
8229 sorted.reserve(map.size());
8230 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
8231 i != map.end();
8232 ++i)
8233 sorted.push_back(i->second);
8234
8235 virtual_member_function_diff_comp comp;
8236 sort(sorted.begin(), sorted.end(), comp);
8237 }
8238
8239 /// Produce a basic report about the changes between two class_decl.
8240 ///
8241 /// @param out the output stream to report the changes to.
8242 ///
8243 /// @param indent the string to use as an indentation prefix in the
8244 /// report.
8245 void
8246 class_diff::report(ostream& out, const string& indent) const
8247 {
8248 if (!to_be_reported())
8249 return;
8250
8251 string name = first_subject()->get_pretty_representation();
8252
8253 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(first_subject(),
8254 second_subject());
8255
8256 currently_reporting(true);
8257
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();
8261
8262 if (report_name_size_and_alignment_changes(first, second, context(),
8263 out, indent,
8264 /*start_with_new_line=*/false))
8265 out << "\n";
8266
8267 maybe_report_diff_for_member(first, second, context(), out, indent);
8268
8269 // bases classes
8270 if (base_changes())
8271 {
8272 // Report deletions.
8273 int numdels = priv_->deleted_bases_.size();
8274 size_t numchanges = priv_->sorted_changed_bases_.size();
8275
8276 if (numdels)
8277 {
8278 report_mem_header(out, numdels, 0, del_kind,
8279 "base class", indent);
8280
8281 for (string_base_sptr_map::const_iterator i
8282 = priv_->deleted_bases_.begin();
8283 i != priv_->deleted_bases_.end();
8284 ++i)
8285 {
8286 if (i != priv_->deleted_bases_.begin())
8287 out << "\n";
8288
8289 class_decl::base_spec_sptr base = i->second;
8290
8291 if ( priv_->base_has_changed(base))
8292 continue;
8293 out << indent << " "
8294 << base->get_base_class()->get_pretty_representation();
8295 }
8296 out << "\n";
8297 }
8298
8299 // Report changes.
8300 bool emitted = false;
8301 size_t num_filtered = priv_->count_filtered_bases();
8302 if (numchanges)
8303 {
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();
8309 ++it)
8310 {
8311 base_diff_sptr diff = *it;
8312 if (!diff || !diff->to_be_reported())
8313 continue;
8314
8315 class_decl::base_spec_sptr o = diff->first_base();
8316 out << indent << " '"
8317 << o->get_base_class()->get_pretty_representation()
8318 << "' changed:\n";
8319 diff->report(out, indent + " ");
8320 emitted = true;
8321 }
8322 if (emitted)
8323 out << "\n";
8324 }
8325
8326 //Report insertions.
8327 int numins = priv_->inserted_bases_.size();
8328 if (numins)
8329 {
8330 report_mem_header(out, numins, 0, ins_kind,
8331 "base class", indent);
8332
8333 bool emitted = false;
8334 for (string_base_sptr_map::const_iterator i =
8335 priv_->inserted_bases_.begin();
8336 i != priv_->inserted_bases_.end();
8337 ++i)
8338 {
8339 class_decl_sptr b = i->second->get_base_class();
8340 if (emitted)
8341 out << "\n";
8342 out << indent << " " << b->get_pretty_representation();
8343 emitted = true;
8344 }
8345 out << "\n";
8346 }
8347 }
8348
8349 // member functions
8350 if (member_fns_changes())
8351 {
8352 // report deletions
8353 int numdels = priv_->deleted_member_functions_.size();
8354 size_t num_filtered = priv_->count_filtered_deleted_mem_fns(context());
8355 if (numdels)
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();
8362 ++i)
8363 {
8364 if (!(context()->get_allowed_category()
8365 & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
8366 && !get_member_function_is_virtual(i->second))
8367 continue;
8368
8369 if (emitted
8370 && i != priv_->deleted_member_functions_.begin())
8371 out << "\n";
8372 class_decl::method_decl_sptr mem_fun = i->second;
8373 out << indent << " ";
8374 represent(*context(), mem_fun, out);
8375 emitted = true;
8376 }
8377 if (emitted)
8378 out << "\n";
8379
8380 // report insertions;
8381 int numins = priv_->inserted_member_functions_.size();
8382 num_filtered = priv_->count_filtered_inserted_mem_fns(context());
8383 if (numins)
8384 report_mem_header(out, numins, num_filtered, ins_kind,
8385 "member function", indent);
8386 emitted = false;
8387 for (string_member_function_sptr_map::const_iterator i =
8388 priv_->inserted_member_functions_.begin();
8389 i != priv_->inserted_member_functions_.end();
8390 ++i)
8391 {
8392 if (!(context()->get_allowed_category()
8393 & NON_VIRT_MEM_FUN_CHANGE_CATEGORY)
8394 && !get_member_function_is_virtual(i->second))
8395 continue;
8396
8397 if (emitted
8398 && i != priv_->inserted_member_functions_.begin())
8399 out << "\n";
8400 class_decl::method_decl_sptr mem_fun = i->second;
8401 out << indent << " ";
8402 represent(*context(), mem_fun, out);
8403 emitted = true;
8404 }
8405 if (emitted)
8406 out << "\n";
8407
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());
8411 if (numchanges)
8412 report_mem_header(out, numchanges, num_filtered, change_kind,
8413 "member function", indent);
8414 emitted = false;
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();
8418 ++i)
8419 {
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())))
8426 continue;
8427
8428 diff_sptr diff = *i;
8429 if (!diff || !diff->to_be_reported())
8430 continue;
8431
8432 string repr =
8433 (*i)->first_function_decl()->get_pretty_representation();
8434 if (emitted
8435 && i != priv_->sorted_changed_member_functions_.begin())
8436 out << "\n";
8437 out << indent << " '" << repr << "' has some sub-type changes:\n";
8438 diff->report(out, indent + " ");
8439 emitted = true;
8440 }
8441 if (numchanges)
8442 out << "\n";
8443 }
8444
8445 // data members
8446 if (data_members_changes())
8447 {
8448 // report deletions
8449 int numdels = priv_->get_deleted_non_static_data_members_number();
8450 if (numdels)
8451 {
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();
8459 ++i)
8460 {
8461 var_decl_sptr data_mem =
8462 dynamic_pointer_cast<var_decl>(*i);
8463 assert(data_mem);
8464 if (get_member_is_static(data_mem))
8465 continue;
8466 if (emitted)
8467 out << "\n";
8468 out << indent << " ";
8469 represent_data_member(data_mem, out);
8470 emitted = true;
8471 }
8472 if (emitted)
8473 out << "\n";
8474 }
8475
8476 //report insertions
8477 int numins = priv_->inserted_data_members_.size();
8478 if (numins)
8479 {
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();
8486 ++i)
8487 {
8488 var_decl_sptr data_mem =
8489 dynamic_pointer_cast<var_decl>(*i);
8490 assert(data_mem);
8491 out << indent << " ";
8492 represent_data_member(data_mem, out);
8493 }
8494 }
8495
8496 // report change
8497 size_t numchanges = priv_->sorted_subtype_changed_dm_.size();
8498 size_t num_filtered = priv_->count_filtered_subtype_changed_dm();
8499 if (numchanges)
8500 {
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();
8506 ++it)
8507 represent(*it, context(), out, indent + " ");
8508 out << "\n";
8509 }
8510
8511 numchanges = priv_->sorted_changed_dm_.size();
8512 num_filtered = priv_->count_filtered_changed_dm();
8513 if (numchanges)
8514 {
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();
8520 ++it)
8521 represent(*it, context(), out, indent + " ");
8522 out << "\n";
8523 }
8524 }
8525
8526 // member types
8527 if (const edit_script& e = member_types_changes())
8528 {
8529 int numchanges = priv_->sorted_changed_member_types_.size();
8530 int numdels = priv_->deleted_member_types_.size();
8531
8532 // report deletions
8533 if (numdels)
8534 {
8535 report_mem_header(out, numdels, 0, del_kind,
8536 "member type", indent);
8537
8538 for (string_decl_base_sptr_map::const_iterator i =
8539 priv_->deleted_member_types_.begin();
8540 i != priv_->deleted_member_types_.end();
8541 ++i)
8542 {
8543 if (i != priv_->deleted_member_types_.begin())
8544 out << "\n";
8545 decl_base_sptr mem_type = i->second;
8546 out << indent << " '"
8547 << mem_type->get_pretty_representation()
8548 << "'";
8549 }
8550 out << "\n\n";
8551 }
8552 // report changes
8553 if (numchanges)
8554 {
8555 report_mem_header(out, numchanges, 0, change_kind,
8556 "member type", indent);
8557
8558 for (diff_sptrs_type::const_iterator it =
8559 priv_->sorted_changed_member_types_.begin();
8560 it != priv_->sorted_changed_member_types_.end();
8561 ++it)
8562 {
8563 if (!(*it)->to_be_reported())
8564 continue;
8565
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()
8570 << "' changed:\n";
8571 (*it)->report(out, indent + " ");
8572 }
8573 out << "\n";
8574 }
8575
8576 // report insertions
8577 int numins = e.num_insertions();
8578 assert(numchanges <= numins);
8579 numins -= numchanges;
8580
8581 if (numins)
8582 {
8583 report_mem_header(out, numins, 0, ins_kind,
8584 "member type", indent);
8585
8586 bool emitted = false;
8587 for (vector<insertion>::const_iterator i = e.insertions().begin();
8588 i != e.insertions().end();
8589 ++i)
8590 {
8591 type_base_sptr mem_type;
8592 for (vector<unsigned>::const_iterator j =
8593 i->inserted_indexes().begin();
8594 j != i->inserted_indexes().end();
8595 ++j)
8596 {
8597 if (emitted)
8598 out << "\n";
8599 mem_type = second->get_member_types()[*j];
8600 if (!priv_->
8601 member_type_has_changed(get_type_declaration(mem_type)))
8602 {
8603 out << indent << " '"
8604 << get_type_declaration(mem_type)->
8605 get_pretty_representation()
8606 << "'";
8607 emitted = true;
8608 }
8609 }
8610 }
8611 out << "\n\n";
8612 }
8613 }
8614
8615 // member function templates
8616 if (const edit_script& e = member_fn_tmpls_changes())
8617 {
8618 // report deletions
8619 int numdels = e.num_deletions();
8620 if (numdels)
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();
8625 ++i)
8626 {
8627 if (i != e.deletions().begin())
8628 out << "\n";
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()
8633 << "'";
8634 }
8635 if (numdels)
8636 out << "\n\n";
8637
8638 // report insertions
8639 int numins = e.num_insertions();
8640 if (numins)
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();
8646 ++i)
8647 {
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();
8652 ++j)
8653 {
8654 if (emitted)
8655 out << "\n";
8656 mem_fn_tmpl = second->get_member_function_templates()[*j];
8657 out << indent << " '"
8658 << mem_fn_tmpl->as_function_tdecl()->
8659 get_pretty_representation()
8660 << "'";
8661 emitted = true;
8662 }
8663 }
8664 if (numins)
8665 out << "\n\n";
8666 }
8667
8668 // member class templates.
8669 if (const edit_script& e = member_class_tmpls_changes())
8670 {
8671 // report deletions
8672 int numdels = e.num_deletions();
8673 if (numdels)
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();
8678 ++i)
8679 {
8680 if (i != e.deletions().begin())
8681 out << "\n";
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()
8686 << "'";
8687 }
8688 if (numdels)
8689 out << "\n\n";
8690
8691 // report insertions
8692 int numins = e.num_insertions();
8693 if (numins)
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();
8699 ++i)
8700 {
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();
8705 ++j)
8706 {
8707 if (emitted)
8708 out << "\n";
8709 mem_cls_tmpl = second->get_member_class_templates()[*j];
8710 out << indent << " '"
8711 << mem_cls_tmpl->as_class_tdecl()
8712 ->get_pretty_representation()
8713 << "'";
8714 emitted = true;
8715 }
8716 }
8717 if (numins)
8718 out << "\n\n";
8719 }
8720
8721 currently_reporting(false);
8722 reported_once(true);
8723 }
8724
8725 /// Compute the set of changes between two instances of class_decl.
8726 ///
8727 /// @param first the first class_decl to consider.
8728 ///
8729 /// @param second the second class_decl to consider.
8730 ///
8731 /// @return changes the resulting changes.
8732 ///
8733 /// @param ctxt the diff context to use.
8734 class_diff_sptr
8735 compute_diff(const class_decl_sptr first,
8736 const class_decl_sptr second,
8737 diff_context_sptr ctxt)
8738 {
8739 class_decl_sptr f = look_through_decl_only_class(first),
8740 s = look_through_decl_only_class(second);
8741
8742 class_diff_sptr changes(new class_diff(f, s, ctxt));
8743
8744 ctxt->initialize_canonical_diff(changes);
8745 assert(changes->get_canonical_diff());
8746
8747 if (!ctxt->get_canonical_diff_for(first, second))
8748 {
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);
8754 }
8755
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.
8760 //
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.
8766 //
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
8771 // private data.
8772 changes->priv_.reset(new class_diff::priv);
8773 else
8774 {
8775 // changes has a non-empty equivalence class so it's going to
8776 // share its private data with its canonical instance.
8777 changes->priv_ =
8778 dynamic_cast<class_diff*>(changes->get_canonical_diff())->priv_;
8779 assert(changes->priv_);
8780 return changes;
8781 }
8782
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());
8789
8790 // Do *not* compare member types because it generates lots of noise
8791 // and I doubt it's really useful.
8792 #if 0
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());
8798 #endif
8799
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());
8806
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());
8813
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());
8820
8821 // Likewise, do not compare member class templates
8822 #if 0
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());
8828 #endif
8829
8830 changes->ensure_lookup_tables_populated();
8831
8832 return changes;
8833 }
8834
8835 //</class_diff stuff>
8836
8837 // <base_diff stuff>
8838 struct base_diff::priv
8839 {
8840 class_diff_sptr underlying_class_diff_;
8841
8842 priv(class_diff_sptr underlying)
8843 : underlying_class_diff_(underlying)
8844 {}
8845 }; // end struct base_diff::priv
8846
8847 /// Populate the vector of children node of the @ref diff base type
8848 /// sub-object of this instance of @ref base_diff.
8849 ///
8850 /// The children node can then later be retrieved using
8851 /// diff::children_node().
8852 void
8853 base_diff::chain_into_hierarchy()
8854 {append_child_node(get_underlying_class_diff());}
8855
8856 /// @param first the first base spec to consider.
8857 ///
8858 /// @param second the second base spec to consider.
8859 ///
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))
8867 {}
8868
8869 /// Finish building the current instance of @ref base_diff.
8870 void
8871 base_diff::finish_diff_type()
8872 {
8873 if (diff::priv_->finished_)
8874 return;
8875
8876 chain_into_hierarchy();
8877 diff::priv_->finished_ = true;
8878 }
8879
8880 /// Getter for the first base spec of the diff object.
8881 ///
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());}
8886
8887 /// Getter for the second base spec of the diff object.
8888 ///
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());}
8893
8894 /// Getter for the diff object for the diff of the underlying base
8895 /// classes.
8896 ///
8897 /// @return the diff object for the diff of the underlying base
8898 /// classes.
8899 const class_diff_sptr
8900 base_diff::get_underlying_class_diff() const
8901 {return priv_->underlying_class_diff_;}
8902
8903 /// Setter for the diff object for the diff of the underlyng base
8904 /// classes.
8905 ///
8906 /// @param d the new diff object for the diff of the underlying base
8907 /// classes.
8908 void
8909 base_diff::set_underlying_class_diff(class_diff_sptr d)
8910 {priv_->underlying_class_diff_ = d;}
8911
8912 /// @return the pretty representation for the current instance of @ref
8913 /// base_diff.
8914 const string&
8915 base_diff::get_pretty_representation() const
8916 {
8917 if (diff::priv_->pretty_representation_.empty())
8918 {
8919 std::ostringstream o;
8920 o << "base_diff["
8921 << first_subject()->get_pretty_representation()
8922 << ", "
8923 << second_subject()->get_pretty_representation()
8924 << "]";
8925 diff::priv_->pretty_representation_ = o.str();
8926 }
8927 return diff::priv_->pretty_representation_;
8928 }
8929
8930 /// Return true iff the current diff node carries a change.
8931 ///
8932 /// Return true iff the current diff node carries a change.
8933 bool
8934 base_diff::has_changes() const
8935 {return first_base() != second_base();}
8936
8937 /// @return true iff the current diff node carries local changes.
8938 bool
8939 base_diff::has_local_changes() const
8940 {
8941 ir::change_kind k = ir::NO_CHANGE_KIND;
8942 if (!equals(*first_base(), *second_base(), &k))
8943 return k & LOCAL_CHANGE_KIND;
8944 return false;
8945 }
8946
8947 /// Generates a report for the current instance of base_diff.
8948 ///
8949 /// @param out the output stream to send the report to.
8950 ///
8951 /// @param indent the string to use for indentation.
8952 void
8953 base_diff::report(ostream& out, const string& indent) const
8954 {
8955 if (!to_be_reported())
8956 return;
8957
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;
8961
8962 if (f->get_is_static() != s->get_is_static())
8963 {
8964 if (f->get_is_static())
8965 out << indent << "is no more static";
8966 else
8967 out << indent << "now becomes static";
8968 emitted = true;
8969 }
8970
8971 if ((context()->get_allowed_category() & ACCESS_CHANGE_CATEGORY)
8972 && (f->get_access_specifier() != s->get_access_specifier()))
8973 {
8974 if (emitted)
8975 out << ", ";
8976
8977 out << "has access changed from '"
8978 << f->get_access_specifier()
8979 << "' to '"
8980 << s->get_access_specifier()
8981 << "'";
8982
8983 emitted = true;
8984 }
8985
8986 if (class_diff_sptr d = get_underlying_class_diff())
8987 {
8988 if (d->to_be_reported())
8989 {
8990 if (emitted)
8991 out << "\n";
8992 d->report(out, indent);
8993 }
8994 }
8995 }
8996
8997 /// Constructs the diff object representing a diff between two base
8998 /// class specifications.
8999 ///
9000 /// @param first the first base class specification.
9001 ///
9002 /// @param second the second base class specification.
9003 ///
9004 /// @param ctxt the content of the diff.
9005 ///
9006 /// @return the resulting diff object.
9007 base_diff_sptr
9008 compute_diff(const class_decl::base_spec_sptr first,
9009 const class_decl::base_spec_sptr second,
9010 diff_context_sptr ctxt)
9011 {
9012 class_diff_sptr cl = compute_diff(first->get_base_class(),
9013 second->get_base_class(),
9014 ctxt);
9015 base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
9016
9017 ctxt->initialize_canonical_diff(changes);
9018
9019 return changes;
9020 }
9021
9022 // </base_diff stuff>
9023
9024 //<scope_diff stuff>
9025 struct scope_diff::priv
9026 {
9027 // The edit script built by the function compute_diff.
9028 edit_script member_changes_;
9029
9030 // Below are the useful lookup tables.
9031 //
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.
9035
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_;
9044
9045 // The changed types/decls lookup tables.
9046 //
9047 // These lookup tables are populated from the lookup tables above.
9048 //
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.
9052 //
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_;
9059
9060 // The removed types/decls lookup tables.
9061 //
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_;
9066
9067 // The added types/decls lookup tables.
9068 //
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
9074
9075 /// Clear the lookup tables that are useful for reporting.
9076 ///
9077 /// This function must be updated each time a lookup table is added or
9078 /// removed.
9079 void
9080 scope_diff::clear_lookup_tables()
9081 {
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();
9092 }
9093
9094 /// Tests if the lookup tables are empty.
9095 ///
9096 /// This function must be updated each time a lookup table is added or
9097 /// removed.
9098 ///
9099 /// @return true iff all the lookup tables are empty.
9100 bool
9101 scope_diff::lookup_tables_empty() const
9102 {
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());
9113 }
9114
9115 /// If the lookup tables are not yet built, walk the member_changes_
9116 /// member and fill the lookup tables.
9117 void
9118 scope_diff::ensure_lookup_tables_populated()
9119 {
9120 if (!lookup_tables_empty())
9121 return;
9122
9123 edit_script& e = priv_->member_changes_;
9124
9125 // Populate deleted types & decls lookup tables.
9126 for (vector<deletion>::const_iterator i = e.deletions().begin();
9127 i != e.deletions().end();
9128 ++i)
9129 {
9130 decl_base_sptr decl = deleted_member_at(i);
9131 string qname = decl->get_qualified_name();
9132 if (is_type(decl))
9133 {
9134 class_decl_sptr klass_decl = dynamic_pointer_cast<class_decl>(decl);
9135 if (klass_decl && klass_decl->get_is_declaration_only())
9136 continue;
9137
9138 assert(priv_->deleted_types_.find(qname)
9139 == priv_->deleted_types_.end());
9140 priv_->deleted_types_[qname] = decl;
9141 }
9142 else
9143 {
9144 assert(priv_->deleted_decls_.find(qname)
9145 == priv_->deleted_decls_.end());
9146 priv_->deleted_decls_[qname] = decl;
9147 }
9148 }
9149
9150 // Populate inserted types & decls as well as chagned types & decls
9151 // lookup tables.
9152 for (vector<insertion>::const_iterator it = e.insertions().begin();
9153 it != e.insertions().end();
9154 ++it)
9155 {
9156 for (vector<unsigned>::const_iterator i = it->inserted_indexes().begin();
9157 i != it->inserted_indexes().end();
9158 ++i)
9159 {
9160 decl_base_sptr decl = inserted_member_at(i);
9161 string qname = decl->get_qualified_name();
9162 if (is_type(decl))
9163 {
9164 class_decl_sptr klass_decl =
9165 dynamic_pointer_cast<class_decl>(decl);
9166 if (klass_decl && klass_decl->get_is_declaration_only())
9167 continue;
9168
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())
9174 {
9175 if (*j->second != *decl)
9176 priv_->changed_types_[qname] =
9177 compute_diff(j->second, decl, context());
9178 priv_->deleted_types_.erase(j);
9179 }
9180 else
9181 priv_->inserted_types_[qname] = decl;
9182 }
9183 else
9184 {
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())
9190 {
9191 if (*j->second != *decl)
9192 priv_->changed_decls_[qname] =
9193 compute_diff(j->second, decl, context());
9194 priv_->deleted_decls_.erase(j);
9195 }
9196 else
9197 priv_->inserted_decls_[qname] = decl;
9198 }
9199 }
9200 }
9201
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_);
9206
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();
9211 ++i)
9212 {
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;
9217 }
9218 for (string_decl_base_sptr_map::const_iterator i =
9219 priv_->deleted_decls_.begin();
9220 i != priv_->deleted_decls_.end();
9221 ++i)
9222 {
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;
9227 }
9228
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();
9233 ++i)
9234 {
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;
9239 }
9240 for (string_decl_base_sptr_map::const_iterator i =
9241 priv_->inserted_decls_.begin();
9242 i != priv_->inserted_decls_.end();
9243 ++i)
9244 {
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;
9249 }
9250 }
9251
9252 /// Populate the vector of children node of the @ref diff base type
9253 /// sub-object of this instance of @ref scope_diff.
9254 ///
9255 /// The children node can then later be retrieved using
9256 /// diff::children_node().
9257 void
9258 scope_diff::chain_into_hierarchy()
9259 {
9260 for (diff_sptrs_type::const_iterator i = changed_types().begin();
9261 i != changed_types().end();
9262 ++i)
9263 if (*i)
9264 append_child_node(*i);
9265
9266 for (diff_sptrs_type::const_iterator i = changed_decls().begin();
9267 i != changed_decls().end();
9268 ++i)
9269 if (*i)
9270 append_child_node(*i);
9271 }
9272
9273 /// Constructor for scope_diff
9274 ///
9275 /// @param first_scope the first scope to consider for the diff.
9276 ///
9277 /// @param second_scope the second scope to consider for the diff.
9278 ///
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),
9284 priv_(new priv)
9285 {}
9286
9287 /// Finish building the current instance of @ref scope_diff.
9288 void
9289 scope_diff::finish_diff_type()
9290 {
9291 if (diff::priv_->finished_)
9292 return;
9293 chain_into_hierarchy();
9294 diff::priv_->finished_ = true;
9295 }
9296
9297 /// Getter for the first scope of the diff.
9298 ///
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());}
9303
9304 /// Getter for the second scope of the diff.
9305 ///
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());}
9310
9311 /// Accessor of the edit script of the members of a scope.
9312 ///
9313 /// This edit script is computed using the equality operator that
9314 /// applies to shared_ptr<decl_base>.
9315 ///
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.
9326 ///
9327 /// @return the edit script of the changes encapsulatd in this
9328 /// instance of scope_diff.
9329 const edit_script&
9330 scope_diff::member_changes() const
9331 {return priv_->member_changes_;}
9332
9333 /// Accessor of the edit script of the members of a scope.
9334 ///
9335 /// This edit script is computed using the equality operator that
9336 /// applies to shared_ptr<decl_base>.
9337 ///
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.
9348 ///
9349 /// @return the edit script of the changes encapsulatd in this
9350 /// instance of scope_diff.
9351 edit_script&
9352 scope_diff::member_changes()
9353 {return priv_->member_changes_;}
9354
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.
9358 ///
9359 /// @param i the index (in the edit script) of an element of the first
9360 /// scope that has been reported as being delete.
9361 ///
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
9366 {
9367 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(first_subject());
9368 return scope->get_member_decls()[i];
9369 }
9370
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.
9375 ///
9376 /// @param i the iterator of an element of the first scope that has
9377 /// been reported as being delete.
9378 ///
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());}
9384
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.
9389 ///
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.
9392 ///
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)
9397 {
9398 scope_decl_sptr scope = dynamic_pointer_cast<scope_decl>(second_subject());
9399 return scope->get_member_decls()[i];
9400 }
9401
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.
9406 ///
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.
9409 ///
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);}
9415
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_;}
9421
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_;}
9427
9428 const string_decl_base_sptr_map&
9429 scope_diff::removed_types() const
9430 {return priv_->removed_types_;}
9431
9432 const string_decl_base_sptr_map&
9433 scope_diff::removed_decls() const
9434 {return priv_->removed_decls_;}
9435
9436 const string_decl_base_sptr_map&
9437 scope_diff::added_types() const
9438 {return priv_->added_types_;}
9439
9440 const string_decl_base_sptr_map&
9441 scope_diff::added_decls() const
9442 {return priv_->added_decls_;}
9443
9444 /// @return the pretty representation for the current instance of @ref
9445 /// scope_diff.
9446 const string&
9447 scope_diff::get_pretty_representation() const
9448 {
9449 if (diff::priv_->pretty_representation_.empty())
9450 {
9451 std::ostringstream o;
9452 o << "scope_diff["
9453 << first_subject()->get_pretty_representation()
9454 << ", "
9455 << second_subject()->get_pretty_representation()
9456 << "]";
9457 diff::priv_->pretty_representation_ = o.str();
9458 }
9459 return diff::priv_->pretty_representation_;
9460 }
9461
9462 /// Return true iff the current diff node carries a change.
9463 ///
9464 /// Return true iff the current diff node carries a change.
9465 bool
9466 scope_diff::has_changes() const
9467 {
9468 // TODO: add the number of really removed/added stuff.
9469 return changed_types().size() + changed_decls().size();
9470 }
9471
9472 /// @return true iff the current diff node carries local changes.
9473 bool
9474 scope_diff::has_local_changes() const
9475 {
9476 ir::change_kind k = ir::NO_CHANGE_KIND;
9477 if (!equals(*first_scope(), *second_scope(), &k))
9478 return k & LOCAL_CHANGE_KIND;
9479 return false;
9480 }
9481
9482 /// A comparison functor for instances of @ref diff.
9483 struct diff_comp
9484 {
9485 bool
9486 operator()(const diff& l, diff& r) const
9487 {
9488 return (get_name(l.first_subject()) < get_name(r.first_subject()));
9489 }
9490
9491 bool
9492 operator()(const diff* l, diff* r) const
9493 {return operator()(*l, *r);}
9494
9495 bool
9496 operator()(const diff_sptr l, diff_sptr r) const
9497 {return operator()(l.get(), r.get());}
9498 }; // end struct diff_comp;
9499
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.
9503 static void
9504 sort_string_diff_sptr_map(const string_diff_sptr_map& map,
9505 diff_sptrs_type& sorted)
9506 {
9507 sorted.reserve(map.size());
9508 for (string_diff_sptr_map::const_iterator i = map.begin();
9509 i != map.end();
9510 ++i)
9511 sorted.push_back(i->second);
9512
9513 diff_comp comp;
9514 sort(sorted.begin(), sorted.end(), comp);
9515 }
9516
9517 /// Report the changes of one scope against another.
9518 ///
9519 /// @param out the out stream to report the changes to.
9520 ///
9521 /// @param indent the string to use for indentation.
9522 void
9523 scope_diff::report(ostream& out, const string& indent) const
9524 {
9525 if (!to_be_reported())
9526 return;
9527
9528 // Report changed types.
9529 unsigned num_changed_types = changed_types().size();
9530 if (num_changed_types == 0)
9531 ;
9532 else if (num_changed_types == 1)
9533 out << indent << "1 changed type:\n";
9534 else
9535 out << indent << num_changed_types << " changed types:\n";
9536
9537 for (diff_sptrs_type::const_iterator d = changed_types().begin();
9538 d != changed_types().end();
9539 ++d)
9540 {
9541 if (!*d)
9542 continue;
9543
9544 out << indent << " '"
9545 << (*d)->first_subject()->get_pretty_representation()
9546 << "' changed:\n";
9547 (*d)->report(out, indent + " ");
9548 }
9549
9550 // Report changed decls
9551 unsigned num_changed_decls = changed_decls().size();
9552 if (num_changed_decls == 0)
9553 ;
9554 else if (num_changed_decls == 1)
9555 out << indent << "1 changed declaration:\n";
9556 else
9557 out << indent << num_changed_decls << " changed declarations:\n";
9558
9559 for (diff_sptrs_type::const_iterator d= changed_decls().begin();
9560 d != changed_decls().end ();
9561 ++d)
9562 {
9563 if (!*d)
9564 continue;
9565
9566 out << indent << " '"
9567 << (*d)->first_subject()->get_pretty_representation()
9568 << "' was changed to '"
9569 << (*d)->second_subject()->get_pretty_representation()
9570 << "':\n";
9571
9572 (*d)->report(out, indent + " ");
9573 }
9574
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();
9579 ++i)
9580 out << indent
9581 << " '"
9582 << i->second->get_pretty_representation()
9583 << "' was removed\n";
9584 if (priv_->deleted_types_.size())
9585 out << "\n";
9586
9587 for (string_decl_base_sptr_map::const_iterator i =
9588 priv_->deleted_decls_.begin();
9589 i != priv_->deleted_decls_.end();
9590 ++i)
9591 out << indent
9592 << " '"
9593 << i->second->get_pretty_representation()
9594 << "' was removed\n";
9595 if (priv_->deleted_decls_.size())
9596 out << "\n";
9597
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();
9603 ++i)
9604 {
9605 // Do not report about type_decl as these are usually built-in
9606 // types.
9607 if (dynamic_pointer_cast<type_decl>(i->second))
9608 continue;
9609 out << indent
9610 << " '"
9611 << i->second->get_pretty_representation()
9612 << "' was added\n";
9613 emitted = true;
9614 }
9615 if (emitted)
9616 out << "\n";
9617
9618 emitted = false;
9619 for (string_decl_base_sptr_map::const_iterator i =
9620 priv_->inserted_decls_.begin();
9621 i != priv_->inserted_decls_.end();
9622 ++i)
9623 {
9624 // Do not report about type_decl as these are usually built-in
9625 // types.
9626 if (dynamic_pointer_cast<type_decl>(i->second))
9627 continue;
9628 out << indent
9629 << " '"
9630 << i->second->get_pretty_representation()
9631 << "' was added\n";
9632 emitted = true;
9633 }
9634 if (emitted)
9635 out << "\n";
9636 }
9637
9638 /// Compute the diff between two scopes.
9639 ///
9640 /// @param first the first scope to consider in computing the diff.
9641 ///
9642 /// @param second the second scope to consider in the diff
9643 /// computation. The second scope is diffed against the first scope.
9644 ///
9645 /// @param d a pointer to the diff object to populate with the
9646 /// computed diff.
9647 ///
9648 /// @return return the populated \a d parameter passed to this
9649 /// function.
9650 ///
9651 /// @param ctxt the diff context to use.
9652 scope_diff_sptr
9653 compute_diff(const scope_decl_sptr first,
9654 const scope_decl_sptr second,
9655 scope_diff_sptr d,
9656 diff_context_sptr ctxt)
9657 {
9658 assert(d->first_scope() == first && d->second_scope() == second);
9659
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());
9665
9666 d->ensure_lookup_tables_populated();
9667 d->context(ctxt);
9668
9669 return d;
9670 }
9671
9672 /// Compute the diff between two scopes.
9673 ///
9674 /// @param first_scope the first scope to consider in computing the diff.
9675 ///
9676 /// @param second_scope the second scope to consider in the diff
9677 /// computation. The second scope is diffed against the first scope.
9678 ///
9679 /// @param ctxt the diff context to use.
9680 ///
9681 /// @return return the resulting diff
9682 scope_diff_sptr
9683 compute_diff(const scope_decl_sptr first_scope,
9684 const scope_decl_sptr second_scope,
9685 diff_context_sptr ctxt)
9686 {
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);
9690 return d;
9691 }
9692
9693 //</scope_diff stuff>
9694
9695 // <fn_parm_diff stuff>
9696 struct fn_parm_diff::priv
9697 {
9698 mutable diff_sptr type_diff;
9699 }; // end struct fn_parm_diff::priv
9700
9701 /// Constructor for the fn_parm_diff type.
9702 ///
9703 /// @param first the first subject of the diff.
9704 ///
9705 /// @param second the second subject of the diff.
9706 ///
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),
9712 priv_(new priv)
9713 {
9714 assert(first->get_index() == second->get_index());
9715 priv_->type_diff = compute_diff(first->get_type(),
9716 second->get_type(),
9717 ctxt);
9718 assert(priv_->type_diff);
9719 }
9720
9721 /// Finish the building of the current instance of @ref fn_parm_diff.
9722 void
9723 fn_parm_diff::finish_diff_type()
9724 {
9725 if (diff::priv_->finished_)
9726 return;
9727 chain_into_hierarchy();
9728 diff::priv_->finished_ = true;
9729 }
9730
9731 /// Getter for the first subject of this diff node.
9732 ///
9733 /// @return the first function_decl::parameter_sptr subject of this
9734 /// diff node.
9735 const function_decl::parameter_sptr
9736 fn_parm_diff::first_parameter() const
9737 {return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
9738
9739 /// Getter for the second subject of this diff node.
9740 ///
9741 /// @return the second function_decl::parameter_sptr subject of this
9742 /// diff node.
9743 const function_decl::parameter_sptr
9744 fn_parm_diff::second_parameter() const
9745 {return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
9746
9747 /// Getter for the diff representing the changes on the type of the
9748 /// function parameter involved in the current instance of @ref
9749 /// fn_parm_diff.
9750 ///
9751 /// @return a diff_sptr representing the changes on the type of the
9752 /// function parameter we are interested in.
9753 diff_sptr
9754 fn_parm_diff::get_type_diff() const
9755 {return priv_->type_diff;}
9756
9757 /// Build and return a textual representation of the current instance
9758 /// of @ref fn_parm_diff.
9759 ///
9760 /// @return the string representing the current instance of
9761 /// fn_parm_diff.
9762 const string&
9763 fn_parm_diff::get_pretty_representation() const
9764 {
9765 if (diff::priv_->pretty_representation_.empty())
9766 {
9767 std::ostringstream o;
9768 o << "function_parameter_diff["
9769 << first_subject()->get_pretty_representation()
9770 << ", "
9771 << second_subject()->get_pretty_representation()
9772 << "]";
9773 diff::priv_->pretty_representation_ = o.str();
9774 }
9775 return diff::priv_->pretty_representation_;
9776 }
9777
9778 /// Return true iff the current diff node carries a change.
9779 ///
9780 /// @return true iff the current diff node carries a change.
9781 bool
9782 fn_parm_diff::has_changes() const
9783 {return *first_parameter() != *second_parameter();}
9784
9785 /// Check if the the current diff node carries a local change.
9786 ///
9787 /// @return true iff the current diff node carries a local change.
9788 bool
9789 fn_parm_diff::has_local_changes() const
9790 {
9791 ir::change_kind k = ir::NO_CHANGE_KIND;
9792 if (!equals(*first_parameter(), *second_parameter(), &k))
9793 return k & LOCAL_CHANGE_KIND;
9794 return false;
9795 }
9796
9797 /// Emit a textual report about the current fn_parm_diff instance.
9798 ///
9799 /// @param out the output stream to emit the textual report to.
9800 ///
9801 /// @param indent the indentation string to use in the report.
9802 void
9803 fn_parm_diff::report(ostream& out, const string& indent) const
9804 {
9805 function_decl::parameter_sptr f = first_parameter(), s = second_parameter();
9806
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
9810 // function).
9811 bool has_sub_type_change =
9812 type_has_sub_type_changes(first_parameter()->get_type(),
9813 second_parameter()->get_type());
9814
9815 if (to_be_reported())
9816 {
9817 assert(get_type_diff() && get_type_diff()->to_be_reported());
9818 out << indent
9819 << "parameter " << f->get_index()
9820 << " of type '"
9821 << f->get_type_pretty_representation();
9822
9823 if (has_sub_type_change)
9824 out << "' has sub-type changes:\n";
9825 else
9826 out << "' changed:\n";
9827
9828 get_type_diff()->report(out, indent + " ");
9829 }
9830 }
9831
9832 /// Populate the vector of children nodes of the @ref diff base type
9833 /// sub-object of this instance of @ref fn_parm_diff.
9834 ///
9835 /// The children nodes can then later be retrieved using
9836 /// diff::children_nodes()
9837 void
9838 fn_parm_diff::chain_into_hierarchy()
9839 {
9840 if (get_type_diff())
9841 append_child_node(get_type_diff());
9842 }
9843
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.
9847 ///
9848 /// @param first the first subject of the diff.
9849 ///
9850 /// @param second the second subject of the diff.
9851 ///
9852 /// @param ctxt the context of the diff.
9853 ///
9854 /// @return fn_parm_diff_sptr the resulting diff node.
9855 fn_parm_diff_sptr
9856 compute_diff(const function_decl::parameter_sptr first,
9857 const function_decl::parameter_sptr second,
9858 diff_context_sptr ctxt)
9859 {
9860 if (!first || !second)
9861 return fn_parm_diff_sptr();
9862
9863 fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
9864 ctxt->initialize_canonical_diff(result);
9865
9866 return result;
9867 }
9868 // </fn_parm_diff stuff>
9869
9870 // <function_type_diff stuff>
9871 struct function_type_diff::priv
9872 {
9873 diff_sptr return_type_diff_;
9874 edit_script parm_changes_;
9875
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
9889 // c++ at least).
9890 unsigned_fn_parm_diff_sptr_map changed_parms_by_id_;
9891
9892 priv()
9893 {}
9894 }; // end struct function_type_diff::priv
9895
9896 void
9897 function_type_diff::ensure_lookup_tables_populated()
9898 {
9899 priv_->return_type_diff_ =
9900 compute_diff(first_function_type()->get_return_type(),
9901 second_function_type()->get_return_type(),
9902 context());
9903
9904 string parm_name;
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();
9909 ++i)
9910 {
9911 parm = *(first_function_type()->get_first_non_implicit_parm()
9912 + i->index());
9913 parm_name = parm->get_name_id();
9914 // If for a reason the type name is empty we want to know and
9915 // fix that.
9916 assert(!parm_name.empty());
9917 priv_->deleted_parms_[parm_name] = parm;
9918 priv_->deleted_parms_by_id_[parm->get_index()] = parm;
9919 }
9920
9921 for (vector<insertion>::const_iterator i =
9922 priv_->parm_changes_.insertions().begin();
9923 i != priv_->parm_changes_.insertions().end();
9924 ++i)
9925 {
9926 for (vector<unsigned>::const_iterator j =
9927 i->inserted_indexes().begin();
9928 j != i->inserted_indexes().end();
9929 ++j)
9930 {
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
9934 // fix that.
9935 assert(!parm_name.empty());
9936 {
9937 string_parm_map::const_iterator k =
9938 priv_->deleted_parms_.find(parm_name);
9939 if (k != priv_->deleted_parms_.end())
9940 {
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);
9945 }
9946 else
9947 priv_->added_parms_[parm_name] = parm;
9948 }
9949 {
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())
9953 {
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());
9961 }
9962 else
9963 priv_->added_parms_by_id_[parm->get_index()] = parm;
9964 }
9965 }
9966 }
9967
9968 sort_string_parm_map(priv_->deleted_parms_,
9969 priv_->sorted_deleted_parms_);
9970
9971 sort_string_parm_map(priv_->added_parms_,
9972 priv_->sorted_added_parms_);
9973 }
9974
9975 /// In the vector of deleted parameters, get the one that is at a given
9976 /// index.
9977 ///
9978 /// @param i the index of the deleted parameter to get.
9979 ///
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];}
9984
9985 /// In the vector of inserted parameters, get the one that is at a
9986 /// given index.
9987 ///
9988 /// @param i the index of the inserted parameter to get.
9989 ///
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];}
9994
9995 /// Consutrctor of the @ref function_type type.
9996 ///
9997 /// @param first the first @ref function_type subject of the diff to
9998 /// create.
9999 ///
10000 /// @param second the second @ref function_type subject of the diff to
10001 /// create.
10002 ///
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),
10009 priv_(new priv)
10010 {}
10011
10012 /// Finish building the current instance of @ref function_type_diff
10013 void
10014 function_type_diff::finish_diff_type()
10015 {
10016 if (diff::priv_->finished_)
10017 return;
10018 chain_into_hierarchy();
10019 diff::priv_->finished_ = true;
10020 }
10021
10022 /// Getter for the first subject of the diff.
10023 ///
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());}
10028
10029 /// Getter for the second subject of the diff.
10030 ///
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());}
10035
10036 /// Getter for the diff of the return types of the two function types
10037 /// of the current diff.
10038 ///
10039 /// @return the diff of the return types of the two function types of
10040 /// the current diff.
10041 const diff_sptr
10042 function_type_diff::return_type_diff() const
10043 {return priv_->return_type_diff_;}
10044
10045 /// Getter for the map of function parameter changes of the current diff.
10046 ///
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_;}
10051
10052 /// Getter for the map of parameters that got removed.
10053 ///
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_;}
10058
10059 /// Getter for the map of parameters that got added.
10060 ///
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_;}
10065
10066 /// Build and return a copy of a pretty representation of the current
10067 /// instance of @ref function_type_diff.
10068 ///
10069 /// @return a copy of the pretty representation of the current
10070 /// instance of @ref function_type_diff.
10071 const string&
10072 function_type_diff::get_pretty_representation() const
10073 {
10074 if (diff::priv_->pretty_representation_.empty())
10075 {
10076 std::ostringstream o;
10077 o << "function_type_diff["
10078 << abigail::ir::get_pretty_representation(first_function_type())
10079 << ", "
10080 << abigail::ir::get_pretty_representation(second_function_type())
10081 << "]";
10082 diff::priv_->pretty_representation_ = o.str();
10083 }
10084 return diff::priv_->pretty_representation_;
10085 }
10086
10087 /// Test if the current diff node carries changes.
10088 ///
10089 /// @return true iff the current diff node carries changes.
10090 bool
10091 function_type_diff::has_changes() const
10092 {return *first_function_type() != *second_function_type();}
10093
10094 /// Test if the current diff node carries local changes.
10095 ///
10096 /// A local change is a change that is carried by this diff node, not
10097 /// by any of its children nodes.
10098 ///
10099 /// @return true iff the current diff node has local changes.
10100 bool
10101 function_type_diff::has_local_changes() const
10102 {
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;
10106 return false;
10107 }
10108
10109 /// Build and emit a textual report about the current
10110 ///
10111 /// @param out the output stream.
10112 ///
10113 /// @param indent the indentation string to use.
10114 void
10115 function_type_diff::report(ostream& out, const string& indent) const
10116 {
10117 if (!to_be_reported())
10118 return;
10119
10120 function_type_sptr fft = first_function_type();
10121 function_type_sptr sft = second_function_type();
10122
10123 diff_context_sptr ctxt = context();
10124 corpus_sptr fc = ctxt->get_first_corpus();
10125 corpus_sptr sc = ctxt->get_second_corpus();
10126
10127 #if 0
10128 string qn1 = get_function_type_name(fft), qn2 = get_function_type_name(sft);
10129
10130 if (qn1 != qn2)
10131 {
10132 string frep1 = ir::get_pretty_representation(fft),
10133 frep2 = ir::get_pretty_representation(sft);
10134 out << indent << "'" << frep1 << "' now becomes '" << frep2 << "'\n";
10135 return;
10136 }
10137 #endif
10138
10139 // Report about the size of the function address
10140 if (fft->get_size_in_bits() != sft->get_size_in_bits())
10141 {
10142 out << indent << "address size of function changed from "
10143 << fft->get_size_in_bits()
10144 << " bits to "
10145 << sft->get_size_in_bits()
10146 << " bits\n";
10147 }
10148
10149 // Report about the alignment of the function address
10150 if (fft->get_alignment_in_bits()
10151 != sft->get_alignment_in_bits())
10152 {
10153 out << indent << "address alignment of function changed from "
10154 << fft->get_alignment_in_bits()
10155 << " bits to "
10156 << sft->get_alignment_in_bits()
10157 << " bits\n";
10158 }
10159
10160 // Report about return type differences.
10161 if (priv_->return_type_diff_ && priv_->return_type_diff_->to_be_reported())
10162 {
10163 out << indent << "return type changed:\n";
10164 priv_->return_type_diff_->report(out, indent + " ");
10165 }
10166
10167 // Hmmh, the above was quick. Now report about function parameters;
10168 // this shouldn't be as straightforward.
10169 //
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_,
10173 sorted_fn_parms);
10174 for (vector<fn_parm_diff_sptr>::const_iterator i =
10175 sorted_fn_parms.begin();
10176 i != sorted_fn_parms.end();
10177 ++i)
10178 {
10179 diff_sptr d = *i;
10180 if (d && d->to_be_reported())
10181 d->report(out, indent);
10182 }
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
10186 // removed.
10187 sorted_fn_parms.clear();
10188 sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
10189 sorted_fn_parms);
10190 for (vector<fn_parm_diff_sptr>::const_iterator i = sorted_fn_parms.begin();
10191 i != sorted_fn_parms.end();
10192 ++i)
10193 {
10194 diff_sptr d = *i;
10195 if (d && d->to_be_reported())
10196 d->report(out, indent);
10197 }
10198
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();
10204 ++i)
10205 {
10206 out << indent << "parameter " << (*i)->get_index()
10207 << " of type '" << (*i)->get_type_pretty_representation()
10208 << "' was removed\n";
10209 emitted = true;
10210 }
10211 if (emitted)
10212 out << "\n";
10213
10214 // Report about the parameters that got added
10215 emitted = false;
10216 for (vector<function_decl::parameter_sptr>::const_iterator i =
10217 priv_->sorted_added_parms_.begin();
10218 i != priv_->sorted_added_parms_.end();
10219 ++i)
10220 {
10221 out << indent << "parameter " << (*i)->get_index()
10222 << " of type '" << (*i)->get_type_pretty_representation()
10223 << "' was added\n";
10224 emitted = true;
10225 }
10226 if (emitted)
10227 out << "\n";
10228 }
10229
10230 /// Populate the vector of children node of the @ref diff base type
10231 /// sub-object of this instance of @ref function_type_diff.
10232 ///
10233 /// The children node can then later be retrieved using
10234 /// diff::children_node().
10235 void
10236 function_type_diff::chain_into_hierarchy()
10237 {
10238 if (diff_sptr d = return_type_diff())
10239 append_child_node(d);
10240
10241 for (string_fn_parm_diff_sptr_map::const_iterator i =
10242 subtype_changed_parms().begin();
10243 i != subtype_changed_parms().end();
10244 ++i)
10245 if (diff_sptr d = i->second)
10246 append_child_node(d);
10247
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();
10251 ++i)
10252 if (diff_sptr d = i->second)
10253 append_child_node(d);
10254 }
10255
10256 /// Compute the diff between two instances of @ref function_type.
10257 ///
10258 /// @param first the first @ref function_type to consider for the diff.
10259 ///
10260 /// @param second the second @ref function_type to consider for the diff.
10261 ///
10262 /// @param ctxt the diff context to use.
10263 ///
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)
10269 {
10270 if (!first || !second)
10271 {
10272 // TODO: implement this for either first or second being NULL.
10273 return function_type_diff_sptr();
10274 }
10275
10276 function_type_diff_sptr result(new function_type_diff(first, second, ctxt));
10277
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_);
10283
10284 result->ensure_lookup_tables_populated();
10285
10286 ctxt->initialize_canonical_diff(result);
10287
10288 return result;
10289 }
10290 // </function_type_diff stuff>
10291
10292 // <function_decl_diff stuff>
10293 struct function_decl_diff::priv
10294 {
10295 function_type_diff_sptr type_diff_;
10296
10297 priv()
10298 {}
10299 };// end struct function_decl_diff::priv
10300
10301 /// Build the lookup tables of the diff, if necessary.
10302 void
10303 function_decl_diff::ensure_lookup_tables_populated()
10304 {
10305 }
10306
10307 /// Populate the vector of children node of the @ref diff base type
10308 /// sub-object of this instance of @ref function_decl_diff.
10309 ///
10310 /// The children node can then later be retrieved using
10311 /// diff::children_node().
10312 void
10313 function_decl_diff::chain_into_hierarchy()
10314 {
10315 if (diff_sptr d = type_diff())
10316 append_child_node(d);
10317 }
10318
10319 /// Constructor for function_decl_diff
10320 ///
10321 /// @param first the first function considered by the diff.
10322 ///
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),
10328 priv_(new priv)
10329 {
10330 }
10331
10332 /// Finish building the current instance of @ref function_decl_diff.
10333 void
10334 function_decl_diff::finish_diff_type()
10335 {
10336 if (diff::priv_->finished_)
10337 return;
10338 chain_into_hierarchy();
10339 diff::priv_->finished_ = true;
10340 }
10341
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());}
10346
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());}
10351
10352 const function_type_diff_sptr
10353 function_decl_diff::type_diff() const
10354 {return priv_->type_diff_;}
10355
10356 /// @return the pretty representation for the current instance of @ref
10357 /// function_decl_diff.
10358 const string&
10359 function_decl_diff::get_pretty_representation() const
10360 {
10361 if (diff::priv_->pretty_representation_.empty())
10362 {
10363 std::ostringstream o;
10364 o << "function_diff["
10365 << first_subject()->get_pretty_representation()
10366 << ", "
10367 << second_subject()->get_pretty_representation()
10368 << "]";
10369 diff::priv_->pretty_representation_ = o.str();
10370 }
10371 return diff::priv_->pretty_representation_;
10372 }
10373
10374 /// Return true iff the current diff node carries a change.
10375 ///
10376 /// @return true iff the current diff node carries a change.
10377 bool
10378 function_decl_diff::has_changes() const
10379 {return *first_function_decl() != *second_function_decl();}
10380
10381 /// @return true iff the current diff node carries local changes.
10382 bool
10383 function_decl_diff::has_local_changes() const
10384 {
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;
10388 return false;
10389 }
10390
10391 /// A comparison functor to compare two instances of @ref fn_parm_diff
10392 /// based on their indexes.
10393 struct fn_parm_diff_comp
10394 {
10395 /// @param f the first diff
10396 ///
10397 /// @param s the second diff
10398 ///
10399 /// @return true if the index of @p f is less than the index of @p
10400 /// s.
10401 bool
10402 operator()(const fn_parm_diff& f, const fn_parm_diff& s)
10403 {return f.first_parameter()->get_index() < s.first_parameter()->get_index();}
10404
10405 bool
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
10409
10410 /// Sort a map of @ref fn_parm_diff by the indexes of the function
10411 /// parameters.
10412 ///
10413 /// @param map the map to sort.
10414 ///
10415 /// @param sorted the resulting sorted vector of changed function
10416 /// parms.
10417 static void
10418 sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map,
10419 vector<fn_parm_diff_sptr>& sorted)
10420 {
10421 sorted.reserve(map.size());
10422 for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
10423 i != map.end();
10424 ++i)
10425 sorted.push_back(i->second);
10426
10427 fn_parm_diff_comp comp;
10428 std::sort(sorted.begin(), sorted.end(), comp);
10429 }
10430
10431 /// Sort a map of changed function parameters by the indexes of the
10432 /// function parameters.
10433 ///
10434 /// @param map the map to sort.
10435 ///
10436 /// @param sorted the resulting sorted vector of instances of @ref
10437 /// fn_parm_diff_sptr
10438 static void
10439 sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map& map,
10440 vector<fn_parm_diff_sptr>& sorted)
10441 {
10442 sorted.reserve(map.size());
10443 for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
10444 i != map.end();
10445 ++i)
10446 sorted.push_back(i->second);
10447
10448 fn_parm_diff_comp comp;
10449 std::sort(sorted.begin(), sorted.end(), comp);
10450 }
10451
10452 /// Functor that compares two function parameters for the purpose of
10453 /// sorting them.
10454 struct parm_comp
10455 {
10456 /// Returns true iff the index of the first parameter is smaller
10457 /// than the of the second parameter.
10458 ///
10459 /// @param l the first parameter to compare.
10460 ///
10461 /// @param r the second parameter to compare.
10462 ///
10463 /// @return true iff the index of the first parameter is smaller
10464 /// than the of the second parameter.
10465 bool
10466 operator()(const function_decl::parameter& l,
10467 const function_decl::parameter& r)
10468 {return l.get_index() < r.get_index();}
10469
10470 /// Returns true iff the index of the first parameter is smaller
10471 /// than the of the second parameter.
10472 ///
10473 /// @param l the first parameter to compare.
10474 ///
10475 /// @param r the second parameter to compare.
10476 ///
10477 /// @return true iff the index of the first parameter is smaller
10478 /// than the of the second parameter.
10479 bool
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
10484
10485 /// Sort a map of string -> function parameters.
10486 ///
10487 /// @param map the map to sort.
10488 ///
10489 /// @param sorted the resulting sorted vector of
10490 /// @ref vector<function_decl::parameter_sptr>
10491 static void
10492 sort_string_parm_map(const string_parm_map& map,
10493 vector<function_decl::parameter_sptr>& sorted)
10494 {
10495 for (string_parm_map::const_iterator i = map.begin();
10496 i != map.end();
10497 ++i)
10498 sorted.push_back(i->second);
10499
10500 // TODO: finish this.
10501 parm_comp comp;
10502 std::sort(sorted.begin(), sorted.end(), comp);
10503 }
10504
10505 /// Serialize a report of the changes encapsulated in the current
10506 /// instance of function_decl_diff over to an output stream.
10507 ///
10508 /// @param out the output stream to serialize the report to.
10509 ///
10510 /// @param indent the string to use an an indentation prefix.
10511 void
10512 function_decl_diff::report(ostream& out, const string& indent) const
10513 {
10514 if (!to_be_reported())
10515 return;
10516
10517 maybe_report_diff_for_member(first_function_decl(),
10518 second_function_decl(),
10519 context(), out, indent);
10520
10521 function_decl_sptr ff = first_function_decl();
10522 function_decl_sptr sf = second_function_decl();
10523
10524 diff_context_sptr ctxt = context();
10525 corpus_sptr fc = ctxt->get_first_corpus();
10526 corpus_sptr sc = ctxt->get_second_corpus();
10527
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();
10531
10532 if (s1)
10533 linkage_names1 = s1->get_id_string();
10534 if (s2)
10535 linkage_names2 = s2->get_id_string();
10536
10537 // If the symbols for ff and sf have aliases, get all the names of
10538 // the aliases;
10539 if (fc && s1)
10540 linkage_names1 =
10541 s1->get_aliases_id_string(fc->get_fun_symbol_map());
10542 if (sc && s2)
10543 linkage_names2 =
10544 s2->get_aliases_id_string(sc->get_fun_symbol_map());
10545
10546 /// If the set of linkage names of the function have changed, report
10547 /// it.
10548 if (linkage_names1 != linkage_names2)
10549 {
10550 if (linkage_names1.empty())
10551 {
10552 out << indent << ff->get_pretty_representation()
10553 << " didn't have any linkage name, and it now has: '"
10554 << linkage_names2 << "'\n";
10555 }
10556 else if (linkage_names2.empty())
10557 {
10558 out << indent << ff->get_pretty_representation()
10559 << " did have linkage names '" << linkage_names1
10560 << "'\n"
10561 << indent << "but it doesn't have any linkage name anymore\n";
10562 }
10563 else
10564 out << indent << "linkage names of "
10565 << ff->get_pretty_representation()
10566 << "\n" << indent << "changed from '"
10567 << linkage_names1 << "' to '" << linkage_names2 << "'\n";
10568 }
10569
10570 if (qn1 != qn2)
10571 {
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";
10577 return;
10578 }
10579
10580 // Now report about inline-ness changes
10581 if (ff->is_declared_inline() != sf->is_declared_inline())
10582 {
10583 out << indent;
10584 if (ff->is_declared_inline())
10585 out << sf->get_pretty_representation()
10586 << " is not declared inline anymore\n";
10587 else
10588 out << sf->get_pretty_representation()
10589 << " is now declared inline\n";
10590 }
10591
10592 // Report about vtable offset changes.
10593 if (is_member_function(ff) && is_member_function(sf))
10594 {
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)
10598 {
10599 out << indent;
10600 if (ff_is_virtual)
10601 out << ff->get_pretty_representation()
10602 << " is no more declared virtual\n";
10603 else
10604 out << ff->get_pretty_representation()
10605 << " is now declared virtual\n";
10606 }
10607
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))
10612 {
10613 out << indent
10614 << "the vtable offset of " << ff->get_pretty_representation()
10615 << " changed from " << ff_vtable_offset
10616 << " to " << sf_vtable_offset << "\n";
10617 }
10618 }
10619
10620 // Report about function type differences.
10621 if (type_diff() && type_diff()->to_be_reported())
10622 type_diff()->report(out, indent);
10623 }
10624
10625 /// Compute the diff between two function_decl.
10626 ///
10627 /// @param first the first function_decl to consider for the diff
10628 ///
10629 /// @param second the second function_decl to consider for the diff
10630 ///
10631 /// @param ctxt the diff context to use.
10632 ///
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)
10638 {
10639 if (!first || !second)
10640 {
10641 // TODO: implement this for either first or second being NULL.
10642 return function_decl_diff_sptr();
10643 }
10644
10645 function_type_diff_sptr type_diff = compute_diff(first->get_type(),
10646 second->get_type(),
10647 ctxt);
10648
10649 function_decl_diff_sptr result(new function_decl_diff(first, second,
10650 ctxt));
10651 result->priv_->type_diff_ = type_diff;
10652
10653 result->ensure_lookup_tables_populated();
10654
10655 ctxt->initialize_canonical_diff(result);
10656
10657 return result;
10658 }
10659
10660 // </function_decl_diff stuff>
10661
10662 // <type_decl_diff stuff>
10663
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)
10669 {}
10670
10671 /// Finish building the current instance of @ref type_decl_diff.
10672 void
10673 type_decl_diff::finish_diff_type()
10674 {
10675 if (diff::priv_->finished_)
10676 return;
10677 diff::priv_->finished_ = true;
10678 }
10679
10680 /// Getter for the first subject of the type_decl_diff.
10681 ///
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());}
10686
10687 /// Getter for the second subject of the type_decl_diff.
10688 ///
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());}
10693
10694 /// @return the pretty representation for the current instance of @ref
10695 /// type_decl_diff.
10696 const string&
10697 type_decl_diff::get_pretty_representation() const
10698 {
10699 if (diff::priv_->pretty_representation_.empty())
10700 {
10701 std::ostringstream o;
10702 o << "type_decl_diff["
10703 << first_subject()->get_pretty_representation()
10704 << ", "
10705 << second_subject()->get_pretty_representation()
10706 << "]";
10707 diff::priv_->pretty_representation_ = o.str();
10708 }
10709 return diff::priv_->pretty_representation_;
10710 }
10711 /// Return true iff the current diff node carries a change.
10712 ///
10713 /// @return true iff the current diff node carries a change.
10714 bool
10715 type_decl_diff::has_changes() const
10716 {return first_type_decl() != second_type_decl();}
10717
10718 /// @return true iff the current diff node carries local changes.
10719 bool
10720 type_decl_diff::has_local_changes() const
10721 {
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;
10725 return false;
10726 }
10727 /// Ouputs a report of the differences between of the two type_decl
10728 /// involved in the type_decl_diff.
10729 ///
10730 /// @param out the output stream to emit the report to.
10731 ///
10732 /// @param indent the string to use for indentatino indent.
10733 void
10734 type_decl_diff::report(ostream& out, const string& indent) const
10735 {
10736 if (!to_be_reported())
10737 return;
10738
10739 type_decl_sptr f = first_type_decl(), s = second_type_decl();
10740
10741 string name = f->get_pretty_representation();
10742
10743 bool n = report_name_size_and_alignment_changes(f, s, context(),
10744 out, indent,
10745 /*new line=*/false);
10746
10747 if (f->get_visibility() != s->get_visibility())
10748 {
10749 if (n)
10750 out << "\n";
10751 out << indent
10752 << "visibility changed from '"
10753 << f->get_visibility() << "' to '" << s->get_visibility();
10754 n = true;
10755 }
10756
10757 if (f->get_linkage_name() != s->get_linkage_name())
10758 {
10759 if (n)
10760 out << "\n";
10761 out << indent
10762 << "mangled name changed from '"
10763 << f->get_linkage_name() << "' to "
10764 << s->get_linkage_name();
10765 n = true;
10766 }
10767
10768 if (n)
10769 out << "\n";
10770 }
10771
10772 /// Compute a diff between two type_decl.
10773 ///
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.
10781 ///
10782 /// @param first a pointer to the first type_decl to
10783 /// consider.
10784 ///
10785 /// @param second a pointer to the second type_decl to consider.
10786 ///
10787 /// @param ctxt the diff context to use.
10788 ///
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)
10794 {
10795 type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
10796
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.
10803
10804 ctxt->initialize_canonical_diff(result);
10805
10806 return result;
10807 }
10808
10809 // </type_decl_diff stuff>
10810
10811 // <typedef_diff stuff>
10812
10813 struct typedef_diff::priv
10814 {
10815 diff_sptr underlying_type_diff_;
10816
10817 priv(const diff_sptr underlying_type_diff)
10818 : underlying_type_diff_(underlying_type_diff)
10819 {}
10820 };//end struct typedef_diff::priv
10821
10822 /// Populate the vector of children node of the @ref diff base type
10823 /// sub-object of this instance of @ref typedef_diff.
10824 ///
10825 /// The children node can then later be retrieved using
10826 /// diff::children_node().
10827 void
10828 typedef_diff::chain_into_hierarchy()
10829 {append_child_node(underlying_type_diff());}
10830
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))
10838 {}
10839
10840 /// Finish building the current instance of @ref typedef_diff.
10841 void
10842 typedef_diff::finish_diff_type()
10843 {
10844 if (diff::priv_->finished_)
10845 return;
10846 chain_into_hierarchy();
10847 diff::priv_->finished_ = true;
10848 }
10849
10850 /// Getter for the firt typedef_decl involved in the diff.
10851 ///
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());}
10856
10857 /// Getter for the second typedef_decl involved in the diff.
10858 ///
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());}
10863
10864 /// Getter for the diff between the two underlying types of the
10865 /// typedefs.
10866 ///
10867 /// @return the diff object reprensenting the difference between the
10868 /// two underlying types of the typedefs.
10869 const diff_sptr
10870 typedef_diff::underlying_type_diff() const
10871 {return priv_->underlying_type_diff_;}
10872
10873 /// Setter for the diff between the two underlying types of the
10874 /// typedefs.
10875 ///
10876 /// @param d the new diff object reprensenting the difference between
10877 /// the two underlying types of the typedefs.
10878 void
10879 typedef_diff::underlying_type_diff(const diff_sptr d)
10880 {priv_->underlying_type_diff_ = d;}
10881
10882 /// @return the pretty representation for the current instance of @ref
10883 /// typedef_diff.
10884 const string&
10885 typedef_diff::get_pretty_representation() const
10886 {
10887 if (diff::priv_->pretty_representation_.empty())
10888 {
10889 std::ostringstream o;
10890 o << "typedef_diff["
10891 << first_subject()->get_pretty_representation()
10892 << ", "
10893 << second_subject()->get_pretty_representation()
10894 << "]";
10895 diff::priv_->pretty_representation_ = o.str();
10896 }
10897 return diff::priv_->pretty_representation_;
10898 }
10899
10900 /// Return true iff the current diff node carries a change.
10901 ///
10902 /// @return true iff the current diff node carries a change.
10903 bool
10904 typedef_diff::has_changes() const
10905 {
10906 decl_base_sptr second = second_typedef_decl();
10907 return !(*first_typedef_decl() == *second);
10908 }
10909
10910 /// @return true iff the current diff node carries local changes.
10911 bool
10912 typedef_diff::has_local_changes() const
10913 {
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;
10917 return false;
10918 }
10919
10920 /// Reports the difference between the two subjects of the diff in a
10921 /// serialized form.
10922 ///
10923 /// @param out the output stream to emit the report to.
10924 ///
10925 /// @param indent the indentation string to use.
10926 void
10927 typedef_diff::report(ostream& out, const string& indent) const
10928 {
10929 if (!to_be_reported())
10930 return;
10931
10932 bool emit_nl = false;
10933 typedef_decl_sptr f = first_typedef_decl(), s = second_typedef_decl();
10934
10935 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(f, s);
10936
10937 maybe_report_diff_for_member(f, s, context(), out, indent);
10938
10939 if (filtering::has_harmless_name_change(f, s)
10940 && context()->get_allowed_category() & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
10941 {
10942 out << indent << "typedef name changed from "
10943 << f->get_qualified_name()
10944 << " to "
10945 << s->get_qualified_name()
10946 << "\n";
10947 emit_nl = true;
10948 }
10949
10950 diff_sptr d = underlying_type_diff();
10951 if (d && d->to_be_reported())
10952 {
10953 RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(d, "underlying type");
10954 out << indent
10955 << "underlying type '"
10956 << d->first_subject()->get_pretty_representation()
10957 << "' changed:\n";
10958 d->report(out, indent + " ");
10959 emit_nl = false;
10960 }
10961
10962 if (emit_nl)
10963 out << "\n";
10964 }
10965
10966 /// Compute a diff between two typedef_decl.
10967 ///
10968 /// @param first a pointer to the first typedef_decl to consider.
10969 ///
10970 /// @param second a pointer to the second typedef_decl to consider.
10971 ///
10972 /// @param ctxt the diff context to use.
10973 ///
10974 /// @return a pointer to the the resulting typedef_diff.
10975 typedef_diff_sptr
10976 compute_diff(const typedef_decl_sptr first,
10977 const typedef_decl_sptr second,
10978 diff_context_sptr ctxt)
10979 {
10980 diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
10981 second->get_underlying_type(),
10982 ctxt);
10983 typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
10984
10985 ctxt->initialize_canonical_diff(result);
10986
10987 return result;
10988 }
10989
10990 // </typedef_diff stuff>
10991
10992 // <translation_unit_diff stuff>
10993
10994 struct translation_unit_diff::priv
10995 {
10996 translation_unit_sptr first_;
10997 translation_unit_sptr second_;
10998
10999 priv(translation_unit_sptr f, translation_unit_sptr s)
11000 : first_(f), second_(s)
11001 {}
11002 };//end struct translation_unit_diff::priv
11003
11004 /// Constructor for translation_unit_diff.
11005 ///
11006 /// @param first the first translation unit to consider for this diff.
11007 ///
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))
11014 {
11015 }
11016
11017 /// Getter for the first translation unit of this diff.
11018 ///
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_;}
11023
11024 /// Getter for the second translation unit of this diff.
11025 ///
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_;}
11030
11031 /// Return true iff the current diff node carries a change.
11032 ///
11033 /// @return true iff the current diff node carries a change.
11034 bool
11035 translation_unit_diff::has_changes() const
11036 {return scope_diff::has_changes();}
11037
11038 /// @return true iff the current diff node carries local changes.
11039 bool
11040 translation_unit_diff::has_local_changes() const
11041 {return false;}
11042
11043 /// Report the diff in a serialized form.
11044 ///
11045 /// @param out the output stream to serialize the report to.
11046 ///
11047 /// @param indent the prefix to use as indentation for the report.
11048 void
11049 translation_unit_diff::report(ostream& out, const string& indent) const
11050 {scope_diff::report(out, indent);}
11051
11052 /// Compute the diff between two translation_units.
11053 ///
11054 /// @param first the first translation_unit to consider.
11055 ///
11056 /// @param second the second translation_unit to consider.
11057 ///
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.
11060 ///
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)
11066 {
11067 if (!ctxt)
11068 ctxt.reset(new diff_context);
11069
11070 // TODO: handle first or second having empty contents.
11071 translation_unit_diff_sptr tu_diff(new translation_unit_diff(first, second,
11072 ctxt));
11073 scope_diff_sptr sc_diff = dynamic_pointer_cast<scope_diff>(tu_diff);
11074
11075 compute_diff(static_pointer_cast<scope_decl>(first->get_global_scope()),
11076 static_pointer_cast<scope_decl>(second->get_global_scope()),
11077 sc_diff,
11078 ctxt);
11079
11080 ctxt->initialize_canonical_diff(tu_diff);
11081
11082 return tu_diff;
11083 }
11084
11085 // </translation_unit_diff stuff>
11086
11087 /// The type of the private data of corpus_diff::diff_stats.
11088 class corpus_diff::diff_stats::priv
11089 {
11090 friend class corpus_diff::diff_stats;
11091
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;
11104
11105 priv()
11106 : num_func_removed(0),
11107 num_func_added(0),
11108 num_func_changed(0),
11109 num_func_filtered_out(0),
11110 num_vars_removed(0),
11111 num_vars_added(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)
11118 {}
11119 }; // end class corpus_diff::diff_stats::priv
11120
11121 /// Default constructor for the @ref diff_stat type.
11122 corpus_diff::diff_stats::diff_stats()
11123 : priv_(new priv)
11124 {}
11125
11126 /// Getter for the number of functions removed.
11127 ///
11128 /// @return the number of functions removed.
11129 size_t
11130 corpus_diff::diff_stats::num_func_removed() const
11131 {return priv_->num_func_removed;}
11132
11133 /// Setter for the number of functions removed.
11134 ///
11135 /// @param n the new number of functions removed.
11136 void
11137 corpus_diff::diff_stats::num_func_removed(size_t n)
11138 {priv_->num_func_removed = n;}
11139
11140 /// Getter for the number of functions added.
11141 ///
11142 /// @return the number of functions added.
11143 size_t
11144 corpus_diff::diff_stats::num_func_added() const
11145 {return priv_->num_func_added;}
11146
11147 /// Setter for the number of functions added.
11148 ///
11149 /// @param n the new number of functions added.
11150 void
11151 corpus_diff::diff_stats::num_func_added(size_t n)
11152 {priv_->num_func_added = n;}
11153
11154 /// Getter for the number of functions that have a change in one of
11155 /// their sub-types.
11156 ///
11157 /// @return the number of functions that have a change in one of their
11158 /// sub-types.
11159 size_t
11160 corpus_diff::diff_stats::num_func_changed() const
11161 {return priv_->num_func_changed;}
11162
11163 /// Setter for the number of functions that have a change in one of
11164 /// their sub-types.
11165 ///
11166 /// @@param n the new number of functions that have a change in one of
11167 /// their sub-types.
11168 void
11169 corpus_diff::diff_stats::num_func_changed(size_t n)
11170 {priv_->num_func_changed = n;}
11171
11172 /// Getter for the number of functions that have a change in one of
11173 /// their sub-types, and that have been filtered out.
11174 ///
11175 /// @return the number of functions that have a change in one of their
11176 /// sub-types, and that have been filtered out.
11177 size_t
11178 corpus_diff::diff_stats::num_func_filtered_out() const
11179 {return priv_->num_func_filtered_out;}
11180
11181 /// Setter for the number of functions that have a change in one of
11182 /// their sub-types, and that have been filtered out.
11183 ///
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.
11186 void
11187 corpus_diff::diff_stats::num_func_filtered_out(size_t n)
11188 {priv_->num_func_filtered_out = n;}
11189
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.
11193 ///
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.
11197 size_t
11198 corpus_diff::diff_stats::net_num_func_changed() const
11199 {return num_func_changed() - num_func_filtered_out();}
11200
11201 /// Getter for the number of variables removed.
11202 ///
11203 /// @return the number of variables removed.
11204 size_t
11205 corpus_diff::diff_stats::num_vars_removed() const
11206 {return priv_->num_vars_removed;}
11207
11208 /// Setter for the number of variables removed.
11209 ///
11210 /// @param n the new number of variables removed.
11211 void
11212 corpus_diff::diff_stats::num_vars_removed(size_t n)
11213 {priv_->num_vars_removed = n;}
11214
11215 /// Getter for the number of variables added.
11216 ///
11217 /// @return the number of variables added.
11218 size_t
11219 corpus_diff::diff_stats::num_vars_added() const
11220 {return priv_->num_vars_added;}
11221
11222 /// Setter for the number of variables added.
11223 ///
11224 /// @param n the new number of variables added.
11225 void
11226 corpus_diff::diff_stats::num_vars_added(size_t n)
11227 {priv_->num_vars_added = n;}
11228
11229 /// Getter for the number of variables that have a change in one of
11230 /// their sub-types.
11231 ///
11232 /// @return the number of variables that have a change in one of their
11233 /// sub-types.
11234 size_t
11235 corpus_diff::diff_stats::num_vars_changed() const
11236 {return priv_->num_vars_changed;}
11237
11238 /// Setter for the number of variables that have a change in one of
11239 /// their sub-types.
11240 ///
11241 /// @param n the new number of variables that have a change in one of
11242 /// their sub-types.
11243 void
11244 corpus_diff::diff_stats::num_vars_changed(size_t n)
11245 {priv_->num_vars_changed = n;}
11246
11247 /// Getter for the number of variables that have a change in one of
11248 /// their sub-types, and that have been filtered out.
11249 ///
11250 /// @return the number of functions that have a change in one of their
11251 /// sub-types, and that have been filtered out.
11252 size_t
11253 corpus_diff::diff_stats::num_vars_filtered_out() const
11254 {return priv_->num_vars_filtered_out;}
11255
11256 /// Setter for the number of variables that have a change in one of
11257 /// their sub-types, and that have been filtered out.
11258 ///
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.
11261 void
11262 corpus_diff::diff_stats::num_vars_filtered_out(size_t n)
11263 {priv_->num_vars_filtered_out = n;}
11264
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.
11268 ///
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.
11272 size_t
11273 corpus_diff::diff_stats::net_num_vars_changed() const
11274 {return num_vars_changed() - num_vars_filtered_out();}
11275
11276 /// Getter for the number of function symbols (not referenced by any
11277 /// debug info) that got removed.
11278 ///
11279 /// @return the number of function symbols (not referenced by any
11280 /// debug info) that got removed.
11281 size_t
11282 corpus_diff::diff_stats::num_func_syms_removed() const
11283 {return priv_->num_func_syms_removed;}
11284
11285 /// Setter for the number of function symbols (not referenced by any
11286 /// debug info) that got removed.
11287 ///
11288 /// @param n the number of function symbols (not referenced by any
11289 /// debug info) that got removed.
11290 void
11291 corpus_diff::diff_stats::num_func_syms_removed(size_t n)
11292 {priv_->num_func_syms_removed = n;}
11293
11294 /// Getter for the number of function symbols (not referenced by any
11295 /// debug info) that got added.
11296 ///
11297 /// @return the number of function symbols (not referenced by any
11298 /// debug info) that got added.
11299 size_t
11300 corpus_diff::diff_stats::num_func_syms_added() const
11301 {return priv_->num_func_syms_added;}
11302
11303 /// Setter for the number of function symbols (not referenced by any
11304 /// debug info) that got added.
11305 ///
11306 /// @param n the new number of function symbols (not referenced by any
11307 /// debug info) that got added.
11308 void
11309 corpus_diff::diff_stats::num_func_syms_added(size_t n)
11310 {priv_->num_func_syms_added = n;}
11311
11312 /// Getter for the number of variable symbols (not referenced by any
11313 /// debug info) that got removed.
11314 ///
11315 /// @return the number of variable symbols (not referenced by any
11316 /// debug info) that got removed.
11317 size_t
11318 corpus_diff::diff_stats::num_var_syms_removed() const
11319 {return priv_->num_var_syms_removed;}
11320
11321 /// Setter for the number of variable symbols (not referenced by any
11322 /// debug info) that got removed.
11323 ///
11324 /// @param n the number of variable symbols (not referenced by any
11325 /// debug info) that got removed.
11326 void
11327 corpus_diff::diff_stats::num_var_syms_removed(size_t n)
11328 {priv_->num_var_syms_removed = n;}
11329
11330 /// Getter for the number of variable symbols (not referenced by any
11331 /// debug info) that got added.
11332 ///
11333 /// @return the number of variable symbols (not referenced by any
11334 /// debug info) that got added.
11335 size_t
11336 corpus_diff::diff_stats::num_var_syms_added() const
11337 {return priv_->num_var_syms_added;}
11338
11339 /// Setter for the number of variable symbols (not referenced by any
11340 /// debug info) that got added.
11341 ///
11342 /// @param n the new number of variable symbols (not referenced by any
11343 /// debug info) that got added.
11344 void
11345 corpus_diff::diff_stats::num_var_syms_added(size_t n)
11346 {priv_->num_var_syms_added = n;}
11347
11348 // <corpus stuff>
11349 struct corpus_diff::priv
11350 {
11351 bool finished_;
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_;
11377
11378 priv()
11379 : finished_(false),
11380 filters_and_suppr_applied_(false),
11381 sonames_equal_(false),
11382 architectures_equal_(false)
11383 {}
11384
11385 bool
11386 lookup_tables_empty() const;
11387
11388 void
11389 clear_lookup_tables();
11390
11391 void
11392 ensure_lookup_tables_populated();
11393
11394 void
11395 apply_filters_and_compute_diff_stats(corpus_diff::diff_stats&);
11396
11397 void
11398 emit_diff_stats(const diff_stats& stats,
11399 ostream& out,
11400 const string& indent);
11401
11402 void
11403 categorize_redundant_changed_sub_nodes();
11404
11405 void
11406 clear_redundancy_categorization();
11407
11408 void
11409 maybe_dump_diff_tree();
11410 }; // end corpus::priv
11411
11412 /// Tests if the lookup tables are empty.
11413 ///
11414 /// @return true if the lookup tables are empty, false otherwise.
11415 bool
11416 corpus_diff::priv::lookup_tables_empty() const
11417 {
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());
11424 }
11425
11426 /// Clear the lookup tables useful for reporting an enum_diff.
11427 void
11428 corpus_diff::priv::clear_lookup_tables()
11429 {
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();
11436 }
11437
11438 /// If the lookup tables are not yet built, walk the differences and
11439 /// fill the lookup tables.
11440 void
11441 corpus_diff::priv::ensure_lookup_tables_populated()
11442 {
11443 if (!lookup_tables_empty())
11444 return;
11445
11446 {
11447 edit_script& e = fns_edit_script_;
11448
11449 for (vector<deletion>::const_iterator it = e.deletions().begin();
11450 it != e.deletions().end();
11451 ++it)
11452 {
11453 unsigned i = it->index();
11454 assert(i < first_->get_functions().size());
11455
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;
11461 }
11462
11463 for (vector<insertion>::const_iterator it = e.insertions().begin();
11464 it != e.insertions().end();
11465 ++it)
11466 {
11467 for (vector<unsigned>::const_iterator iit =
11468 it->inserted_indexes().begin();
11469 iit != it->inserted_indexes().end();
11470 ++iit)
11471 {
11472 unsigned i = *iit;
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())
11480 {
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);
11487 }
11488 else
11489 added_fns_[n] = added_fn;
11490 }
11491 }
11492 sort_string_function_decl_diff_sptr_map(changed_fns_map_, changed_fns_);
11493
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.
11497
11498 vector<string> to_delete;
11499 for (string_function_ptr_map::const_iterator i = deleted_fns_.begin();
11500 i != deleted_fns_.end();
11501 ++i)
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);
11505
11506 for (vector<string>::const_iterator i = to_delete.begin();
11507 i != to_delete.end();
11508 ++i)
11509 deleted_fns_.erase(*i);
11510
11511 // Do something similar for added functions.
11512
11513 to_delete.clear();
11514 for (string_function_ptr_map::const_iterator i = added_fns_.begin();
11515 i != added_fns_.end();
11516 ++i)
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);
11520
11521 for (vector<string>::const_iterator i = to_delete.begin();
11522 i != to_delete.end();
11523 ++i)
11524 added_fns_.erase(*i);
11525 }
11526
11527 {
11528 edit_script& e = vars_edit_script_;
11529
11530 for (vector<deletion>::const_iterator it = e.deletions().begin();
11531 it != e.deletions().end();
11532 ++it)
11533 {
11534 unsigned i = it->index();
11535 assert(i < first_->get_variables().size());
11536
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;
11542 }
11543
11544 for (vector<insertion>::const_iterator it = e.insertions().begin();
11545 it != e.insertions().end();
11546 ++it)
11547 {
11548 for (vector<unsigned>::const_iterator iit =
11549 it->inserted_indexes().begin();
11550 iit != it->inserted_indexes().end();
11551 ++iit)
11552 {
11553 unsigned i = *iit;
11554 var_decl* added_var = second_->get_variables()[i];
11555 string n = added_var->get_id();
11556 assert(!n.empty());
11557 {
11558 string_var_ptr_map::const_iterator k = added_vars_.find(n);
11559 if ( k != added_vars_.end())
11560 {
11561 assert(is_member_decl(k->second)
11562 && get_member_is_static(k->second));
11563 continue;
11564 }
11565 }
11566 string_var_ptr_map::const_iterator j =
11567 deleted_vars_.find(n);
11568 if (j != deleted_vars_.end())
11569 {
11570 if (*j->second != *added_var)
11571 {
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_);
11575 }
11576 deleted_vars_.erase(j);
11577 }
11578 else
11579 added_vars_[n] = added_var;
11580 }
11581 }
11582 sort_string_var_diff_sptr_map(changed_vars_map_,
11583 sorted_changed_vars_);
11584
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.
11588
11589 vector<string> to_delete;
11590 for (string_var_ptr_map::const_iterator i = deleted_vars_.begin();
11591 i != deleted_vars_.end();
11592 ++i)
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);
11596
11597 for (vector<string>::const_iterator i = to_delete.begin();
11598 i != to_delete.end();
11599 ++i)
11600 deleted_fns_.erase(*i);
11601
11602 // Do something similar for added variables.
11603
11604 to_delete.clear();
11605 for (string_var_ptr_map::const_iterator i = added_vars_.begin();
11606 i != added_vars_.end();
11607 ++i)
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);
11611
11612 for (vector<string>::const_iterator i = to_delete.begin();
11613 i != to_delete.end();
11614 ++i)
11615 added_vars_.erase(*i);
11616 }
11617
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}.
11621 {
11622 edit_script& e = unrefed_fn_syms_edit_script_;
11623 for (vector<deletion>::const_iterator it = e.deletions().begin();
11624 it != e.deletions().end();
11625 ++it)
11626 {
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;
11634 }
11635
11636 for (vector<insertion>::const_iterator it = e.insertions().begin();
11637 it != e.insertions().end();
11638 ++it)
11639 {
11640 for (vector<unsigned>::const_iterator iit =
11641 it->inserted_indexes().begin();
11642 iit != it->inserted_indexes().end();
11643 ++iit)
11644 {
11645 unsigned i = *iit;
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()))
11651 {
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()] =
11655 added_sym;
11656 }
11657 else
11658 deleted_unrefed_fn_syms_.erase(added_sym->get_id_string());
11659 }
11660 }
11661 }
11662
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}.
11666 {
11667 edit_script& e = unrefed_var_syms_edit_script_;
11668 for (vector<deletion>::const_iterator it = e.deletions().begin();
11669 it != e.deletions().end();
11670 ++it)
11671 {
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;
11679 }
11680
11681 for (vector<insertion>::const_iterator it = e.insertions().begin();
11682 it != e.insertions().end();
11683 ++it)
11684 {
11685 for (vector<unsigned>::const_iterator iit =
11686 it->inserted_indexes().begin();
11687 iit != it->inserted_indexes().end();
11688 ++iit)
11689 {
11690 unsigned i = *iit;
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())
11696 {
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()] =
11700 added_sym;
11701 }
11702 else
11703 deleted_unrefed_var_syms_.erase(added_sym->get_id_string());
11704 }
11705 }
11706 }
11707 }
11708
11709 /// Compute the diff stats.
11710 ///
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.
11714 ///
11715 /// @param num_removed the number of removed functions.
11716 ///
11717 /// @param num_added the number of added functions.
11718 ///
11719 /// @param num_changed the number of changed functions.
11720 ///
11721 /// @param num_filtered_out the number of changed functions that are
11722 /// got filtered out from the report
11723 void
11724 corpus_diff::priv::apply_filters_and_compute_diff_stats(diff_stats& stat)
11725
11726 {
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());
11730
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());
11734
11735 // Walk the changed function diff nodes to apply the categorization
11736 // filters.
11737 diff_sptr diff;
11738 for (function_decl_diff_sptrs_type::const_iterator i =
11739 changed_fns_.begin();
11740 i != changed_fns_.end();
11741 ++i)
11742 {
11743 diff_sptr diff = *i;
11744 ctxt_->maybe_apply_filters(diff);
11745 }
11746
11747 // Walk the changed variable diff nodes to apply the categorization
11748 // filters.
11749 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11750 i != sorted_changed_vars_.end();
11751 ++i)
11752 {
11753 diff_sptr diff = *i;
11754 ctxt_->maybe_apply_filters(diff);
11755 }
11756
11757 categorize_redundant_changed_sub_nodes();
11758
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();
11764 ++i)
11765 if ((*i)->is_filtered_out())
11766 stat.num_func_filtered_out(stat.num_func_filtered_out() + 1);
11767
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();
11772 ++i)
11773 {
11774 if ((*i)->is_filtered_out())
11775 stat.num_vars_filtered_out(stat.num_vars_filtered_out() + 1);
11776 }
11777
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());
11782 }
11783
11784 /// Emit the summary of the functions & variables that got
11785 /// removed/changed/added.
11786 ///
11787 /// @param out the output stream to emit the stats to.
11788 ///
11789 /// @param indent the indentation string to use in the summary.
11790 void
11791 corpus_diff::priv::emit_diff_stats(const diff_stats& s,
11792 ostream& out,
11793 const string& indent)
11794 {
11795 /// Report added/removed/changed functions.
11796 size_t total = s.num_func_removed() + s.num_func_added() +
11797 s.net_num_func_changed();
11798
11799 if (!sonames_equal_)
11800 out << indent << "ELF SONAME changed\n";
11801
11802 if (!architectures_equal_)
11803 out << indent << "ELF architecture changed\n";
11804
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)";
11811 out << ", ";
11812 out << s.num_func_added() << " Added ";
11813 if (total <= 1)
11814 out << "function\n";
11815 else
11816 out << "functions\n";
11817
11818 total = s.num_vars_removed() + s.num_vars_added() +
11819 s.net_num_vars_changed();
11820
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)";
11827 out << ", ";
11828 out << s.num_vars_added() << " Added ";
11829 if (total <= 1)
11830 out << "variable\n";
11831 else
11832 out << "variables\n";
11833
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()))
11839 {
11840 // function symbols changes summary.
11841
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.
11848 ;
11849 else
11850 {
11851 out << indent
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)
11856 out << "s";
11857 out << " not referenced by debug info\n";
11858 }
11859
11860 // variable symbol changes summary.
11861
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.
11868 ;
11869 else
11870 {
11871 out << indent
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)
11876 out << "s";
11877 out << " not referenced by debug info\n";
11878 }
11879 }
11880 }
11881
11882 /// Walk the changed functions and variables diff nodes to categorize
11883 /// redundant nodes.
11884 void
11885 corpus_diff::priv::categorize_redundant_changed_sub_nodes()
11886 {
11887 diff_sptr diff;
11888
11889 ctxt_->forget_visited_diffs();
11890 for (function_decl_diff_sptrs_type::const_iterator i =
11891 changed_fns_.begin();
11892 i!= changed_fns_.end();
11893 ++i)
11894 {
11895 diff = *i;
11896 categorize_redundancy(diff);
11897 }
11898
11899 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11900 i!= sorted_changed_vars_.end();
11901 ++i)
11902 {
11903 diff_sptr diff = *i;
11904 categorize_redundancy(diff);
11905 }
11906 }
11907
11908 /// Walk the changed functions and variables diff nodes and clear the
11909 /// redundancy categorization they might carry.
11910 void
11911 corpus_diff::priv::clear_redundancy_categorization()
11912 {
11913 diff_sptr diff;
11914 for (function_decl_diff_sptrs_type::const_iterator i = changed_fns_.begin();
11915 i!= changed_fns_.end();
11916 ++i)
11917 {
11918 diff = *i;
11919 abigail::comparison::clear_redundancy_categorization(diff);
11920 }
11921
11922 for (var_diff_sptrs_type::const_iterator i = sorted_changed_vars_.begin();
11923 i!= sorted_changed_vars_.end();
11924 ++i)
11925 {
11926 diff = *i;
11927 abigail::comparison::clear_redundancy_categorization(diff);
11928 }
11929 }
11930
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
11933 /// that.
11934 ///
11935 /// This function is used for debugging purposes.
11936 void
11937 corpus_diff::priv::maybe_dump_diff_tree()
11938 {
11939 if (!ctxt_->dump_diff_tree()
11940 || ctxt_->error_output_stream() == 0)
11941 return;
11942
11943 if (!changed_fns_.empty())
11944 {
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();
11949 ++i)
11950 {
11951 diff_sptr d = *i;
11952 print_diff_tree(d, *ctxt_->error_output_stream());
11953 }
11954 }
11955
11956 if (!sorted_changed_vars_.empty())
11957 {
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();
11962 ++i)
11963 {
11964 diff_sptr d = *i;
11965 print_diff_tree(d, *ctxt_->error_output_stream());
11966 }
11967 }
11968 }
11969
11970 /// Populate the vector of children node of the @ref corpus_diff type.
11971 ///
11972 /// The children node can then later be retrieved using
11973 /// corpus_diff::children_node().
11974 void
11975 corpus_diff::chain_into_hierarchy()
11976 {
11977 for (function_decl_diff_sptrs_type::const_iterator i =
11978 changed_functions_sorted().begin();
11979 i != changed_functions_sorted().end();
11980 ++i)
11981 if (diff_sptr d = *i)
11982 append_child_node(d);
11983 }
11984
11985 /// Constructor for @ref corpus_diff.
11986 ///
11987 /// @param first the first corpus of the diff.
11988 ///
11989 /// @param second the second corpus of the diff.
11990 ///
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)
11995 : priv_(new priv)
11996 {
11997 priv_->first_ = first;
11998 priv_->second_ = second;
11999 priv_->ctxt_ = ctxt;
12000 }
12001
12002 /// Finish building the current instance of @ref corpus_diff.
12003 void
12004 corpus_diff::finish_diff_type()
12005 {
12006 if (priv_->finished_)
12007 return;
12008 chain_into_hierarchy();
12009 priv_->finished_ = true;
12010 }
12011
12012 /// @return the first corpus of the diff.
12013 corpus_sptr
12014 corpus_diff::first_corpus() const
12015 {return priv_->first_;}
12016
12017 /// @return the second corpus of the diff.
12018 corpus_sptr
12019 corpus_diff::second_corpus() const
12020 {return priv_->second_;}
12021
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_;}
12026
12027 /// Append a new child node to the vector of childre nodes for the
12028 /// current instance of @ref corpus_diff node.
12029 ///
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.
12033 void
12034 corpus_diff::append_child_node(diff_sptr d)
12035 {
12036 assert(d);
12037 priv_->children_.push_back(d);
12038
12039 diff_less_than_functor comp;
12040 std::sort(priv_->children_.begin(),
12041 priv_->children_.end(),
12042 comp);
12043 }
12044
12045 /// @return the bare edit script of the functions changed as recorded
12046 /// by the diff.
12047 edit_script&
12048 corpus_diff::function_changes() const
12049 {return priv_->fns_edit_script_;}
12050
12051 /// @return the bare edit script of the variables changed as recorded
12052 /// by the diff.
12053 edit_script&
12054 corpus_diff::variable_changes() const
12055 {return priv_->vars_edit_script_;}
12056
12057 /// Test if the soname of the underlying corpus has changed.
12058 ///
12059 /// @return true iff the soname has changed.
12060 bool
12061 corpus_diff::soname_changed() const
12062 {return !priv_->sonames_equal_;}
12063
12064 /// Test if the architecture of the underlying corpus has changed.
12065 ///
12066 /// @return true iff the architecture has changed.
12067 bool
12068 corpus_diff::architecture_changed() const
12069 {return !priv_->architectures_equal_;}
12070
12071 /// Getter for the deleted functions of the diff.
12072 ///
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_;}
12077
12078 /// Getter for the added functions of the diff.
12079 ///
12080 /// @return the added functions of the diff.
12081 const string_function_ptr_map&
12082 corpus_diff::added_functions()
12083 {return priv_->added_fns_;}
12084
12085 /// Getter for the functions which signature didn't change, but which
12086 /// do have some indirect changes in their parms.
12087 ///
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_;}
12096
12097 /// Getter for a sorted vector of functions which signature didn't
12098 /// change, but which do have some indirect changes in their parms.
12099 ///
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_;}
12105
12106 /// Getter for the variables that got deleted from the first subject
12107 /// of the diff.
12108 ///
12109 /// @return the map of deleted variable.
12110 const string_var_ptr_map&
12111 corpus_diff::deleted_variables() const
12112 {return priv_->deleted_vars_;}
12113
12114 /// Getter for the added variables of the diff.
12115 ///
12116 /// @return the map of added variable.
12117 const string_var_ptr_map&
12118 corpus_diff::added_variables() const
12119 {return priv_->added_vars_;}
12120
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.
12123 ///
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_;}
12128
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.
12131 ///
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_;}
12136
12137 /// Getter for function symbols not referenced by any debug info and
12138 /// that got deleted.
12139 ///
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_;}
12145
12146 /// Getter for function symbols not referenced by any debug info and
12147 /// that got added.
12148 ///
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_;}
12154
12155 /// Getter for variable symbols not referenced by any debug info and
12156 /// that got deleted.
12157 ///
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_;}
12163
12164 /// Getter for variable symbols not referenced by any debug info and
12165 /// that got added.
12166 ///
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_;}
12172
12173 /// Getter of the diff context of this diff
12174 ///
12175 /// @return the diff context for this diff.
12176 const diff_context_sptr
12177 corpus_diff::context() const
12178 {return priv_->ctxt_;}
12179
12180 /// @return the pretty representation for the current instance of @ref
12181 /// corpus_diff
12182 const string&
12183 corpus_diff::get_pretty_representation() const
12184 {
12185 if (priv_->pretty_representation_.empty())
12186 {
12187 std::ostringstream o;
12188 o << "corpus_diff["
12189 << first_corpus()->get_path()
12190 << ", "
12191 << second_corpus()->get_path()
12192 << "]";
12193 priv_->pretty_representation_ = o.str();
12194 }
12195 return priv_->pretty_representation_;
12196 }
12197 /// Return true iff the current diff node carries a change.
12198 ///
12199 /// @return true iff the current diff node carries a change.
12200 bool
12201 corpus_diff::has_changes() const
12202 {
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());
12215 }
12216
12217 /// "Less than" functor to compare instances of @ref function_decl.
12218 struct function_comp
12219 {
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.
12223 ///
12224 /// @param f the first @ref function_decl to take in account.
12225 ///
12226 /// @param s the second @ref function_decl to take in account.
12227 ///
12228 /// @return true iff @p f is less than @p s.
12229 bool
12230 operator()(const function_decl& f, const function_decl& s)
12231 {
12232 string fr = f.get_pretty_representation_of_declarator(),
12233 sr = s.get_pretty_representation_of_declarator();
12234
12235 if (fr != sr)
12236 return fr < sr;
12237
12238 fr = f.get_pretty_representation(),
12239 sr = f.get_pretty_representation();
12240
12241 if (fr != sr)
12242 return fr < sr;
12243
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();
12248
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();
12253
12254 return fr < sr;
12255 }
12256
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.
12260 ///
12261 /// @param f the first @ref function_decl to take in account.
12262 ///
12263 /// @param s the second @ref function_decl to take in account.
12264 ///
12265 /// @return true iff @p f is less than @p s.
12266 bool
12267 operator()(const function_decl* f, const function_decl* s)
12268 {return operator()(*f, *s);}
12269
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.
12273 ///
12274 /// @param f the first @ref function_decl to take in account.
12275 ///
12276 /// @param s the second @ref function_decl to take in account.
12277 ///
12278 /// @return true iff @p f is less than @p s.
12279 bool
12280 operator()(const function_decl_sptr f, const function_decl_sptr s)
12281 {return operator()(f.get(), s.get());}
12282 }; // end function_comp
12283
12284 /// Sort a an instance of @ref string_function_ptr_map map and stuff
12285 /// a resulting sorted vector of pointers to function_decl.
12286 ///
12287 /// @param map the map to sort.
12288 ///
12289 /// @param sorted the resulting sorted vector.
12290 static void
12291 sort_string_function_ptr_map(const string_function_ptr_map& map,
12292 vector<function_decl*>& sorted)
12293 {
12294 sorted.reserve(map.size());
12295 for (string_function_ptr_map::const_iterator i = map.begin();
12296 i != map.end();
12297 ++i)
12298 sorted.push_back(i->second);
12299
12300 function_comp comp;
12301 std::sort(sorted.begin(), sorted.end(), comp);
12302 }
12303
12304 /// A "Less Than" functor to compare instance of @ref
12305 /// function_decl_diff.
12306 struct function_decl_diff_comp
12307 {
12308 /// The actual less than operator.
12309 ///
12310 /// It returns true if the first @ref function_decl_diff is less
12311 /// than the second one.
12312 ///
12313 /// param first the first @ref function_decl_diff to consider.
12314 ///
12315 /// @param second the second @ref function_decl_diff to consider.
12316 ///
12317 /// @return true iff @p first is less than @p second.
12318 bool
12319 operator()(const function_decl_diff& first,
12320 const function_decl_diff& second)
12321 {
12322 function_decl_sptr f = first.first_function_decl(),
12323 s = second.first_function_decl();
12324
12325 string fr = f->get_qualified_name(),
12326 sr = s->get_qualified_name();
12327
12328 if (fr == sr)
12329 {
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();
12334 else
12335 fr = f->get_pretty_representation();
12336
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();
12341 else
12342 sr = s->get_pretty_representation();
12343 }
12344
12345 return (fr.compare(sr) < 0);
12346 }
12347
12348 /// The actual less than operator.
12349 ///
12350 /// It returns true if the first @ref function_decl_diff_sptr is
12351 /// less than the second one.
12352 ///
12353 /// param first the first @ref function_decl_diff_sptr to consider.
12354 ///
12355 /// @param second the second @ref function_decl_diff_sptr to
12356 /// consider.
12357 ///
12358 /// @return true iff @p first is less than @p second.
12359 bool
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
12364
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
12367 /// objects.
12368 ///
12369 /// @param map the map whose values to store.
12370 ///
12371 /// @param sorted the vector of function_decl_diff_sptr to store the
12372 /// result of the sort into.
12373 static void
12374 sort_string_function_decl_diff_sptr_map
12375 (const string_function_decl_diff_sptr_map& map,
12376 function_decl_diff_sptrs_type& sorted)
12377 {
12378 sorted.reserve(map.size());
12379 for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
12380 i != map.end();
12381 ++i)
12382 sorted.push_back(i->second);
12383 function_decl_diff_comp comp;
12384 std::sort(sorted.begin(), sorted.end(), comp);
12385 }
12386
12387 /// Functor to sort instances of @ref var_diff_sptr
12388 struct var_diff_sptr_comp
12389 {
12390 /// Return true if the first argument is less than the second one.
12391 ///
12392 /// @param f the first argument to consider.
12393 ///
12394 /// @param s the second argument to consider.
12395 ///
12396 /// @return true if @p f is less than @p s.
12397 bool
12398 operator()(const var_diff_sptr f,
12399 const var_diff_sptr s)
12400 {
12401 return (f->first_var()->get_qualified_name()
12402 < s->first_var()->get_qualified_name());
12403 }
12404 }; // end struct var_diff_sptr_comp
12405
12406 /// Sort of an instance of @ref string_var_diff_sptr_map map.
12407 ///
12408 /// @param map the input map to sort.
12409 ///
12410 /// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
12411 /// It's populated with the sorted content.
12412 static void
12413 sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
12414 var_diff_sptrs_type& sorted)
12415 {
12416 sorted.reserve(map.size());
12417 for (string_var_diff_sptr_map::const_iterator i = map.begin();
12418 i != map.end();
12419 ++i)
12420 sorted.push_back(i->second);
12421
12422 var_diff_sptr_comp comp;
12423 std::sort(sorted.begin(), sorted.end(), comp);
12424 }
12425
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.
12428 ///
12429 /// @param out the output string to emit the resulting string to.
12430 ///
12431 /// @param indent the indentation string to use before emitting the
12432 /// resulting string.
12433 ///
12434 /// @param symbol the symbol to emit the representation string for.
12435 ///
12436 /// @param sym_map the symbol map to consider to look for aliases of
12437 /// @p symbol.
12438 static void
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)
12443 {
12444 out << indent << symbol.get_id_string();
12445 string aliases =
12446 symbol.get_aliases_id_string(sym_map,
12447 /*include_symbol_itself=*/false);
12448 if (!aliases.empty())
12449 out << ", aliases " << aliases;
12450 }
12451
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.
12455 ///
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.
12460 ///
12461 /// This member function is called by the reporting function
12462 /// corpus_diff::report().
12463 ///
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
12468 /// invocation.
12469 ///
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()
12474 {
12475 if (priv_->filters_and_suppr_applied_)
12476 return priv_->diff_stats_;
12477
12478 apply_suppressions(this);
12479 priv_->apply_filters_and_compute_diff_stats(priv_->diff_stats_);
12480
12481 priv_->filters_and_suppr_applied_ = true;
12482
12483 return priv_->diff_stats_;
12484 }
12485
12486 /// Report the diff in a serialized form.
12487 ///
12488 /// @param out the stream to serialize the diff to.
12489 ///
12490 /// @param indent the prefix to use for the indentation of this
12491 /// serialization.
12492 void
12493 corpus_diff::report(ostream& out, const string& indent) const
12494 {
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();
12498
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;
12503
12504 priv_->emit_diff_stats(s, out, indent);
12505 if (context()->show_stats_only())
12506 return;
12507 out << "\n";
12508
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";
12514
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";
12520
12521 if (context()->show_deleted_fns())
12522 {
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";
12527
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();
12533 ++i)
12534 {
12535 out << indent
12536 << " ";
12537 if (total > large_num)
12538 out << "[D] ";
12539 out << "'" << (*i)->get_pretty_representation() << "'";
12540 if (context()->show_linkage_names())
12541 {
12542 out << " {";
12543 show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
12544 first_corpus()->get_fun_symbol_map());
12545 out << "}";
12546 }
12547 out << "\n";
12548 ++removed;
12549 }
12550 if (removed)
12551 out << "\n";
12552 }
12553
12554 if (context()->show_added_fns())
12555 {
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();
12565 ++i)
12566 {
12567 out
12568 << indent
12569 << " ";
12570 if (total > large_num)
12571 out << "[A] ";
12572 out << "'"
12573 << (*i)->get_pretty_representation()
12574 << "'";
12575 if (context()->show_linkage_names())
12576 {
12577 out << " {";
12578 show_linkage_name_and_aliases
12579 (out, "", *(*i)->get_symbol(),
12580 second_corpus()->get_fun_symbol_map());
12581 out << "}";
12582 }
12583 out << "\n";
12584 ++added;
12585 }
12586 if (added)
12587 {
12588 out << "\n";
12589 added = false;
12590 }
12591 }
12592
12593 if (context()->show_changed_fns())
12594 {
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";
12601
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();
12609 ++i)
12610 {
12611 diff_sptr diff = *i;
12612 if (!diff)
12613 continue;
12614
12615 if (diff->to_be_reported())
12616 {
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 + " ");
12621 out << "\n";
12622 emitted |= true;
12623 }
12624 }
12625 if (emitted)
12626 {
12627 out << "\n";
12628 emitted = false;
12629 }
12630 }
12631
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();
12635
12636 if (context()->show_deleted_vars())
12637 {
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";
12643 string n;
12644 for (string_var_ptr_map::const_iterator i =
12645 priv_->deleted_vars_.begin();
12646 i != priv_->deleted_vars_.end();
12647 ++i)
12648 {
12649 n = i->second->get_pretty_representation();
12650 out << indent
12651 << " ";
12652 if (total > large_num)
12653 out << "[D] ";
12654 out << "'"
12655 << n
12656 << "'";
12657 if (context()->show_linkage_names())
12658 {
12659 out << " {";
12660 show_linkage_name_and_aliases(out, "", *i->second->get_symbol(),
12661 first_corpus()->get_var_symbol_map());
12662 out << "}";
12663 }
12664 out << "\n";
12665 ++removed;
12666 }
12667 if (removed)
12668 {
12669 out << "\n";
12670 removed = 0;
12671 }
12672 }
12673
12674 if (context()->show_added_vars())
12675 {
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";
12681 string n;
12682 for (string_var_ptr_map::const_iterator i =
12683 priv_->added_vars_.begin();
12684 i != priv_->added_vars_.end();
12685 ++i)
12686 {
12687 n = i->second->get_pretty_representation();
12688 out << indent
12689 << " ";
12690 if (total > large_num)
12691 out << "[A] ";
12692 out << "'" << n << "'";
12693 if (context()->show_linkage_names())
12694 {
12695 out << " {";
12696 show_linkage_name_and_aliases(out, "", *i->second->get_symbol(),
12697 second_corpus()->get_var_symbol_map());
12698 out << "}";
12699 }
12700 out << "\n";
12701 ++added;
12702 }
12703 if (added)
12704 {
12705 out << "\n";
12706 added = 0;
12707 }
12708 }
12709
12710 if (context()->show_changed_vars())
12711 {
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";
12718 string n1, n2;
12719
12720 for (var_diff_sptrs_type::const_iterator i =
12721 priv_->sorted_changed_vars_.begin();
12722 i != priv_->sorted_changed_vars_.end();
12723 ++i)
12724 {
12725 diff_sptr diff = *i;
12726
12727 if (!diff)
12728 continue;
12729
12730 if (!diff->to_be_reported())
12731 continue;
12732
12733 n1 = diff->first_subject()->get_pretty_representation();
12734 n2 = diff->second_subject()->get_pretty_representation();
12735
12736 out << indent << " [C]'" << n1 << "' was changed";
12737 if (n1 != n2)
12738 out << " to '" << n2 << "'";
12739 out << ":\n";
12740 diff->report(out, indent + " ");
12741 out << "\n";
12742 }
12743 if (num_changed)
12744 out << "\n";
12745 }
12746
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())
12750 {
12751 if (s.num_func_syms_removed() == 1)
12752 out << indent
12753 << "1 Removed function symbol not referenced by debug info:\n\n";
12754 else if (s.num_func_syms_removed() > 0)
12755 out << indent
12756 << s.num_func_syms_removed()
12757 << " Removed function symbols not referenced by debug info:\n\n";
12758
12759 for (string_elf_symbol_map::const_iterator i =
12760 priv_->deleted_unrefed_fn_syms_.begin();
12761 i != priv_->deleted_unrefed_fn_syms_.end();
12762 ++i)
12763 {
12764 out << indent << " ";
12765 if (s.num_func_syms_removed() > large_num)
12766 out << "[D] ";
12767
12768 show_linkage_name_and_aliases(out, "", *i->second,
12769 first_corpus()->get_fun_symbol_map());
12770 out << "\n";
12771 }
12772 if (priv_->deleted_unrefed_fn_syms_.size())
12773 out << '\n';
12774 }
12775
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())
12779 {
12780 if (s.num_func_syms_added() == 1)
12781 out << indent
12782 << "1 Added function symbol not referenced by debug info:\n\n";
12783 else if (s.num_func_syms_added() > 0)
12784 out << indent
12785 << s.num_func_syms_added()
12786 << " Added function symbols not referenced by debug info:\n\n";
12787
12788 for (string_elf_symbol_map::const_iterator i =
12789 priv_->added_unrefed_fn_syms_.begin();
12790 i != priv_->added_unrefed_fn_syms_.end();
12791 ++i)
12792 {
12793 out << indent << " ";
12794 if (s.num_func_syms_added() > large_num)
12795 out << "[A] ";
12796 show_linkage_name_and_aliases(out, "",
12797 *i->second,
12798 second_corpus()->get_fun_symbol_map());
12799 out << "\n";
12800 }
12801 if (priv_->added_unrefed_fn_syms_.size())
12802 out << '\n';
12803 }
12804
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())
12808 {
12809 if (s.num_var_syms_removed() == 1)
12810 out << indent
12811 << "1 Removed variable symbol not referenced by debug info:\n\n";
12812 else if (s.num_var_syms_removed() > 0)
12813 out << indent
12814 << s.num_var_syms_removed()
12815 << " Removed variable symbols not referenced by debug info:\n\n";
12816
12817 for (string_elf_symbol_map::const_iterator i =
12818 priv_->deleted_unrefed_var_syms_.begin();
12819 i != priv_->deleted_unrefed_var_syms_.end();
12820 ++i)
12821 {
12822 out << indent << " ";
12823 if (s.num_var_syms_removed() > large_num)
12824 out << "[D] ";
12825
12826 show_linkage_name_and_aliases(out, "", *i->second,
12827 first_corpus()->get_fun_symbol_map());
12828 out << "\n";
12829 }
12830 if (priv_->deleted_unrefed_var_syms_.size())
12831 out << '\n';
12832 }
12833
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())
12837 {
12838 if (s.num_var_syms_added() == 1)
12839 out << indent
12840 << "1 Added variable symbol not referenced by debug info:\n\n";
12841 else if (s.num_var_syms_added() > 0)
12842 out << indent
12843 << s.num_var_syms_added()
12844 << " Added variable symbols not referenced by debug info:\n\n";
12845
12846 for (string_elf_symbol_map::const_iterator i =
12847 priv_->added_unrefed_var_syms_.begin();
12848 i != priv_->added_unrefed_var_syms_.end();
12849 ++i)
12850 {
12851 out << indent << " ";
12852 if (s.num_var_syms_added() > large_num)
12853 out << "[A] ";
12854 show_linkage_name_and_aliases(out, "",
12855 *i->second,
12856 second_corpus()->get_fun_symbol_map());
12857 out << "\n";
12858 }
12859 if (priv_->added_unrefed_var_syms_.size())
12860 out << '\n';
12861 }
12862
12863 priv_->maybe_dump_diff_tree();
12864 }
12865
12866 /// Traverse the diff sub-tree under the current instance corpus_diff.
12867 ///
12868 /// @param v the visitor to invoke on each diff node of the sub-tree.
12869 ///
12870 /// @return true if the traversing has to keep going on, false otherwise.
12871 bool
12872 corpus_diff::traverse(diff_node_visitor& v)
12873 {
12874 finish_diff_type();
12875
12876 v.visit_begin(this);
12877
12878 if (!v.visit(this, true))
12879 {
12880 v.visit_end(this);
12881 return false;
12882 }
12883
12884 for (function_decl_diff_sptrs_type::const_iterator i =
12885 changed_functions_sorted().begin();
12886 i != changed_functions_sorted().end();
12887 ++i)
12888 {
12889 if (diff_sptr d = *i)
12890 {
12891 if (!d->traverse(v))
12892 {
12893 v.visit_end(this);
12894 return false;
12895 }
12896 }
12897 }
12898
12899 for (var_diff_sptrs_type::const_iterator i =
12900 changed_variables_sorted().begin();
12901 i != changed_variables_sorted().end();
12902 ++i)
12903 {
12904 if (diff_sptr d = *i)
12905 {
12906 if (!d->traverse(v))
12907 {
12908 v.visit_end(this);
12909 return false;
12910 }
12911 }
12912 }
12913
12914 v.visit_end(this);
12915 return true;
12916 }
12917
12918 /// Compute the diff between two instances fo the @ref corpus
12919 ///
12920 /// @param f the first @ref corpus to consider for the diff.
12921 ///
12922 /// @param s the second @ref corpus to consider for the diff.
12923 ///
12924 /// @param ctxt the diff context to use.
12925 ///
12926 /// @return the resulting diff between the two @ref corpus.
12927 corpus_diff_sptr
12928 compute_diff(const corpus_sptr f,
12929 const corpus_sptr s,
12930 diff_context_sptr ctxt)
12931 {
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;
12936
12937 if (!ctxt)
12938 ctxt.reset(new diff_context);
12939
12940 ctxt->set_corpora(f, s);
12941
12942 corpus_diff_sptr r(new corpus_diff(f, s, ctxt));
12943
12944 r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
12945
12946 r->priv_->architectures_equal_ =
12947 f->get_architecture_name() == s->get_architecture_name();
12948
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_);
12954
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_);
12959
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_);
12966
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_);
12973
12974 r->priv_->ensure_lookup_tables_populated();
12975
12976 return r;
12977 }
12978
12979 // </corpus stuff>
12980
12981 // <diff_node_visitor stuff>
12982
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
12985 /// node.
12986 ///
12987 /// @param d the diff node to visit.
12988 void
12989 diff_node_visitor::visit_begin(diff* /*p*/)
12990 {}
12991
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
12994 /// nodes.
12995 ///
12996 /// @param d the diff node that got visited.
12997 void
12998 diff_node_visitor::visit_end(diff* /*p*/)
12999 {}
13000
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
13003 /// children node.
13004 ///
13005 /// @param p the corpus_diff node to visit.
13006 ///
13007 void
13008 diff_node_visitor::visit_begin(corpus_diff* /*p*/)
13009 {}
13010
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
13013 /// nodes.
13014 ///
13015 /// @param d the diff node that got visited.
13016 void
13017 diff_node_visitor::visit_end(corpus_diff* /*d*/)
13018 {}
13019
13020 /// Default visitor implementation
13021 ///
13022 /// @return true
13023 bool
13024 diff_node_visitor::visit(diff*, bool)
13025 {return true;}
13026
13027 /// Default visitor implementation.
13028 ///
13029 /// @return true
13030 bool
13031 diff_node_visitor::visit(distinct_diff* dif, bool pre)
13032 {
13033 diff* d = dif;
13034 visit(d, pre);
13035
13036 return true;
13037 }
13038
13039 /// Default visitor implementation.
13040 ///
13041 /// @return true
13042 bool
13043 diff_node_visitor::visit(var_diff* dif, bool pre)
13044 {
13045 diff* d = dif;
13046 visit(d, pre);
13047
13048 return true;
13049 }
13050
13051 /// Default visitor implementation.
13052 ///
13053 /// @return true
13054 bool
13055 diff_node_visitor::visit(pointer_diff* dif, bool pre)
13056 {
13057 diff* d = dif;
13058 visit(d, pre);
13059
13060 return true;
13061 }
13062
13063 /// Default visitor implementation.
13064 ///
13065 /// @return true
13066 bool
13067 diff_node_visitor::visit(reference_diff* dif, bool pre)
13068 {
13069 diff* d = dif;
13070 visit(d, pre);
13071
13072 return true;
13073 }
13074
13075 /// Default visitor implementation.
13076 ///
13077 /// @return true
13078 bool
13079 diff_node_visitor::visit(qualified_type_diff* dif, bool pre)
13080 {
13081 diff* d = dif;
13082 visit(d, pre);
13083
13084 return true;
13085 }
13086
13087 /// Default visitor implementation.
13088 ///
13089 /// @return true
13090 bool
13091 diff_node_visitor::visit(enum_diff* dif, bool pre)
13092 {
13093 diff* d = dif;
13094 visit(d, pre);
13095
13096 return true;
13097 }
13098
13099 /// Default visitor implementation.
13100 ///
13101 /// @return true
13102 bool
13103 diff_node_visitor::visit(class_diff* dif, bool pre)
13104 {
13105 diff* d = dif;
13106 visit(d, pre);
13107
13108 return true;
13109 }
13110
13111 /// Default visitor implementation.
13112 ///
13113 /// @return true
13114 bool
13115 diff_node_visitor::visit(base_diff* dif, bool pre)
13116 {
13117 diff* d = dif;
13118 visit(d, pre);
13119
13120 return true;
13121 }
13122
13123 /// Default visitor implementation.
13124 ///
13125 /// @return true
13126 bool
13127 diff_node_visitor::visit(scope_diff* dif, bool pre)
13128 {
13129 diff* d = dif;
13130 visit(d, pre);
13131
13132 return true;
13133 }
13134
13135 /// Default visitor implementation.
13136 ///
13137 /// @return true
13138 bool
13139 diff_node_visitor::visit(function_decl_diff* dif, bool pre)
13140 {
13141 diff* d = dif;
13142 visit(d, pre);
13143
13144 return true;
13145 }
13146
13147 /// Default visitor implementation.
13148 ///
13149 /// @return true
13150 bool
13151 diff_node_visitor::visit(type_decl_diff* dif, bool pre)
13152 {
13153 diff* d = dif;
13154 visit(d, pre);
13155
13156 return true;
13157 }
13158
13159 /// Default visitor implementation.
13160 ///
13161 /// @return true
13162 bool
13163 diff_node_visitor::visit(typedef_diff* dif, bool pre)
13164 {
13165 diff* d = dif;
13166 visit(d, pre);
13167
13168 return true;
13169 }
13170
13171 /// Default visitor implementation.
13172 ///
13173 /// @return true
13174 bool
13175 diff_node_visitor::visit(translation_unit_diff* dif, bool pre)
13176 {
13177 diff* d = dif;
13178 visit(d, pre);
13179
13180 return true;
13181 }
13182
13183 /// Default visitor implementation.
13184 ///
13185 /// @return true
13186 bool
13187 diff_node_visitor::visit(corpus_diff*, bool)
13188 {return true;}
13189
13190 // </diff_node_visitor stuff>
13191
13192 // <redundant diff node marking>
13193
13194 // </redundant diff node marking>
13195
13196 // <diff tree category propagation>
13197
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
13202 {
13203 virtual void
13204 visit_end(diff* d)
13205 {
13206 // Has this diff node 'd' been already visited ?
13207 bool already_visited = d->context()->diff_has_been_visited(d);
13208
13209 // The canonical diff node of the class of equivalence of the diff
13210 // node 'd'.
13211 diff* canonical = d->get_canonical_diff();
13212
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;
13216
13217 for (vector<diff_sptr>::const_iterator i = d->children_nodes().begin();
13218 i != d->children_nodes().end();
13219 ++i)
13220 {
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'.
13224 //
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()
13230 : (*i).get();
13231
13232 assert(diff);
13233
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);
13240 }
13241 }
13242 };// end struct category_propagation_visitor
13243
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
13246 /// parent nodes.
13247 ///
13248 /// @param diff_tree the diff sub-tree to walk for categorization
13249 /// purpose;
13250 void
13251 propagate_categories(diff* diff_tree)
13252 {
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);
13259 }
13260
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
13263 /// parent nodes.
13264 ///
13265 /// @param diff_tree the diff sub-tree to walk for categorization
13266 /// purpose;
13267 void
13268 propagate_categories(diff_sptr diff_tree)
13269 {propagate_categories(diff_tree.get());}
13270
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.
13274 ///
13275 /// @param diff_tree the corpus_diff tree to walk for categorization
13276 /// purpose;
13277 void
13278 propagate_categories(corpus_diff* diff_tree)
13279 {
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);
13285 }
13286
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.
13290 ///
13291 /// @param diff_tree the corpus_diff tree to walk for categorization
13292 /// purpose;
13293 void
13294 propagate_categories(corpus_diff_sptr diff_tree)
13295 {propagate_categories(diff_tree.get());}
13296
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
13301 {
13302
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.
13306 ///
13307 /// @param p the diff node to visit.
13308 virtual void
13309 visit_begin(diff* d)
13310 {
13311 if (d->is_suppressed())
13312 d->add_to_local_and_inherited_categories(SUPPRESSED_CATEGORY);
13313 }
13314
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.
13318 ///
13319 /// That is, if all children nodes carry a suppressed change the
13320 /// current node should be marked as suppressed as well.
13321 ///
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.
13326 ///
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.
13329 virtual void
13330 visit_end(diff* d)
13331 {
13332 bool has_non_suppressed_child = false;
13333 bool has_non_empty_child = false;
13334 bool has_suppressed_child = false;
13335
13336 if (!(d->get_category() & SUPPRESSED_CATEGORY)
13337 && !d->has_local_changes())
13338 {
13339 for (vector<diff_sptr>::const_iterator i = d->children_nodes().begin();
13340 i != d->children_nodes().end();
13341 ++i)
13342 {
13343 diff_sptr child = *i;
13344 if (child->has_changes())
13345 {
13346 has_non_empty_child = true;
13347 if (child->get_category() & SUPPRESSED_CATEGORY)
13348 has_suppressed_child = true;
13349 else
13350 has_non_suppressed_child = true;
13351 }
13352 }
13353
13354 if (has_non_empty_child
13355 && has_suppressed_child
13356 && !has_non_suppressed_child)
13357 d->add_to_category(SUPPRESSED_CATEGORY);
13358 }
13359 }
13360 }; //end struct suppression_categorization_visitor
13361
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.
13366 ///
13367 /// @param diff_tree the diff-sub tree to apply the suppressions to.
13368 void
13369 apply_suppressions(diff* diff_tree)
13370 {
13371 if (diff_tree && !diff_tree->context()->suppressions().empty())
13372 {
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);
13378 }
13379 }
13380
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.
13385 ///
13386 /// @param diff_tree the diff-sub tree to apply the suppressions to.
13387 void
13388 apply_suppressions(diff_sptr diff_tree)
13389 {apply_suppressions(diff_tree.get());}
13390
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.
13395 ///
13396 /// @param diff_tree the diff tree to apply the suppressions to.
13397 void
13398 apply_suppressions(const corpus_diff* diff_tree)
13399 {
13400 if (diff_tree && !diff_tree->context()->suppressions().empty())
13401 {
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);
13407 }
13408 }
13409
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.
13414 ///
13415 /// @param diff_tree the diff tree to apply the suppressions to.
13416 void
13417 apply_suppressions(corpus_diff_sptr diff_tree)
13418 {apply_suppressions(diff_tree.get());}
13419
13420 // </diff tree category propagation>
13421
13422 // <diff tree printing stuff>
13423
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
13427 {
13428 ostream& out_;
13429 unsigned level_;
13430
13431 /// Emit a certain number of spaces to the output stream associated
13432 /// to this diff_node_printer.
13433 ///
13434 /// @param level half of the numver of spaces to emit.
13435 void
13436 do_indent(unsigned level)
13437 {
13438 for (unsigned i = 0; i < level; ++i)
13439 out_ << " ";
13440 }
13441
13442 diff_node_printer(ostream& out)
13443 : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
13444 out_(out),
13445 level_(0)
13446 {}
13447
13448 virtual void
13449 visit_begin(diff*)
13450 {
13451 ++level_;
13452 }
13453
13454 virtual void
13455 visit_end(diff*)
13456 {
13457 --level_;
13458 }
13459
13460 virtual void
13461 visit_begin(corpus_diff*)
13462 {
13463 ++level_;
13464 }
13465
13466 virtual void
13467 visit_end(corpus_diff*)
13468 {
13469 --level_;
13470 }
13471
13472 virtual bool
13473 visit(diff* d, bool pre)
13474 {
13475 if (!pre)
13476 // We are post-visiting the diff node D. Which means, we have
13477 // printed a pretty representation for it already. So do
13478 // nothing now.
13479 return true;
13480
13481 do_indent(level_);
13482 out_ << d->get_pretty_representation();
13483 out_ << "\n";
13484 do_indent(level_);
13485 out_ << "{\n";
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";
13494 do_indent(level_);
13495 out_ << "}\n";
13496
13497 return true;
13498 }
13499
13500 virtual bool
13501 visit(corpus_diff* d, bool pre)
13502 {
13503 if (!pre)
13504 // We are post-visiting the diff node D. Which means, we have
13505 // printed a pretty representation for it already. So do
13506 // nothing now.
13507 return true;
13508
13509 // indent
13510 for (unsigned i = 0; i < level_; ++i)
13511 out_ << ' ';
13512 out_ << d->get_pretty_representation();
13513 out_ << '\n';
13514 return true;
13515 }
13516 }; // end struct diff_printer_visitor
13517
13518 // </ diff tree printing stuff>
13519
13520 /// Emit a textual representation of a @ref diff sub-tree to an
13521 /// output stream.
13522 ///
13523 /// @param diff_tree the sub-tree to emit the textual representation
13524 /// for.
13525 ///
13526 /// @param out the output stream to emit the textual representation
13527 /// for @p diff_tree to.
13528 void
13529 print_diff_tree(diff* diff_tree, ostream& out)
13530 {
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);
13536 }
13537
13538 /// Emit a textual representation of a @ref corpus_diff tree to an
13539 /// output stream.
13540 ///
13541 /// @param diff_tree the @ref corpus_diff tree to emit the textual
13542 /// representation for.
13543 ///
13544 /// @param out the output stream to emit the textual representation
13545 /// for @p diff_tree to.
13546 void
13547 print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
13548 {
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);
13554 }
13555
13556 /// Emit a textual representation of a @ref diff sub-tree to an
13557 /// output stream.
13558 ///
13559 /// @param diff_tree the sub-tree to emit the textual representation
13560 /// for.
13561 ///
13562 /// @param out the output stream to emit the textual representation
13563 /// for @p diff_tree to.
13564 void
13565 print_diff_tree(diff_sptr diff_tree,
13566 std::ostream& o)
13567 {print_diff_tree(diff_tree.get(), o);}
13568
13569 /// Emit a textual representation of a @ref corpus_diff tree to an
13570 /// output stream.
13571 ///
13572 /// @param diff_tree the @ref corpus_diff tree to emit the textual
13573 /// representation for.
13574 ///
13575 /// @param out the output stream to emit the textual representation
13576 /// for @p diff_tree to.
13577 void
13578 print_diff_tree(corpus_diff_sptr diff_tree,
13579 std::ostream& o)
13580 {print_diff_tree(diff_tree.get(), o);}
13581
13582 // <redundancy_marking_visitor>
13583
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
13589 /// appropriate.
13590 struct redundancy_marking_visitor : public diff_node_visitor
13591 {
13592 bool skip_children_nodes_;
13593
13594 redundancy_marking_visitor()
13595 : skip_children_nodes_()
13596 {}
13597
13598 virtual void
13599 visit_begin(diff* d)
13600 {
13601 if (d->to_be_reported())
13602 {
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())
13610 {
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:
13614 //
13615 // int foo(int a, int b);
13616 // compared with:
13617 // float foo(float a, float b); (in C).
13618 //
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.
13622
13623 bool redundant_with_sibling_node = false;
13624 const diff* p = d->parent_node();
13625
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();
13630
13631 if (p)
13632 for (vector<diff_sptr>::const_iterator s =
13633 p->children_nodes().begin();
13634 s != p->children_nodes().end();
13635 ++s)
13636 {
13637 if (s->get() == d)
13638 continue;
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();
13645 if (sib == d)
13646 continue;
13647 if (sib->get_canonical_diff() == d->get_canonical_diff())
13648 {
13649 redundant_with_sibling_node = true;
13650 break;
13651 }
13652 }
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
13657 // functions.
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
13661 // them all.
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
13668 (d->context()->
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
13678 // redundant.
13679 && (is_reference_or_pointer_diff(d)
13680 || (!is_child_node_of_function_parm_diff(d)
13681 && !is_child_node_of_base_diff(d))))
13682 {
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;
13694 }
13695 }
13696 }
13697 else
13698 {
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;
13702 }
13703
13704 d->context()->mark_last_diff_visited_per_class_of_equivalence(d);
13705 }
13706
13707 virtual void
13708 visit_begin(corpus_diff*)
13709 {
13710 }
13711
13712 virtual void
13713 visit_end(diff* d)
13714 {
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
13719 // nodes.
13720 {
13721 set_visiting_kind(get_visiting_kind() & (~SKIP_CHILDREN_VISITING_KIND));
13722 skip_children_nodes_ = false;
13723 }
13724 else
13725 {
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())
13731 {
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();
13737 ++i)
13738 {
13739 if ((*i)->has_changes())
13740 {
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;
13745 }
13746 if (has_non_redundant_child)
13747 break;
13748 }
13749
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);
13756 }
13757 }
13758 }
13759
13760 virtual void
13761 visit_end(corpus_diff*)
13762 {
13763 }
13764
13765 virtual bool
13766 visit(diff*, bool)
13767 {return true;}
13768
13769 virtual bool
13770 visit(corpus_diff*, bool)
13771 {
13772 return true;
13773 }
13774 };// end struct redundancy_marking_visitor
13775
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
13779 {
13780 bool
13781 visit(corpus_diff*, bool)
13782 {return true;}
13783
13784 bool
13785 visit(diff* d, bool)
13786 {
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);
13791 return true;
13792 }
13793 }; // end struct redundancy_clearing_visitor
13794
13795 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13796 /// with respect to the REDUNDANT_CATEGORY.
13797 ///
13798 /// @param diff_tree the @ref diff sub-tree to walk.
13799 void
13800 categorize_redundancy(diff* diff_tree)
13801 {
13802 if (diff_tree->context()->show_redundant_changes())
13803 return;
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();
13811 }
13812
13813 /// Walk a given @ref diff sub-tree to categorize each of the nodes
13814 /// with respect to the REDUNDANT_CATEGORY.
13815 ///
13816 /// @param diff_tree the @ref diff sub-tree to walk.
13817 void
13818 categorize_redundancy(diff_sptr diff_tree)
13819 {categorize_redundancy(diff_tree.get());}
13820
13821 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13822 /// with respect to the REDUNDANT_CATEGORY.
13823 ///
13824 /// @param diff_tree the @ref corpus_diff tree to walk.
13825 void
13826 categorize_redundancy(corpus_diff* diff_tree)
13827 {
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);
13834 }
13835
13836 /// Walk a given @ref corpus_diff tree to categorize each of the nodes
13837 /// with respect to the REDUNDANT_CATEGORY.
13838 ///
13839 /// @param diff_tree the @ref corpus_diff tree to walk.
13840 void
13841 categorize_redundancy(corpus_diff_sptr diff_tree)
13842 {categorize_redundancy(diff_tree.get());}
13843
13844 // </redundancy_marking_visitor>
13845
13846 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13847 /// out of the category of the nodes.
13848 ///
13849 /// @param diff_tree the @ref diff sub-tree to walk.
13850 void
13851 clear_redundancy_categorization(diff* diff_tree)
13852 {
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();
13859 }
13860
13861 /// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
13862 /// out of the category of the nodes.
13863 ///
13864 /// @param diff_tree the @ref diff sub-tree to walk.
13865 void
13866 clear_redundancy_categorization(diff_sptr diff_tree)
13867 {clear_redundancy_categorization(diff_tree.get());}
13868
13869 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13870 /// out of the category of the nodes.
13871 ///
13872 /// @param diff_tree the @ref corpus_diff tree to walk.
13873 void
13874 clear_redundancy_categorization(corpus_diff* diff_tree)
13875 {
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();
13882 }
13883
13884 /// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
13885 /// out of the category of the nodes.
13886 ///
13887 /// @param diff_tree the @ref corpus_diff tree to walk.
13888 void
13889 clear_redundancy_categorization(corpus_diff_sptr diff_tree)
13890 {clear_redundancy_categorization(diff_tree.get());}
13891
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.
13896 ///
13897 /// @param diff_tree the @ref corpus_diff instance which @ref diff are
13898 /// to be categorized.
13899 void
13900 apply_filters(corpus_diff_sptr diff_tree)
13901 {
13902 diff_tree->context()->maybe_apply_filters(diff_tree);
13903 propagate_categories(diff_tree);
13904 }
13905
13906 /// Test if a diff node represents the difference between a variadic
13907 /// parameter type and something else.
13908 ///
13909 /// @param d the diff node to consider.
13910 ///
13911 /// @return true iff @p d is a diff node that represents the
13912 /// difference between a variadic parameter type and something else.
13913 bool
13914 is_diff_of_variadic_parameter_type(const diff* d)
13915 {
13916 if (!d)
13917 return false;
13918
13919 type_base_sptr t = is_type(d->first_subject());
13920 if (t && t.get() == type_decl::get_variadic_parameter_type_decl().get())
13921 return true;
13922
13923 t = is_type(d->second_subject());
13924 if (t && t.get() == type_decl::get_variadic_parameter_type_decl().get())
13925 return true;
13926
13927 return false;
13928 }
13929
13930 /// Test if a diff node represents the difference between a variadic
13931 /// parameter type and something else.
13932 ///
13933 /// @param d the diff node to consider.
13934 ///
13935 /// @return true iff @p d is a diff node that represents the
13936 /// difference between a variadic parameter type and something else.
13937 bool
13938 is_diff_of_variadic_parameter_type(const diff_sptr& d)
13939 {return is_diff_of_variadic_parameter_type(d.get());}
13940
13941 /// Test if a diff node represents the difference between a variadic
13942 /// parameter and something else.
13943 ///
13944 /// @param d the diff node to consider.
13945 ///
13946 /// @return true iff @p d is a diff node that represents the
13947 /// difference between a variadic parameter and something else.
13948 bool
13949 is_diff_of_variadic_parameter(const diff* d)
13950 {
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()));
13954 }
13955
13956 /// Test if a diff node represents the difference between a variadic
13957 /// parameter and something else.
13958 ///
13959 /// @param d the diff node to consider.
13960 ///
13961 /// @return true iff @p d is a diff node that represents the
13962 /// difference between a variadic parameter and something else.
13963 bool
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
This page took 0.607752 seconds and 4 git commands to generate.