• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2016-2020 Red Hat, Inc.
5 //
6 // Author: Dodji Seketeli
7 
8 /// @file
9 ///
10 /// This contains the implementation of the suppression engine of
11 /// libabigail.
12 
13 #include <algorithm>
14 
15 #include "abg-internal.h"
16 #include <memory>
17 #include <limits>
18 
19 // <headers defining libabigail's API go under here>
20 ABG_BEGIN_EXPORT_DECLARATIONS
21 
22 #include "abg-ini.h"
23 #include "abg-comp-filter.h"
24 #include "abg-suppression.h"
25 #include "abg-tools-utils.h"
26 
27 ABG_END_EXPORT_DECLARATIONS
28 // </headers defining libabigail's API>
29 
30 #include "abg-suppression-priv.h"
31 
32 namespace abigail
33 {
34 
35 namespace suppr
36 {
37 
38 using std::dynamic_pointer_cast;
39 using regex::regex_t_sptr;
40 
41 // <parsing stuff>
42 
43 // section parsing
44 
45 /// Check if a section has at least one of the given properties.
46 ///
47 /// @param names pointer to the start of an array of names.
48 ///
49 /// @param count number of names in the array.
50 ///
51 /// @return whether at least of one the properties was found.
52 bool
check_sufficient_props(const char * const * names,size_t count,const ini::config::section & section)53 check_sufficient_props(const char *const * names, size_t count,
54 		       const ini::config::section& section)
55 {
56   for (const char *const * name = names; name < names + count; ++name)
57     if (section.find_property(*name))
58       return true;
59   // TODO: Possibly give reason for failure in a message here.
60   return false;
61 }
62 
63 // </parsing stuff>
64 
65 // <suppression_base stuff>
66 
67 /// Constructor for @ref suppression_base
68 ///
69 /// @param a label for the suppression.  This represents just a
70 /// comment.
suppression_base(const string & label)71 suppression_base::suppression_base(const string& label)
72   : priv_(new priv(label))
73 {}
74 
75 /// Constructor for @ref suppression_base
76 ///
77 /// @param a label for the suppression.  This represents just a
78 /// comment.
79 ///
80 /// @param file_name_regex_str the regular expression that denotes the
81 /// file name to match.
82 ///
83 /// @param file_name_not_regex_str the regular expression that denotes
84 /// the file name to *NOT* match.
suppression_base(const string & label,const string & file_name_regex_str,const string & file_name_not_regex_str)85 suppression_base::suppression_base(const string& label,
86 				   const string& file_name_regex_str,
87 				   const string& file_name_not_regex_str)
88   : priv_(new priv(label,
89 		   file_name_regex_str,
90 		   file_name_not_regex_str))
91 {
92 }
93 
94 /// Tests if the current suppression specification is to avoid adding
95 /// the matched ABI artifact to the internal representation or not.
96 ///
97 /// @return true iff the current suppression specification is to avoid
98 /// adding the matched ABI artifact to the internal representation.
99 bool
get_drops_artifact_from_ir() const100 suppression_base::get_drops_artifact_from_ir() const
101 {return priv_->drops_artifact_;}
102 
103 /// Set the flag that says whether the current suppression
104 /// specification is to avoid adding the matched ABI artifact to the
105 /// internal representation or not.
106 ///
107 /// @param f the flag to set to true iff the current suppression
108 /// specification is to avoid adding the matched ABI artifact to the
109 /// internal representation.
110 void
set_drops_artifact_from_ir(bool f)111 suppression_base::set_drops_artifact_from_ir(bool f)
112 {priv_->drops_artifact_ = f;}
113 
114 /// Test is the suppression specification is artificial.
115 ///
116 /// Artificial means that the suppression was automatically generated
117 /// by libabigail, rather than being constructed from a suppression
118 /// file provided by the user.
119 ///
120 /// @return TRUE iff the suppression specification is artificial.
121 bool
get_is_artificial() const122 suppression_base::get_is_artificial() const
123 {return priv_->is_artificial_;}
124 
125 /// Set a flag saying if the suppression specification is artificial
126 /// or not.
127 ///
128 /// Artificial means that the suppression was automatically generated
129 /// by libabigail, rather than being constructed from a suppression
130 /// file provided by the user.
131 void
set_is_artificial(bool f)132 suppression_base::set_is_artificial(bool f)
133 {priv_->is_artificial_ = f;}
134 
135 /// Getter for the label associated to this suppression specification.
136 ///
137 /// @return the label.
138 const string
get_label() const139 suppression_base::get_label() const
140 {return priv_->label_;}
141 
142 /// Setter for the label associated to this suppression specification.
143 ///
144 /// @param label the new label.
145 void
set_label(const string & label)146 suppression_base::set_label(const string& label)
147 {priv_->label_ = label;}
148 
149 /// Setter for the "file_name_regex" property of the current instance
150 /// of @ref suppression_base.
151 ///
152 /// The "file_name_regex" property is a regular expression string that
153 /// designates the file name that contains the ABI artifact this
154 /// suppression should apply to.
155 ///
156 /// @param regexp the new regular expression string.
157 void
set_file_name_regex_str(const string & regexp)158 suppression_base::set_file_name_regex_str(const string& regexp)
159 {priv_->file_name_regex_str_ = regexp;}
160 
161 /// Getter for the "file_name_regex" property of the current instance
162 /// of @ref suppression_base.
163 ///
164 /// The "file_name_regex" property is a regular expression string that
165 /// designates the file name that contains the ABI artifacts this
166 /// suppression should apply to.
167 ///
168 /// @return the regular expression string.
169 const string&
get_file_name_regex_str() const170 suppression_base::get_file_name_regex_str() const
171 {return priv_->file_name_regex_str_;}
172 
173 /// Setter for the "file_name_not_regex" property of the current
174 /// instance of @ref suppression_base.
175 ///
176 /// The current suppression specification should apply to ABI
177 /// artifacts of a file which name does *NOT* match the regular
178 /// expression string designated by the "file_name_not_regex"
179 /// property.
180 ///
181 /// @param regexp the new regular expression string.
182 void
set_file_name_not_regex_str(const string & regexp)183 suppression_base::set_file_name_not_regex_str(const string& regexp)
184 {priv_->file_name_not_regex_str_ = regexp;}
185 
186 /// Getter for the "file_name_not_regex" property of the current
187 /// instance of @ref suppression_base.
188 ///
189 /// The current suppression specification should apply to ABI
190 /// artifacts of a file which name does *NOT* match the regular
191 /// expression string designated by the "file_name_not_regex"
192 /// property.
193 ///
194 /// @return the regular expression string.
195 const string&
get_file_name_not_regex_str() const196 suppression_base::get_file_name_not_regex_str() const
197 {return priv_->file_name_not_regex_str_;}
198 
199 /// Test if the current suppression has a property related to file
200 /// name.
201 ///
202 /// @return true iff the current suppression has either a
203 /// file_name_regex or a file_name_not_regex property.
204 bool
has_file_name_related_property() const205 suppression_base::has_file_name_related_property() const
206 {
207   return (!(get_file_name_regex_str().empty()
208 	    && get_file_name_not_regex_str().empty()));
209 }
210 
211 /// Setter of the "soname_regex_str property of the current instance
212 /// of @ref suppression_base.
213 ///
214 /// The "soname_regex_str" is a regular expression string that
215 /// designates the soname of the shared library that contains the ABI
216 /// artifacts this suppression should apply to.
217 ///
218 /// @param regexp the new regular expression string.
219 void
set_soname_regex_str(const string & regexp)220 suppression_base::set_soname_regex_str(const string& regexp)
221 {priv_->soname_regex_str_ = regexp;}
222 
223 /// Getter of the "soname_regex_str property of the current instance
224 /// of @ref suppression_base.
225 ///
226 /// The "soname_regex_str" is a regular expression string that
227 /// designates the soname of the shared library that contains the ABI
228 /// artifacts this suppression should apply to.
229 ///
230 /// @return the regular expression string.
231 const string&
get_soname_regex_str() const232 suppression_base::get_soname_regex_str() const
233 {return priv_->soname_regex_str_;}
234 
235 /// Setter of the "soname_not_regex_str property of the current
236 /// instance of @ref suppression_base.
237 ///
238 /// The current suppression specification should apply to ABI
239 /// artifacts of a shared library which SONAME does *NOT* match the
240 /// regular expression string designated by the "soname_not_regex"
241 /// property.
242 ///
243 /// @param regexp the new regular expression string.
244 void
set_soname_not_regex_str(const string & regexp)245 suppression_base::set_soname_not_regex_str(const string& regexp)
246 {priv_->soname_not_regex_str_ = regexp;}
247 
248 /// Getter of the "soname_not_regex_str property of the current
249 /// instance of @ref suppression_base.
250 ///
251 /// The current suppression specification should apply to ABI
252 /// artifacts of a shared library which SONAME does *NOT* match the
253 /// regular expression string designated by the "soname_not_regex"
254 /// property.
255 ///
256 /// @return the regular expression string.
257 const string&
get_soname_not_regex_str() const258 suppression_base::get_soname_not_regex_str() const
259 {return priv_->soname_not_regex_str_;}
260 
261 /// Test if the current suppression has a property related to SONAMEs.
262 ///
263 /// @return true iff the current suppression has either a soname_regex
264 /// or a soname_not_regex property.
265 bool
has_soname_related_property() const266 suppression_base::has_soname_related_property() const
267 {
268   return (!(get_soname_regex_str().empty()
269 	    && get_soname_not_regex_str().empty()));
270 }
271 
272 /// Check if the SONAMEs of the two binaries being compared match the
273 /// content of the properties "soname_regexp" and "soname_not_regexp"
274 /// of the current suppression specification.
275 ///
276 /// @param suppr the suppression specification
277 ///
278 /// @param ctxt the context of the comparison.
279 ///
280 /// @return false if the regular expression contained in the property
281 /// soname_regexp or in the property "soname_not_regexp" does *NOT*
282 /// match at least one of the SONAMEs of the two binaries being
283 /// compared.  Return true otherwise.
284 static bool
sonames_of_binaries_match(const suppression_base & suppr,const diff_context & ctxt)285 sonames_of_binaries_match(const suppression_base& suppr,
286 			  const diff_context& ctxt)
287 {
288   // Check if the sonames of the binaries match
289   string first_soname = ctxt.get_corpus_diff()->first_corpus()->get_soname(),
290     second_soname = ctxt.get_corpus_diff()->second_corpus()->get_soname();
291 
292   if (!suppr.has_soname_related_property())
293     return false;
294 
295   if (!suppr.priv_->matches_soname(first_soname)
296       && !suppr.priv_->matches_soname(second_soname))
297     return false;
298 
299   return true;
300 }
301 
302 /// Check if the names of the two binaries being compared match the
303 /// content of the properties "file_name_regexp" and
304 /// "file_name_not_regexp".
305 ///
306 /// @param suppr the current suppression specification.
307 ///
308 /// @param ctxt the context of the comparison.
309 ///
310 /// @return false if the regular expression contained in the property
311 /// file_name_regexp or in the property "file_name_not_regexp" does
312 /// *NOT* match at least one of the names of the two binaries being
313 /// compared.  Return true otherwise.
314 static bool
names_of_binaries_match(const suppression_base & suppr,const diff_context & ctxt)315 names_of_binaries_match(const suppression_base& suppr,
316 			const diff_context &ctxt)
317 {
318    // Check if the file names of the binaries match
319   string first_binary_path = ctxt.get_corpus_diff()->first_corpus()->get_path(),
320     second_binary_path = ctxt.get_corpus_diff()->second_corpus()->get_path();
321 
322   if (!suppr.has_file_name_related_property())
323     return false;
324 
325   if (!suppr.priv_->matches_binary_name(first_binary_path)
326       && !suppr.priv_->matches_binary_name(second_binary_path))
327     return false;
328 
329   return true;
330 }
331 
~suppression_base()332 suppression_base::~suppression_base()
333 {}
334 
335 static type_suppression_sptr
336 read_type_suppression(const ini::config::section& section);
337 
338 static function_suppression_sptr
339 read_function_suppression(const ini::config::section& section);
340 
341 static variable_suppression_sptr
342 read_variable_suppression(const ini::config::section& section);
343 
344 static file_suppression_sptr
345 read_file_suppression(const ini::config::section& section);
346 
347 /// Read a vector of suppression specifications from the sections of
348 /// an ini::config.
349 ///
350 /// Note that this function needs to be updated each time a new kind
351 /// of suppression specification is added.
352 ///
353 /// @param config the config to read from.
354 ///
355 /// @param suppressions out parameter.  The vector of suppressions to
356 /// append the newly read suppressions to.
357 static void
read_suppressions(const ini::config & config,suppressions_type & suppressions)358 read_suppressions(const ini::config& config,
359 		  suppressions_type& suppressions)
360 {
361   suppression_sptr s;
362   for (ini::config::sections_type::const_iterator i =
363 	 config.get_sections().begin();
364        i != config.get_sections().end();
365        ++i)
366     if ((s = read_type_suppression(**i))
367 	|| (s = read_function_suppression(**i))
368 	|| (s = read_variable_suppression(**i))
369 	|| (s = read_file_suppression(**i)))
370       suppressions.push_back(s);
371 
372 }
373 
374 /// Read suppressions specifications from an input stream.
375 ///
376 /// @param input the input stream to read from.
377 ///
378 /// @param suppressions the vector of suppressions to append the newly
379 /// read suppressions to.
380 void
read_suppressions(std::istream & input,suppressions_type & suppressions)381 read_suppressions(std::istream& input,
382 		  suppressions_type& suppressions)
383 {
384     if (ini::config_sptr config = ini::read_config(input))
385     read_suppressions(*config, suppressions);
386 }
387 
388 /// Read suppressions specifications from an input file on disk.
389 ///
390 /// @param input the path to the input file to read from.
391 ///
392 /// @param suppressions the vector of suppressions to append the newly
393 /// read suppressions to.
394 void
read_suppressions(const string & file_path,suppressions_type & suppressions)395 read_suppressions(const string& file_path,
396 		  suppressions_type& suppressions)
397 {
398   if (ini::config_sptr config = ini::read_config(file_path))
399     read_suppressions(*config, suppressions);
400 }
401 // </suppression_base stuff>
402 
403 // <type_suppression stuff>
404 
405 /// Constructor for @ref type_suppression.
406 ///
407 /// @param label the label of the suppression.  This is just a free
408 /// form comment explaining what the suppression is about.
409 ///
410 /// @param type_name_regexp the regular expression describing the
411 /// types about which diff reports should be suppressed.  If it's an
412 /// empty string, the parameter is ignored.
413 ///
414 /// @param type_name the name of the type about which diff reports
415 /// should be suppressed.  If it's an empty string, the parameter is
416 /// ignored.
417 ///
418 /// Note that parameter @p type_name_regexp and @p type_name_regexp
419 /// should not necessarily be populated.  It usually is either one or
420 /// the other that the user wants.
type_suppression(const string & label,const string & type_name_regexp,const string & type_name)421 type_suppression::type_suppression(const string& label,
422 				   const string& type_name_regexp,
423 				   const string& type_name)
424   : suppression_base(label),
425     priv_(new priv(type_name_regexp,
426 		   type_name,
427 		   /*consider_type_kind=*/false,
428 		   /*type_kind=*/CLASS_TYPE_KIND,
429 		   /*consider_reach_kind=*/false,
430 		   /*reach_kind=*/DIRECT_REACH_KIND))
431 {}
432 
~type_suppression()433 type_suppression::~type_suppression()
434 {}
435 
436 /// Setter for the "type_name_regex" property of the type suppression
437 /// specification.
438 ///
439 /// This sets a regular expression that specifies the family of types
440 /// about which diff reports should be suppressed.
441 ///
442 /// @param name_regex_str the new regular expression to set.
443 void
set_type_name_regex_str(const string & name_regex_str)444 type_suppression::set_type_name_regex_str(const string& name_regex_str)
445 {priv_->type_name_regex_str_ = name_regex_str;}
446 
447 /// Getter for the "type_name_regex" property of the type suppression
448 /// specification.
449 ///
450 /// This returns a regular expression string that specifies the family
451 /// of types about which diff reports should be suppressed.
452 ///
453 /// @return the regular expression string.
454 const string&
get_type_name_regex_str() const455 type_suppression::get_type_name_regex_str() const
456 {return priv_->type_name_regex_str_;}
457 
458 /// Setter for the "type_name_not_regex_str" property of the type
459 /// suppression specification.
460 ///
461 /// This returns a regular expression string that specifies the family
462 /// of types that should be kept after suppression.
463 ///
464 /// @param r the new regexp string.
465 void
set_type_name_not_regex_str(const string & r)466 type_suppression::set_type_name_not_regex_str(const string& r)
467 {priv_->set_type_name_not_regex_str(r);}
468 
469 /// Getter for the "type_name_not_regex_str" property of the type
470 /// suppression specification.
471 ///
472 /// This returns a regular expression string that specifies the family
473 /// of types that should be kept after suppression.
474 ///
475 /// @return the new regexp string.
476 const string&
get_type_name_not_regex_str() const477 type_suppression::get_type_name_not_regex_str() const
478 {return priv_->get_type_name_not_regex_str();}
479 
480 /// Setter for the name of the type about which diff reports should be
481 /// suppressed.
482 ///
483 /// @param name the new type name.
484 void
set_type_name(const string & name)485 type_suppression::set_type_name(const string& name)
486 {priv_->type_name_ = name;}
487 
488 /// Getter for the name of the type about which diff reports should be
489 /// suppressed.
490 ///
491 /// @param return the type name.
492 const string&
get_type_name() const493 type_suppression::get_type_name() const
494 {return priv_->type_name_;}
495 
496 /// Getter of the property that says whether to consider the kind of
497 /// type this suppression is about.
498 ///
499 /// @return the boolean value of the property.
500 bool
get_consider_type_kind() const501 type_suppression::get_consider_type_kind() const
502 {return priv_->consider_type_kind_;}
503 
504 /// Setter of the property that says whether to consider the kind of
505 /// type this suppression is about.
506 ///
507 /// @param f the new boolean value of the property.
508 void
set_consider_type_kind(bool f)509 type_suppression::set_consider_type_kind(bool f)
510 {priv_->consider_type_kind_ = f;}
511 
512 /// Setter of the kind of type this suppression is about.
513 ///
514 /// Note that this will be considered during evaluation of the
515 /// suppression only if type_suppression::get_consider_type_kind()
516 /// returns true.
517 ///
518 /// @param k the new kind of type this suppression is about.
519 void
set_type_kind(type_kind k)520 type_suppression::set_type_kind(type_kind k)
521 {priv_->type_kind_ = k;}
522 
523 /// Getter of the kind of type this suppression is about.
524 ///
525 /// Note that this will be considered during evaluation of the
526 /// suppression only if type_suppression::get_consider_type_kind()
527 /// returns true.
528 ///
529 /// @return the kind of type this suppression is about.
530 type_suppression::type_kind
get_type_kind() const531 type_suppression::get_type_kind() const
532 {return priv_->type_kind_;}
533 
534 /// Test if the current type suppression specification
535 /// suggests to consider how the matching diff node is reached.
536 ///
537 /// @return true if the current type suppression specification
538 /// suggests to consider how the matching diff node is reached.
539 bool
get_consider_reach_kind() const540 type_suppression::get_consider_reach_kind() const
541 {return priv_->consider_reach_kind_;}
542 
543 /// Set a flag saying if the current type suppression specification
544 /// suggests to consider how the matching diff node is reached.
545 ///
546 /// @param f the new value of the flag.  It's true iff the current
547 /// type suppression specification suggests to consider how the
548 /// matching diff node is reached.
549 void
set_consider_reach_kind(bool f)550 type_suppression::set_consider_reach_kind(bool f)
551 {priv_->consider_reach_kind_ = f;}
552 
553 /// Getter of the way the diff node matching the current suppression
554 /// specification is to be reached.
555 ///
556 /// @return the way the diff node matching the current suppression
557 /// specification is to be reached.
558 type_suppression::reach_kind
get_reach_kind() const559 type_suppression::get_reach_kind() const
560 {return priv_->reach_kind_;}
561 
562 /// Setter of the way the diff node matching the current suppression
563 /// specification is to be reached.
564 ///
565 /// @param p the way the diff node matching the current suppression
566 /// specification is to be reached.
567 void
set_reach_kind(reach_kind k)568 type_suppression::set_reach_kind(reach_kind k)
569 {priv_->reach_kind_ = k;}
570 
571 /// Setter for the vector of data member insertion ranges that
572 /// specifies where a data member is inserted as far as this
573 /// suppression specification is concerned.
574 ///
575 /// @param r the new insertion range vector.
576 void
set_data_member_insertion_ranges(const insertion_ranges & r)577 type_suppression::set_data_member_insertion_ranges(const insertion_ranges& r)
578 {priv_->insertion_ranges_ = r;}
579 
580 /// Getter for the vector of data member insertion range that
581 /// specifiers where a data member is inserted as far as this
582 /// suppression specification is concerned.
583 ///
584 /// @return the vector of insertion ranges.
585 const type_suppression::insertion_ranges&
get_data_member_insertion_ranges() const586 type_suppression::get_data_member_insertion_ranges() const
587 {return priv_->insertion_ranges_;}
588 
589 /// Getter for the vector of data member insertion range that
590 /// specifiers where a data member is inserted as far as this
591 /// suppression specification is concerned.
592 ///
593 /// @return the vector of insertion ranges.
594 type_suppression::insertion_ranges&
get_data_member_insertion_ranges()595 type_suppression::get_data_member_insertion_ranges()
596 {return priv_->insertion_ranges_;}
597 
598 /// Getter for the array of source location paths of types that should
599 /// *NOT* be suppressed.
600 ///
601 /// @return the set of source locations of types that should *NOT* be
602 /// supressed.
603 const unordered_set<string>&
get_source_locations_to_keep() const604 type_suppression::get_source_locations_to_keep() const
605 {return priv_->source_locations_to_keep_;}
606 
607 /// Getter for the array of source location paths of types that should
608 /// *NOT* be suppressed.
609 ///
610 /// @return the array of source locations of types that should *NOT*
611 /// be supressed.
612 unordered_set<string>&
get_source_locations_to_keep()613 type_suppression::get_source_locations_to_keep()
614 {return priv_->source_locations_to_keep_;}
615 
616 /// Setter for the array of source location paths of types that should
617 /// *NOT* be suppressed.
618 ///
619 /// @param l the new array.
620 void
set_source_locations_to_keep(const unordered_set<string> & l)621 type_suppression::set_source_locations_to_keep
622 (const unordered_set<string>& l)
623 {priv_->source_locations_to_keep_ = l;}
624 
625 /// Getter of the regular expression string that designates the source
626 /// location paths of types that should not be suppressed.
627 ///
628 /// @return the regular expression string.
629 const string&
get_source_location_to_keep_regex_str() const630 type_suppression::get_source_location_to_keep_regex_str() const
631 {return priv_->source_location_to_keep_regex_str_;}
632 
633 /// Setter of the regular expression string that designates the source
634 /// location paths of types that should not be suppressed.
635 ///
636 /// @param r the new regular expression.
637 void
set_source_location_to_keep_regex_str(const string & r)638 type_suppression::set_source_location_to_keep_regex_str(const string& r)
639 {priv_->source_location_to_keep_regex_str_ = r;}
640 
641 /// Getter of the vector of the changed enumerators that are supposed
642 /// to be suppressed.  Note that this will be "valid" only if the type
643 /// suppression has the 'type_kind = enum' property.
644 ///
645 /// @return the vector of the changed enumerators that are supposed to
646 /// be suppressed.
647 const vector<string>&
get_changed_enumerator_names() const648 type_suppression::get_changed_enumerator_names() const
649 {return priv_->changed_enumerator_names_;}
650 
651 /// Setter of the vector of changed enumerators that are supposed to
652 /// be suppressed.  Note that this will be "valid" only if the type
653 /// suppression has the 'type_kind = enum' property.
654 ///
655 /// @param n the vector of the changed enumerators that are supposed
656 /// to be suppressed.
657 void
set_changed_enumerator_names(const vector<string> & n)658 type_suppression::set_changed_enumerator_names(const vector<string>& n)
659 {priv_->changed_enumerator_names_ = n;}
660 
661 /// Evaluate this suppression specification on a given diff node and
662 /// say if the diff node should be suppressed or not.
663 ///
664 /// @param diff the diff node to evaluate this suppression
665 /// specification against.
666 ///
667 /// @return true if @p diff should be suppressed.
668 bool
suppresses_diff(const diff * diff) const669 type_suppression::suppresses_diff(const diff* diff) const
670 {
671   const type_diff_base* d = is_type_diff(diff);
672   if (!d)
673     {
674       // So the diff we are looking at is not a type diff.  However,
675       // there are cases where a type suppression can suppress changes
676       // on functions.
677 
678       // Typically, if a virtual member function's virtual index (its
679       // index in the vtable of a class) changes and if the current
680       // type suppression is meant to suppress change reports about
681       // the enclosing class of the virtual member function, then this
682       // type suppression should suppress reports about that function
683       // change.
684       const function_decl_diff* d = is_function_decl_diff(diff);
685       if (d)
686 	{
687 	  // Let's see if 'd' carries a virtual member function
688 	  // change.
689 	  if (comparison::filtering::has_virtual_mem_fn_change(d))
690 	    {
691 	      function_decl_sptr f = d->first_function_decl();
692 	      class_decl_sptr fc =
693 		is_class_type(is_method_type(f->get_type())->get_class_type());
694 	      ABG_ASSERT(fc);
695 	      if (suppresses_type(fc, diff->context()))
696 		return true;
697 	    }
698 	}
699       return false;
700     }
701 
702   // If the suppression should consider the way the diff node has been
703   // reached, then do it now.
704   if (get_consider_reach_kind())
705     {
706       if (get_reach_kind() == POINTER_REACH_KIND)
707 	{
708 	  if (const pointer_diff* ptr_diff = is_pointer_diff(diff))
709 	    {
710 	      d = is_type_diff(ptr_diff->underlying_type_diff().get());
711 	      if (!d)
712 		// This might be of, e.g, distinct_diff type.
713 		return false;
714 	      d = is_type_diff(peel_qualified_diff(d));
715 	    }
716 	  else
717 	    return false;
718 	}
719       else if (get_reach_kind() == REFERENCE_REACH_KIND)
720 	{
721 	  if (const reference_diff* ref_diff = is_reference_diff(diff))
722 	    {
723 	      d = is_type_diff(ref_diff->underlying_type_diff().get());
724 	      if (!d)
725 		// This might be of, e.g, distinct_diff type.
726 		return false;
727 	      d = is_type_diff(peel_qualified_diff(d));
728 	    }
729 	  else
730 	    return false;
731 	}
732       else if (get_reach_kind() == REFERENCE_OR_POINTER_REACH_KIND)
733 	{
734 	  if (const pointer_diff* ptr_diff = is_pointer_diff(diff))
735 	    {
736 	      d = is_type_diff(ptr_diff->underlying_type_diff().get());
737 	      ABG_ASSERT(d);
738 	      d = is_type_diff(peel_qualified_diff(d));
739 	    }
740 	  else if (const reference_diff* ref_diff = is_reference_diff(diff))
741 	    {
742 	      d = is_type_diff(ref_diff->underlying_type_diff().get());
743 	      ABG_ASSERT(d);
744 	      d = is_type_diff(peel_qualified_diff(d));
745 	    }
746 	  else
747 	    return false;
748 	}
749     }
750 
751   type_base_sptr ft, st;
752   ft = is_type(d->first_subject());
753   st = is_type(d->second_subject());
754   ABG_ASSERT(ft && st);
755 
756   if (!suppresses_type(ft, d->context())
757       && !suppresses_type(st, d->context()))
758     {
759       // A private type suppression specification considers that a
760       // type can be private and yet some typedefs of that type can be
761       // public -- depending on, e.g, if the typedef is defined in a
762       // public header or not.  So if we are in the context of a
763       // private type suppression let's *NOT* peel typedefs away.
764       if (!is_private_type_suppr_spec(*this))
765 	{
766 	  ft = peel_typedef_type(ft);
767 	  st = peel_typedef_type(st);
768 	}
769 
770       if (!suppresses_type(ft, d->context())
771 	  && !suppresses_type(st, d->context()))
772 	return false;
773 
774       d = is_type_diff(get_typedef_diff_underlying_type_diff(d));
775     }
776 
777   // Now let's consider class diffs in the context of a suppr spec
778   // that contains properties like "has_data_member_inserted_*".
779 
780   const class_diff* klass_diff = dynamic_cast<const class_diff*>(d);
781   if (klass_diff)
782     {
783       // We are looking at a class diff ...
784       if (!get_data_member_insertion_ranges().empty())
785 	{
786 	  // ... and the suppr spec contains a
787 	  // "has_data_member_inserted_*" clause ...
788 	  if (klass_diff->deleted_data_members().empty()
789 	      && (klass_diff->first_class_decl()->get_size_in_bits()
790 		  <= klass_diff->second_class_decl()->get_size_in_bits()))
791 	    {
792 	      // That "has_data_member_inserted_*" clause doesn't hold
793 	      // if the class has deleted data members or shrunk.
794 
795 	      const class_decl_sptr& first_type_decl =
796 		klass_diff->first_class_decl();
797 
798 	      for (string_decl_base_sptr_map::const_iterator m =
799 		     klass_diff->inserted_data_members().begin();
800 		   m != klass_diff->inserted_data_members().end();
801 		   ++m)
802 		{
803 		  decl_base_sptr member = m->second;
804 		  size_t dm_offset = get_data_member_offset(member);
805 		  bool matched = false;
806 
807 		  for (insertion_ranges::const_iterator i =
808 			 get_data_member_insertion_ranges().begin();
809 		       i != get_data_member_insertion_ranges().end();
810 		       ++i)
811 		    {
812 		      type_suppression::insertion_range_sptr range = *i;
813 		      uint64_t range_begin_val = 0, range_end_val = 0;
814 		      if (!type_suppression::insertion_range::eval_boundary
815 			  (range->begin(), first_type_decl, range_begin_val))
816 			break;
817 		      if (!type_suppression::insertion_range::eval_boundary
818 			  (range->end(), first_type_decl, range_end_val))
819 			break;
820 
821 		      uint64_t range_begin = range_begin_val;
822 		      uint64_t range_end = range_end_val;
823 
824 		      if (insertion_range::boundary_value_is_end(range_begin)
825 			  && insertion_range::boundary_value_is_end(range_end))
826 			{
827 			  // This idiom represents the predicate
828 			  // "has_data_member_inserted_at = end"
829 			  if (dm_offset >
830 			      get_data_member_offset(get_last_data_member
831 						     (first_type_decl)))
832 			    {
833 			      // So the data member was added after
834 			      // last data member of the klass.  That
835 			      // matches the suppr spec
836 			      // "has_data_member_inserted_at = end".
837 			      matched = true;
838 			      continue;
839 			    }
840 			}
841 
842 			if (range_begin > range_end)
843 			  // Wrong suppr spec.  Ignore it.
844 			  continue;
845 
846 		      if (dm_offset < range_begin || dm_offset > range_end)
847 			// The offset of the added data member doesn't
848 			// match the insertion range specified.  So
849 			// the diff object won't be suppressed.
850 			continue;
851 
852 		      // If we reached this point, then all the
853 		      // insertion range constraints have been
854 		      // satisfied.  So
855 		      matched = true;
856 		    }
857 		  if (!matched)
858 		    return false;
859 		}
860 	    }
861 	  else
862 	    return false;
863 	}
864     }
865 
866   const enum_diff* enum_dif = dynamic_cast<const enum_diff*>(d);
867   if (// We are looking at an enum diff node which ...
868       enum_dif
869       //... carries no deleted enumerator ... "
870       && enum_dif->deleted_enumerators().empty()
871       // ... carries no size change ...
872       && (enum_dif->first_enum()->get_size_in_bits()
873 	  == enum_dif->second_enum()->get_size_in_bits())
874       // ... and yet carries some changed enumerators!
875       && !enum_dif->changed_enumerators().empty())
876     {
877       // Make sure that all changed enumerators are listed in the
878       // vector of enumerator names returned by the
879       // get_changed_enumerator_names() member function.
880       bool matched = true;
881       for (string_changed_enumerator_map::const_iterator i =
882 	     enum_dif->changed_enumerators().begin();
883 	   i != enum_dif->changed_enumerators().end();
884 	   ++i)
885 	{
886 	  matched &= true;
887 	  if (std::find(get_changed_enumerator_names().begin(),
888 			get_changed_enumerator_names().end(),
889 			i->first) == get_changed_enumerator_names().end())
890 	    {
891 	      matched &= false;
892 	      break;
893 	    }
894 	}
895       if (!matched)
896 	return false;
897     }
898 
899   return true;
900 }
901 
902 /// Test if the current instance of @ref type_suppression suppresses a
903 /// change reports about a given type.
904 ///
905 /// @param type the type to consider.
906 ///
907 /// @param ctxt the context of comparison we are involved with.
908 ///
909 /// @return true iff the suppression specification suppresses type @p
910 /// type.
911 bool
suppresses_type(const type_base_sptr & type,const diff_context_sptr & ctxt) const912 type_suppression::suppresses_type(const type_base_sptr& type,
913 				  const diff_context_sptr& ctxt) const
914 {
915   if (ctxt)
916     {
917       // Check if the names of the binaries match the suppression
918       if (!names_of_binaries_match(*this, *ctxt))
919 	if (has_file_name_related_property())
920 	  return false;
921 
922       // Check if the sonames of the binaries match the suppression
923       if (!sonames_of_binaries_match(*this, *ctxt))
924 	if (has_soname_related_property())
925 	  return false;
926     }
927 
928   return suppresses_type(type);
929 }
930 
931 /// Test if an instance of @ref type_suppression matches a given type.
932 ///
933 /// This function does not take the name of the type into account
934 /// while testing if the type matches the type_suppression.
935 ///
936 /// @param s the suppression to evaluate.
937 ///
938 /// @param type the type to consider.
939 ///
940 /// @return true iff the suppression specification matches type @p
941 /// type without taking its name into account.
942 static bool
suppression_matches_type_no_name(const type_suppression & s,const type_base_sptr & type)943 suppression_matches_type_no_name(const type_suppression&	 s,
944 				 const type_base_sptr		&type)
945 {
946   // If the suppression should consider type kind then, well, check
947   // for that.
948   if (s.get_consider_type_kind())
949     {
950       type_suppression::type_kind tk = s.get_type_kind();
951       bool matches = true;
952       switch (tk)
953 	{
954 	case type_suppression::UNKNOWN_TYPE_KIND:
955 	case type_suppression::CLASS_TYPE_KIND:
956 	  if (!is_class_type(type))
957 	    matches = false;
958 	  break;
959 	case type_suppression::STRUCT_TYPE_KIND:
960 	  {
961 	    class_decl_sptr klass = is_class_type(type);
962 	    if (!klass || !klass->is_struct())
963 	      matches = false;
964 	  }
965 	  break;
966 	case type_suppression::UNION_TYPE_KIND:
967 	  if (!is_union_type(type))
968 	    matches = false;
969 	  break;
970 	case type_suppression::ENUM_TYPE_KIND:
971 	  if (!is_enum_type(type))
972 	    matches = false;
973 	  break;
974 	case type_suppression::ARRAY_TYPE_KIND:
975 	  if (!is_array_type(type))
976 	    matches = false;
977 	  break;
978 	case type_suppression::TYPEDEF_TYPE_KIND:
979 	  if (!is_typedef(type))
980 	    matches = false;
981 	  break;
982 	case type_suppression::BUILTIN_TYPE_KIND:
983 	  if (!is_type_decl(type))
984 	    matches = false;
985 	  break;
986 	}
987 
988       if (!matches)
989 	return false;
990     }
991 
992   // Check if there is a source location related match.
993   if (!suppression_matches_type_location(s, type))
994     return false;
995 
996   return true;
997 }
998 
999 /// Test if a type suppression specification matches a type name.
1000 ///
1001 /// @param s the type suppression to consider.
1002 ///
1003 /// @param type_name the type name to consider.
1004 ///
1005 /// @return true iff the type designated by its name @p type_name is
1006 /// matched by the type suppression specification @p s.
1007 bool
suppression_matches_type_name(const type_suppression & s,const string & type_name)1008 suppression_matches_type_name(const type_suppression&	s,
1009 			      const string&		type_name)
1010 {
1011   if (!s.get_type_name().empty()
1012       || s.priv_->get_type_name_regex()
1013       || s.priv_->get_type_name_not_regex())
1014     {
1015       // Check if there is an exact type name match.
1016       if (!s.get_type_name().empty())
1017 	{
1018 	  if (s.get_type_name() != type_name)
1019 	    return false;
1020 	}
1021       else
1022 	{
1023 	  // Now check if there is a regular expression match.
1024 	  //
1025 	  // If the qualified name of the considered type doesn't match
1026 	  // the regular expression of the type name, then this
1027 	  // suppression doesn't apply.
1028 	  if (const regex_t_sptr& type_name_regex =
1029 	      s.priv_->get_type_name_regex())
1030 	    {
1031 	      if (!regex::match(type_name_regex, type_name))
1032 		return false;
1033 	    }
1034 
1035 	  if (const regex_t_sptr type_name_not_regex =
1036 	      s.priv_->get_type_name_not_regex())
1037 	    {
1038 	      if (regex::match(type_name_not_regex, type_name))
1039 		return false;
1040 	    }
1041 	}
1042     }
1043 
1044   return true;
1045 }
1046 
1047 /// Test if a type suppression matches a type in a particular scope.
1048 ///
1049 /// @param s the type suppression to consider.
1050 ///
1051 /// @param type_scope the scope of the type to consider.
1052 ///
1053 /// @param type the type to consider.
1054 ///
1055 /// @return true iff the supression @p s matches type @p type in scope
1056 /// @p type_scope.
1057 bool
suppression_matches_type_name(const suppr::type_suppression & s,const scope_decl * type_scope,const type_base_sptr & type)1058 suppression_matches_type_name(const suppr::type_suppression&	s,
1059 			      const scope_decl*		type_scope,
1060 			      const type_base_sptr&		type)
1061 {
1062   string type_name = build_qualified_name(type_scope, type);
1063   return suppression_matches_type_name(s, type_name);
1064 }
1065 
1066 /// Test if a type suppression matches a source location.
1067 ///
1068 /// @param s the type suppression to consider.
1069 ///
1070 /// @param loc the location to consider.
1071 ///
1072 /// @return true iff the suppression @p s matches location @p loc.
1073 bool
suppression_matches_type_location(const type_suppression & s,const location & loc)1074 suppression_matches_type_location(const type_suppression&	s,
1075 				  const location&		loc)
1076 {
1077   if (loc)
1078     {
1079       // Check if there is a source location related match.
1080       string loc_path, loc_path_base;
1081       unsigned loc_line = 0, loc_column = 0;
1082       loc.expand(loc_path, loc_line, loc_column);
1083 
1084       if (regex_t_sptr regexp = s.priv_->get_source_location_to_keep_regex())
1085 	if (regex::match(regexp, loc_path))
1086 	  return false;
1087 
1088       tools_utils::base_name(loc_path, loc_path_base);
1089       if (s.get_source_locations_to_keep().find(loc_path_base)
1090 	  != s.get_source_locations_to_keep().end())
1091 	return false;
1092       if (s.get_source_locations_to_keep().find(loc_path)
1093 	  != s.get_source_locations_to_keep().end())
1094 	return false;
1095     }
1096   else
1097     {
1098       if (!s.get_source_locations_to_keep().empty()
1099 	  || s.priv_->get_source_location_to_keep_regex())
1100 	// The user provided a "source_location_not_regexp" or
1101 	// a "source_location_not_in" property that was not
1102 	// triggered.  This means the current type suppression
1103 	// doesn't suppress the type given.
1104 	return false;
1105     }
1106 
1107   return true;
1108 }
1109 
1110 /// Test if a type suppression matches a type.
1111 ///
1112 /// @param s the type suppression to consider.
1113 ///
1114 /// @param type the type to consider.
1115 ///
1116 /// @return true iff the suppression @p s matches type @p type.
1117 bool
suppression_matches_type_location(const type_suppression & s,const type_base_sptr & type)1118 suppression_matches_type_location(const type_suppression&	s,
1119 				  const type_base_sptr&	type)
1120 {
1121   location loc = get_location(type);
1122   if (loc)
1123     return suppression_matches_type_location(s, loc);
1124   else
1125     {
1126       // The type had no source location.
1127       //
1128       // In the case where this type suppression was automatically
1129       // generated to suppress types not defined in public
1130       // headers, then this might mean that the type is not
1131       // defined in the public headers.  Otherwise, why does it
1132       // not have a source location?
1133       if (s.get_is_artificial())
1134 	{
1135 	  if (class_decl_sptr cl = is_class_type(type))
1136 	    {
1137 	      if (cl->get_is_declaration_only())
1138 		// We tried hard above to get the definition of
1139 		// the declaration.  If we reach this place, it
1140 		// means the class has no definition at this point.
1141 		ABG_ASSERT(!cl->get_definition_of_declaration());
1142 	      if (s.get_label() == get_private_types_suppr_spec_label())
1143 		// So this looks like what really amounts to an
1144 		// opaque type.  So it's not defined in the public
1145 		// headers.  So we want to filter it out.
1146 		return true;
1147 	    }
1148 	}
1149       if (!s.get_source_locations_to_keep().empty()
1150 	  || s.priv_->get_source_location_to_keep_regex())
1151 	// The user provided a "source_location_not_regexp" or
1152 	// a "source_location_not_in" property that was not
1153 	// triggered.  This means the current type suppression
1154 	// doesn't suppress the type given.
1155 	return false;
1156     }
1157 
1158   return true;
1159 }
1160 
1161 /// Test if a type suppression matches a type name and location.
1162 ///
1163 /// @param s the type suppression to consider.
1164 ///
1165 /// @param type_name the name of the type to consider.
1166 ///
1167 /// @param type_location the location of the type to consider.
1168 ///
1169 /// @return true iff suppression @p s matches a type named @p
1170 /// type_name with a location @p type_location.
1171 bool
suppression_matches_type_name_or_location(const type_suppression & s,const string & type_name,const location & type_location)1172 suppression_matches_type_name_or_location(const type_suppression& s,
1173 					  const string& type_name,
1174 					  const location& type_location)
1175 {
1176   if (!suppression_matches_type_name(s, type_name))
1177     return false;
1178   if (!suppression_matches_type_location(s, type_location))
1179     return false;
1180   return true;
1181 }
1182 
1183 /// Test if the current instance of @ref type_suppression matches a
1184 /// given type.
1185 ///
1186 /// @param type the type to consider.
1187 ///
1188 /// @return true iff the suppression specification suppresses type @p
1189 /// type.
1190 bool
suppresses_type(const type_base_sptr & type) const1191 type_suppression::suppresses_type(const type_base_sptr& type) const
1192 {
1193   if (!suppression_matches_type_no_name(*this, type))
1194     return false;
1195 
1196   if (!suppression_matches_type_name(*this, get_name(type)))
1197     return false;
1198 
1199   return true;
1200 }
1201 
1202 /// Test if the current instance of @ref type_suppression matches a
1203 /// given type in a given scope.
1204 ///
1205 /// @param type the type to consider.
1206 ///
1207 /// @param type_scope the scope of type @p type.
1208 ///
1209 /// @return true iff the suppression specification suppresses type @p
1210 /// type from scope @p type_scope.
1211 bool
suppresses_type(const type_base_sptr & type,const scope_decl * type_scope) const1212 type_suppression::suppresses_type(const type_base_sptr& type,
1213 				  const scope_decl* type_scope) const
1214 {
1215   if (!suppression_matches_type_no_name(*this, type))
1216     return false;
1217 
1218   if (!suppression_matches_type_name(*this, type_scope, type))
1219     return false;
1220 
1221   return true;
1222 }
1223 
1224 /// The private data of type_suppression::insertion_range
1225 struct type_suppression::insertion_range::priv
1226 {
1227   boundary_sptr begin_;
1228   boundary_sptr end_;
1229 
privabigail::suppr::type_suppression::insertion_range::priv1230   priv()
1231   {}
1232 
privabigail::suppr::type_suppression::insertion_range::priv1233   priv(boundary_sptr begin, boundary_sptr end)
1234     : begin_(begin), end_(end)
1235   {}
1236 }; // end struct type_suppression::insertion_range::priv
1237 
1238 /// Default Constructor of @ref type_suppression::insertion_range.
insertion_range()1239 type_suppression::insertion_range::insertion_range()
1240   : priv_(new priv)
1241 {}
1242 
1243 /// Constructor of @ref type_suppression::insertion_range.
1244 ///
1245 /// @param begin the start of the range.  A range boundary that is an
1246 /// instance of @ref interger_boundary with a negative value means the
1247 /// maximum possible value.
1248 ///
1249 /// @param end the end of the range.  A range boundary that is an
1250 /// instance of @ref interger_boundary with a negative value means the
1251 /// maximum possible value.
insertion_range(boundary_sptr begin,boundary_sptr end)1252 type_suppression::insertion_range::insertion_range(boundary_sptr begin,
1253 						   boundary_sptr end)
1254   : priv_(new priv(begin, end))
1255 {}
1256 
1257 /// Getter for the beginning of the range.
1258 ///
1259 /// @return the beginning of the range.  A range boundary that is an
1260 /// instance of @ref interger_boundary with a negative value means the
1261 /// maximum possible value.
1262 type_suppression::insertion_range::boundary_sptr
begin() const1263 type_suppression::insertion_range::begin() const
1264 {return priv_->begin_;}
1265 
1266 /// Getter for the end of the range.
1267 ///
1268 /// @return the end of the range.  A range boundary that is an
1269 /// instance of @ref interger_boundary with a negative value means the
1270 /// maximum possible value.
1271 type_suppression::insertion_range::boundary_sptr
end() const1272 type_suppression::insertion_range::end() const
1273 {return priv_->end_;}
1274 
1275 /// Create an integer boundary.
1276 ///
1277 /// The return value of this function is to be used as a boundary for
1278 /// an instance of @ref type_suppression::insertion_range.  That
1279 /// boundary evaluates to an integer value.
1280 ///
1281 /// @param value the value of the integer boundary.
1282 ///
1283 /// @return the resulting integer boundary.
1284 type_suppression::insertion_range::integer_boundary_sptr
create_integer_boundary(int value)1285 type_suppression::insertion_range::create_integer_boundary(int value)
1286 {return integer_boundary_sptr(new integer_boundary(value));}
1287 
1288 /// Create a function call expression boundary.
1289 ///
1290 /// The return value of this function is to be used as a boundary for
1291 /// an instance of @ref type_suppression::insertion_range.  The value
1292 /// of that boundary is actually a function call expression that
1293 /// itself evalutates to an integer value, in the context of a @ref
1294 /// class_decl.
1295 ///
1296 /// @param expr the function call expression to create the boundary from.
1297 ///
1298 /// @return the resulting function call expression boundary.
1299 type_suppression::insertion_range::fn_call_expr_boundary_sptr
create_fn_call_expr_boundary(ini::function_call_expr_sptr expr)1300 type_suppression::insertion_range::create_fn_call_expr_boundary(ini::function_call_expr_sptr expr)
1301 {return fn_call_expr_boundary_sptr(new fn_call_expr_boundary(expr));}
1302 
1303 /// Create a function call expression boundary.
1304 ///
1305 /// The return value of this function is to be used as a boundary for
1306 /// an instance of @ref type_suppression::insertion_range.  The value
1307 /// of that boundary is actually a function call expression that
1308 /// itself evalutates to an integer value, in the context of a @ref
1309 /// class_decl.
1310 ///
1311 /// @param s a string representing the expression the function call
1312 /// expression to create the boundary from.
1313 ///
1314 /// @return the resulting function call expression boundary.
1315 type_suppression::insertion_range::fn_call_expr_boundary_sptr
create_fn_call_expr_boundary(const string & s)1316 type_suppression::insertion_range::create_fn_call_expr_boundary(const string& s)
1317 {
1318   fn_call_expr_boundary_sptr result, nil;
1319   ini::function_call_expr_sptr expr;
1320   if (ini::read_function_call_expr(s, expr) && expr)
1321     result.reset(new fn_call_expr_boundary(expr));
1322   return result;
1323 }
1324 
1325 /// Evaluate an insertion range boundary to get a resulting integer
1326 /// value.
1327 ///
1328 /// @param boundary the boundary to evaluate.
1329 ///
1330 /// @param context the context of evualuation.  It's a @ref class_decl
1331 /// to take into account during the evaluation, if there is a need for
1332 /// it.
1333 ///
1334 /// @return true iff the evaluation was successful and @p value
1335 /// contains the resulting value.
1336 bool
eval_boundary(boundary_sptr boundary,class_decl_sptr context,uint64_t & value)1337 type_suppression::insertion_range::eval_boundary(boundary_sptr	 boundary,
1338 						 class_decl_sptr context,
1339 						 uint64_t&	 value)
1340 {
1341   if (integer_boundary_sptr b = is_integer_boundary(boundary))
1342     {
1343       value = b->as_integer();
1344       return true;
1345     }
1346   else if (fn_call_expr_boundary_sptr b = is_fn_call_expr_boundary(boundary))
1347     {
1348       ini::function_call_expr_sptr fn_call = b->as_function_call_expr();
1349       if ((fn_call->get_name() == "offset_of"
1350 	   || fn_call->get_name() == "offset_after")
1351 	  && fn_call->get_arguments().size() == 1)
1352 	{
1353 	  string member_name = fn_call->get_arguments()[0];
1354 	  for (class_decl::data_members::const_iterator it =
1355 		 context->get_data_members().begin();
1356 	       it != context->get_data_members().end();
1357 	       ++it)
1358 	    {
1359 	      if (!get_data_member_is_laid_out(**it))
1360 		continue;
1361 	      if ((*it)->get_name() == member_name)
1362 		{
1363 		  if (fn_call->get_name() == "offset_of")
1364 		    value = get_data_member_offset(*it);
1365 		  else if (fn_call->get_name() == "offset_after")
1366 		    {
1367 		      if (!get_next_data_member_offset(context, *it, value))
1368 			{
1369 			  value = get_data_member_offset(*it) +
1370 			    (*it)->get_type()->get_size_in_bits();
1371 			}
1372 		    }
1373 		  else
1374 		    // We should not reach this point.
1375 		    abort();
1376 		  return true;
1377 		}
1378 	    }
1379 	}
1380     }
1381   return false;
1382 }
1383 
1384 /// Test if a given value supposed to be inside an insertion range
1385 /// represents the end of the range.
1386 ///
1387 /// @param value the value to test for.
1388 ///
1389 /// @return true iff @p value represents the end of the insertion
1390 /// range.
1391 bool
boundary_value_is_end(uint64_t value)1392 type_suppression::insertion_range::boundary_value_is_end(uint64_t value)
1393 {
1394   return value == std::numeric_limits<uint64_t>::max();
1395 }
1396 
1397 /// Tests if a given instance of @ref
1398 /// type_suppression::insertion_range::boundary is actually an integer boundary.
1399 ///
1400 /// @param b the boundary to test.
1401 ///
1402 /// @return a pointer to the instance of
1403 /// type_suppression::insertion_range::integer_boundary if @p b is
1404 /// actually an integer boundary.  Otherwise, return a null pointer.
1405 type_suppression::insertion_range::integer_boundary_sptr
is_integer_boundary(type_suppression::insertion_range::boundary_sptr b)1406 is_integer_boundary(type_suppression::insertion_range::boundary_sptr b)
1407 {return dynamic_pointer_cast<type_suppression::insertion_range::integer_boundary>(b);}
1408 
1409 /// Tests if a given instance of @ref
1410 /// type_suppression::insertion_range::boundary is actually an function call expression boundary.
1411 ///
1412 /// @param b the boundary to test.
1413 ///
1414 /// @return a pointer to the instance of
1415 /// type_suppression::insertion_range::fn_call_expr_boundary if @p b
1416 /// is actually an function call expression boundary.  Otherwise,
1417 /// return a null pointer.
1418 type_suppression::insertion_range::fn_call_expr_boundary_sptr
is_fn_call_expr_boundary(type_suppression::insertion_range::boundary_sptr b)1419 is_fn_call_expr_boundary(type_suppression::insertion_range::boundary_sptr b)
1420 {return dynamic_pointer_cast<type_suppression::insertion_range::fn_call_expr_boundary>(b);}
1421 
1422 /// The private data type of @ref
1423 /// type_suppression::insertion_range::boundary.
1424 struct type_suppression::insertion_range::boundary::priv
1425 {
privabigail::suppr::type_suppression::insertion_range::boundary::priv1426   priv()
1427   {}
1428 }; // end struct type_suppression::insertion_range::boundary::priv
1429 
1430 /// Default constructor of @ref
1431 /// type_suppression::insertion_range::boundary
boundary()1432 type_suppression::insertion_range::boundary::boundary()
1433   : priv_(new priv())
1434 {}
1435 
1436 /// Destructor of @ref type_suppression::insertion_range::boundary.
~boundary()1437 type_suppression::insertion_range::boundary::~boundary()
1438 {}
1439 
1440 /// Private data type for @ref
1441 /// type_suppression::insertion_range::integer_boundary.
1442 struct type_suppression::insertion_range::integer_boundary::priv
1443 {
1444   uint64_t value_;
1445 
privabigail::suppr::type_suppression::insertion_range::integer_boundary::priv1446   priv()
1447     : value_()
1448   {}
1449 
privabigail::suppr::type_suppression::insertion_range::integer_boundary::priv1450   priv(uint64_t value)
1451     : value_(value)
1452   {}
1453 }; // end type_suppression::insertion_range::integer_boundary::priv
1454 
1455 /// Converting constructor of
1456 /// type_suppression::insertion_range::integer_boundary.
1457 ///
1458 /// @param value the integer value of the newly created integer boundary.
integer_boundary(uint64_t value)1459 type_suppression::insertion_range::integer_boundary::integer_boundary(uint64_t value)
1460   : priv_(new priv(value))
1461 {}
1462 
1463 /// Return the integer value of the current instance of @ref
1464 /// type_suppression::insertion_range::integer_boundary.
1465 ///
1466 /// @return the integer value of the current boundary.
1467 uint64_t
as_integer() const1468 type_suppression::insertion_range::integer_boundary::as_integer() const
1469 {return priv_->value_;}
1470 
1471 /// Converts the current boundary into an integer value.
1472 ///
1473 /// @return the integer value of the current boundary.
operator uint64_t() const1474 type_suppression::insertion_range::integer_boundary::operator uint64_t() const
1475 {return as_integer();}
1476 
1477 /// Destructor of @ref type_suppression::insertion_range::integer_boundary.
~integer_boundary()1478 type_suppression::insertion_range::integer_boundary::~integer_boundary()
1479 {}
1480 
1481 /// Private data type of type @ref
1482 /// type_suppression::insertion_range::fn_call_expr_boundary.
1483 struct type_suppression::insertion_range::fn_call_expr_boundary::priv
1484 {
1485   ini::function_call_expr_sptr expr_;
1486 
privabigail::suppr::type_suppression::insertion_range::fn_call_expr_boundary::priv1487   priv()
1488   {}
1489 
privabigail::suppr::type_suppression::insertion_range::fn_call_expr_boundary::priv1490   priv(ini::function_call_expr_sptr expr)
1491     : expr_(expr)
1492   {}
1493 }; // end struct type_suppression::insertion_range::fn_call_expr_boundary::priv
1494 
1495 /// Converting constructor for @ref
1496 /// type_suppression::insertion_range::fn_call_expr_boundary.
1497 ///
1498 /// @param expr the function call expression to build this boundary
1499 /// from.
1500 type_suppression::insertion_range::fn_call_expr_boundary::
fn_call_expr_boundary(ini::function_call_expr_sptr expr)1501 fn_call_expr_boundary(ini::function_call_expr_sptr expr)
1502   : priv_(new priv(expr))
1503 {}
1504 
1505 /// Returns the function call expression value of the current boundary.
1506 ///
1507 /// @return the function call expression value of the current boundary;
1508 ini::function_call_expr_sptr
as_function_call_expr() const1509 type_suppression::insertion_range::fn_call_expr_boundary::as_function_call_expr() const
1510 {return priv_->expr_;}
1511 
1512 /// Converts the current boundary to its function call expression value.
1513 ///
1514 /// @return the function call expression value of the current boundary.
operator ini::function_call_expr_sptr() const1515 type_suppression::insertion_range::fn_call_expr_boundary::operator ini::function_call_expr_sptr () const
1516 {return as_function_call_expr();}
1517 
1518 /// Destructor of @ref
1519 /// type_suppression::insertion_range::fn_call_expr_boundary.
~fn_call_expr_boundary()1520 type_suppression::insertion_range::fn_call_expr_boundary::~fn_call_expr_boundary()
1521 {}
1522 
1523 /// Test if an instance of @ref suppression is an instance of @ref
1524 /// type_suppression.
1525 ///
1526 /// @param suppr the instance of @ref suppression to test for.
1527 ///
1528 /// @return if @p suppr is an instance of @ref type_suppression, then
1529 /// return the sub-object of the @p suppr of type @ref
1530 /// type_suppression, otherwise return a nil pointer.
1531 type_suppression_sptr
is_type_suppression(suppression_sptr suppr)1532 is_type_suppression(suppression_sptr suppr)
1533 {return dynamic_pointer_cast<type_suppression>(suppr);}
1534 
1535 // </type_suppression stuff>
1536 
1537 /// Parse the value of the "type_kind" property in the "suppress_type"
1538 /// section.
1539 ///
1540 /// @param input the input string representing the value of the
1541 /// "type_kind" property.
1542 ///
1543 /// @return the @ref type_kind enumerator parsed.
1544 static type_suppression::type_kind
read_type_kind_string(const string & input)1545 read_type_kind_string(const string& input)
1546 {
1547   if (input == "class")
1548     return type_suppression::CLASS_TYPE_KIND;
1549   else if (input == "struct")
1550     return type_suppression::STRUCT_TYPE_KIND;
1551   else if (input == "union")
1552     return type_suppression::UNION_TYPE_KIND;
1553   else if (input == "enum")
1554     return type_suppression::ENUM_TYPE_KIND;
1555   else if (input == "array")
1556     return type_suppression::ARRAY_TYPE_KIND;
1557   else if (input == "typedef")
1558     return type_suppression::TYPEDEF_TYPE_KIND;
1559   else if (input == "builtin")
1560     return type_suppression::BUILTIN_TYPE_KIND;
1561   else
1562     return type_suppression::UNKNOWN_TYPE_KIND;
1563 }
1564 
1565 /// Parse the value of the "accessed_through" property in the
1566 /// "suppress_type" section.
1567 ///
1568 /// @param input the input string representing the value of the
1569 /// "accessed_through" property.
1570 ///
1571 /// @return the @ref type_suppression::reach_kind enumerator parsed.
1572 static type_suppression::reach_kind
read_suppression_reach_kind(const string & input)1573 read_suppression_reach_kind(const string& input)
1574 {
1575   if (input == "direct")
1576     return type_suppression::DIRECT_REACH_KIND;
1577   else if (input == "pointer")
1578     return type_suppression::POINTER_REACH_KIND;
1579   else if (input == "reference")
1580     return type_suppression::REFERENCE_REACH_KIND;
1581   else if (input == "reference-or-pointer")
1582     return type_suppression::REFERENCE_OR_POINTER_REACH_KIND;
1583   else
1584     return type_suppression::DIRECT_REACH_KIND;
1585 }
1586 
1587 /// Read a type suppression from an instance of ini::config::section
1588 /// and build a @ref type_suppression as a result.
1589 ///
1590 /// @param section the section of the ini config to read.
1591 ///
1592 /// @return the resulting @ref type_suppression upon successful
1593 /// parsing, or nil.
1594 static type_suppression_sptr
read_type_suppression(const ini::config::section & section)1595 read_type_suppression(const ini::config::section& section)
1596 {
1597   type_suppression_sptr result;
1598 
1599   if (section.get_name() != "suppress_type")
1600     return result;
1601 
1602   static const char *const sufficient_props[] = {
1603     "file_name_regexp",
1604     "file_name_not_regexp",
1605     "soname_regexp",
1606     "soname_not_regexp",
1607     "name",
1608     "name_regexp",
1609     "name_not_regexp",
1610     "type_kind",
1611     "source_location_not_in",
1612     "source_location_not_regexp",
1613   };
1614   if (!check_sufficient_props(sufficient_props,
1615 			      sizeof(sufficient_props)/sizeof(char*),
1616 			      section))
1617     return result;
1618 
1619   ini::simple_property_sptr drop_artifact =
1620     is_simple_property(section.find_property("drop_artifact"));
1621   if (!drop_artifact)
1622     drop_artifact = is_simple_property(section.find_property("drop"));
1623 
1624   string drop_artifact_str = drop_artifact
1625     ? drop_artifact->get_value()->as_string()
1626     : "";
1627 
1628   ini::simple_property_sptr label =
1629     is_simple_property(section.find_property("label"));
1630   string label_str = label ? label->get_value()->as_string() : "";
1631 
1632   ini::simple_property_sptr file_name_regex_prop =
1633     is_simple_property(section.find_property("file_name_regexp"));
1634   string file_name_regex_str =
1635     file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
1636 
1637   ini::simple_property_sptr file_name_not_regex_prop =
1638     is_simple_property(section.find_property("file_name_not_regexp"));
1639   string file_name_not_regex_str =
1640     file_name_not_regex_prop
1641     ? file_name_not_regex_prop->get_value()->as_string()
1642     : "";
1643 
1644   ini::simple_property_sptr soname_regex_prop =
1645     is_simple_property(section.find_property("soname_regexp"));
1646   string soname_regex_str =
1647     soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
1648 
1649   ini::simple_property_sptr soname_not_regex_prop =
1650     is_simple_property(section.find_property("soname_not_regexp"));
1651   string soname_not_regex_str =
1652     soname_not_regex_prop
1653     ? soname_not_regex_prop->get_value()->as_string()
1654     : "";
1655 
1656   ini::simple_property_sptr name_regex_prop =
1657     is_simple_property(section.find_property("name_regexp"));
1658   string name_regex_str = name_regex_prop
1659     ? name_regex_prop->get_value()->as_string()
1660     : "";
1661 
1662   ini::simple_property_sptr name_not_regex_prop =
1663     is_simple_property(section.find_property("name_not_regexp"));
1664   string name_not_regex_str = name_not_regex_prop
1665     ? name_not_regex_prop->get_value()->as_string()
1666     : "";
1667 
1668   ini::simple_property_sptr name_prop =
1669     is_simple_property(section.find_property("name"));
1670   string name_str = name_prop
1671     ? name_prop->get_value()->as_string()
1672     : "";
1673 
1674   ini::property_sptr srcloc_not_in_prop =
1675     section.find_property("source_location_not_in");
1676   unordered_set<string> srcloc_not_in;
1677   if (srcloc_not_in_prop)
1678     {
1679       if (ini::simple_property_sptr p = is_simple_property(srcloc_not_in_prop))
1680 	srcloc_not_in.insert(p->get_value()->as_string());
1681       else
1682 	{
1683 	  ini::list_property_sptr list_property =
1684 	    is_list_property(srcloc_not_in_prop);
1685 	  if (list_property)
1686 	    {
1687 	      vector<string>::const_iterator i;
1688 	      for (i = list_property->get_value()->get_content().begin();
1689 		   i != list_property->get_value()->get_content().end();
1690 		   ++i)
1691 		srcloc_not_in.insert(*i);
1692 	    }
1693 	}
1694     }
1695 
1696   ini::simple_property_sptr srcloc_not_regexp_prop =
1697     is_simple_property(section.find_property("source_location_not_regexp"));
1698   string srcloc_not_regexp_str;
1699   if (srcloc_not_regexp_prop)
1700     srcloc_not_regexp_str = srcloc_not_regexp_prop->get_value()->as_string();
1701 
1702   bool consider_type_kind = false;
1703   type_suppression::type_kind type_kind = type_suppression::UNKNOWN_TYPE_KIND;
1704   if (ini::simple_property_sptr type_kind_prop =
1705       is_simple_property(section.find_property("type_kind")))
1706     {
1707       consider_type_kind = true;
1708       type_kind =
1709 	read_type_kind_string(type_kind_prop->get_value()->as_string());
1710     }
1711 
1712   bool consider_reach_kind = false;
1713   type_suppression::reach_kind reach_kind = type_suppression::DIRECT_REACH_KIND;
1714   if (ini::simple_property_sptr reach_kind_prop =
1715       is_simple_property(section.find_property("accessed_through")))
1716     {
1717       consider_reach_kind = true;
1718       reach_kind =
1719 	read_suppression_reach_kind(reach_kind_prop->get_value()->as_string());
1720     }
1721 
1722   // Support has_data_member_inserted_at
1723   vector<type_suppression::insertion_range_sptr> insert_ranges;
1724   bool consider_data_member_insertion = false;
1725   if (ini::simple_property_sptr prop =
1726       is_simple_property(section.find_property("has_data_member_inserted_at")))
1727     {
1728       // So this property has the form:
1729       //   has_data_member_inserted_at = <one-string-property-value>
1730       string ins_point = prop->get_value()->as_string();
1731       type_suppression::insertion_range::boundary_sptr begin, end;
1732       if (ins_point == "end")
1733 	begin = type_suppression::insertion_range::create_integer_boundary(-1);
1734       else if (isdigit(ins_point[0]))
1735 	begin = type_suppression::insertion_range::create_integer_boundary
1736 	  (atoi(ins_point.c_str()));
1737       else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1738 	       type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(ins_point)))
1739 	begin = expr;
1740       else
1741 	return result;
1742 
1743       end = type_suppression::insertion_range::create_integer_boundary(-1);
1744       type_suppression::insertion_range_sptr insert_range
1745 	(new type_suppression::insertion_range(begin, end));
1746 	  insert_ranges.push_back(insert_range);
1747 	  consider_data_member_insertion = true;
1748     }
1749 
1750   // Support has_data_member_inserted_between
1751   if (ini::tuple_property_sptr prop =
1752       is_tuple_property(section.find_property
1753 			("has_data_member_inserted_between")))
1754     {
1755       // ensures that this has the form:
1756       //  has_data_member_inserted_between = {0 , end};
1757       // and not (for instance):
1758       //  has_data_member_inserted_between = {{0 , end}, {1, foo}}
1759       //
1760       //  This means that the tuple_property_value contains just one
1761       //  value, which is a list_property that itself contains 2
1762       //  values.
1763       type_suppression::insertion_range::boundary_sptr begin, end;
1764       ini::tuple_property_value_sptr v = prop->get_value();
1765       if (v
1766 	  && v->get_value_items().size() == 1
1767 	  && is_list_property_value(v->get_value_items()[0])
1768 	  && is_list_property_value(v->get_value_items()[0])->get_content().size() == 2)
1769 	{
1770 	  ini::list_property_value_sptr val =
1771 	    is_list_property_value(v->get_value_items()[0]);
1772 	  ABG_ASSERT(val);
1773 	  string str = val->get_content()[0];
1774 	  if (str == "end")
1775 	    begin =
1776 	      type_suppression::insertion_range::create_integer_boundary(-1);
1777 	  else if (isdigit(str[0]))
1778 	    begin = type_suppression::insertion_range::create_integer_boundary
1779 	      (atoi(str.c_str()));
1780 	  else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1781 		   type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1782 	    begin = expr;
1783 	  else
1784 	    return result;
1785 
1786 	  str = val->get_content()[1];
1787 	  if (str == "end")
1788 	    end =
1789 	      type_suppression::insertion_range::create_integer_boundary(-1);
1790 	  else if (isdigit(str[0]))
1791 	    end = type_suppression::insertion_range::create_integer_boundary
1792 	      (atoi(str.c_str()));
1793 	  else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1794 		   type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1795 	    end = expr;
1796 	  else
1797 	    return result;
1798 
1799 	  type_suppression::insertion_range_sptr insert_range
1800 	    (new type_suppression::insertion_range(begin, end));
1801 	  insert_ranges.push_back(insert_range);
1802 	  consider_data_member_insertion = true;
1803 	}
1804       else
1805 	// the 'has_data_member_inserted_between' property has a wrong
1806 	// value type, so let's discard the endire [suppress_type]
1807 	// section.
1808 	return result;
1809     }
1810 
1811   // Support has_data_members_inserted_between
1812   // The syntax looks like:
1813   //
1814   //    has_data_members_inserted_between = {{8, 24}, {32, 64}, {128, end}}
1815   //
1816   // So we expect a tuple property, with potentially several pairs (as
1817   // part of the value); each pair designating a range.  Note that
1818   // each pair (range) is a list property value.
1819   if (ini::tuple_property_sptr prop =
1820       is_tuple_property(section.find_property
1821 			("has_data_members_inserted_between")))
1822     {
1823       bool is_well_formed = true;
1824       for (vector<ini::property_value_sptr>::const_iterator i =
1825 	     prop->get_value()->get_value_items().begin();
1826 	   is_well_formed && i != prop->get_value()->get_value_items().end();
1827 	   ++i)
1828 	{
1829 	  ini::tuple_property_value_sptr tuple_value =
1830 	    is_tuple_property_value(*i);
1831 	  if (!tuple_value
1832 	      || tuple_value->get_value_items().size() != 1
1833 	      || !is_list_property_value(tuple_value->get_value_items()[0]))
1834 	    {
1835 	      is_well_formed = false;
1836 	      break;
1837 	    }
1838 	  ini::list_property_value_sptr list_value =
1839 	    is_list_property_value(tuple_value->get_value_items()[0]);
1840 	  if (list_value->get_content().size() != 2)
1841 	    {
1842 	      is_well_formed = false;
1843 	      break;
1844 	    }
1845 
1846 	  type_suppression::insertion_range::boundary_sptr begin, end;
1847 	  string str = list_value->get_content()[0];
1848 	  if (str == "end")
1849 	    begin =
1850 	      type_suppression::insertion_range::create_integer_boundary(-1);
1851 	  else if (isdigit(str[0]))
1852 	    begin =
1853 	      type_suppression::insertion_range::create_integer_boundary
1854 	      (atoi(str.c_str()));
1855 	  else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1856 		   type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1857 	    begin = expr;
1858 	  else
1859 	    return result;
1860 
1861 	  str = list_value->get_content()[1];
1862 	  if (str == "end")
1863 	    end =
1864 	      type_suppression::insertion_range::create_integer_boundary(-1);
1865 	  else if (isdigit(str[0]))
1866 	    end = type_suppression::insertion_range::create_integer_boundary
1867 	      (atoi(str.c_str()));
1868 	  else if (type_suppression::insertion_range::fn_call_expr_boundary_sptr expr =
1869 		   type_suppression::insertion_range::create_fn_call_expr_boundary(ini::read_function_call_expr(str)))
1870 	    end = expr;
1871 	  else
1872 	    return result;
1873 
1874 	  type_suppression::insertion_range_sptr insert_range
1875 	    (new type_suppression::insertion_range(begin, end));
1876 	  insert_ranges.push_back(insert_range);
1877 	  consider_data_member_insertion = true;
1878 	}
1879       if (!is_well_formed)
1880 	return result;
1881     }
1882 
1883   /// Support 'changed_enumerators = foo, bar, baz'
1884   ///
1885   /// Note that this constraint is valid only if we have:
1886   ///   'type_kind = enum'.
1887   ///
1888   /// If the current type is an enum and if it carries changed
1889   /// enumerators listed in the changed_enumerators property value
1890   /// then it should be suppressed.
1891 
1892   ini::property_sptr changed_enumerators_prop =
1893     section.find_property("changed_enumerators");
1894 
1895   vector<string> changed_enumerator_names;
1896   if (changed_enumerators_prop)
1897     {
1898       if (ini::list_property_sptr p =
1899 	  is_list_property(changed_enumerators_prop))
1900 	changed_enumerator_names =
1901 	  p->get_value()->get_content();
1902       else if (ini::simple_property_sptr p =
1903 	       is_simple_property(changed_enumerators_prop))
1904 	changed_enumerator_names.push_back(p->get_value()->as_string());
1905     }
1906 
1907   result.reset(new type_suppression(label_str, name_regex_str, name_str));
1908 
1909   if (consider_type_kind)
1910     {
1911       result->set_consider_type_kind(true);
1912       result->set_type_kind(type_kind);
1913     }
1914 
1915   if (consider_reach_kind)
1916     {
1917       result->set_consider_reach_kind(true);
1918       result->set_reach_kind(reach_kind);
1919     }
1920 
1921   if (consider_data_member_insertion)
1922     result->set_data_member_insertion_ranges(insert_ranges);
1923 
1924   if (!name_not_regex_str.empty())
1925     result->set_type_name_not_regex_str(name_not_regex_str);
1926 
1927   if (!file_name_regex_str.empty())
1928     result->set_file_name_regex_str(file_name_regex_str);
1929 
1930   if (!file_name_not_regex_str.empty())
1931     result->set_file_name_not_regex_str(file_name_not_regex_str);
1932 
1933   if (!soname_regex_str.empty())
1934     result->set_soname_regex_str(soname_regex_str);
1935 
1936   if (!soname_not_regex_str.empty())
1937     result->set_soname_not_regex_str(soname_not_regex_str);
1938 
1939   if (!srcloc_not_in.empty())
1940     result->set_source_locations_to_keep(srcloc_not_in);
1941 
1942   if (!srcloc_not_regexp_str.empty())
1943     result->set_source_location_to_keep_regex_str(srcloc_not_regexp_str);
1944 
1945   if ((drop_artifact_str == "yes" || drop_artifact_str == "true")
1946       && ((!name_regex_str.empty()
1947 	   || !name_str.empty()
1948 	   || !srcloc_not_regexp_str.empty()
1949 	   || !srcloc_not_in.empty())))
1950     result->set_drops_artifact_from_ir(true);
1951 
1952   if (result->get_type_kind() == type_suppression::ENUM_TYPE_KIND
1953       && !changed_enumerator_names.empty())
1954     result->set_changed_enumerator_names(changed_enumerator_names);
1955 
1956   return result;
1957 }
1958 
1959 // <function_suppression stuff>
1960 
1961 /// Constructor for the @ref the function_suppression::parameter_spec
1962 /// type.
1963 ///
1964 /// @param i the index of the parameter designated by this specification.
1965 ///
1966 /// @param tn the type name of the parameter designated by this specification.
1967 ///
1968 /// @param tn_regex a regular expression that defines a set of type
1969 /// names for the parameter designated by this specification.  Note
1970 /// that at evaluation time, this regular expression is taken in
1971 /// account only if the parameter @p tn is empty.
parameter_spec(size_t i,const string & tn,const string & tn_regex)1972 function_suppression::parameter_spec::parameter_spec(size_t i,
1973 						     const string& tn,
1974 						     const string& tn_regex)
1975   : priv_(new priv(i, tn, tn_regex))
1976 {}
1977 
1978 /// Getter for the index of the parameter designated by this
1979 /// specification.
1980 ///
1981 /// @return the index of the parameter designated by this
1982 /// specification.
1983 size_t
get_index() const1984 function_suppression::parameter_spec::get_index() const
1985 {return priv_->index_;}
1986 
1987 /// Setter for the index of the parameter designated by this
1988 /// specification.
1989 ///
1990 /// @param i the new index to set.
1991 void
set_index(size_t i)1992 function_suppression::parameter_spec::set_index(size_t i)
1993 {priv_->index_ = i;}
1994 
1995 /// Getter for the type name of the parameter designated by this specification.
1996 ///
1997 /// @return the type name of the parameter.
1998 const string&
get_parameter_type_name() const1999 function_suppression::parameter_spec::get_parameter_type_name() const
2000 {return priv_->type_name_;}
2001 
2002 /// Setter for the type name of the parameter designated by this
2003 /// specification.
2004 ///
2005 /// @param tn new parameter type name to set.
2006 void
set_parameter_type_name(const string & tn)2007 function_suppression::parameter_spec::set_parameter_type_name(const string& tn)
2008 {priv_->type_name_ = tn;}
2009 
2010 /// Getter for the regular expression that defines a set of type names
2011 /// for the parameter designated by this specification.
2012 ///
2013 /// Note that at evaluation time, this regular expression is taken in
2014 /// account only if the name of the parameter as returned by
2015 /// function_suppression::parameter_spec::get_parameter_type_name() is
2016 /// empty.
2017 ///
2018 /// @return the regular expression or the parameter type name.
2019 const string&
get_parameter_type_name_regex_str() const2020 function_suppression::parameter_spec::get_parameter_type_name_regex_str() const
2021 {return priv_->type_name_regex_str_;}
2022 
2023 /// Setter for the regular expression that defines a set of type names
2024 /// for the parameter designated by this specification.
2025 ///
2026 /// Note that at evaluation time, this regular expression is taken in
2027 /// account only if the name of the parameter as returned by
2028 /// function_suppression::parameter_spec::get_parameter_type_name() is
2029 /// empty.
2030 ///
2031 /// @param type_name_regex_str the new type name regular expression to
2032 /// set.
2033 void
set_parameter_type_name_regex_str(const string & type_name_regex_str)2034 function_suppression::parameter_spec::set_parameter_type_name_regex_str
2035 (const string& type_name_regex_str)
2036 {priv_->type_name_regex_str_ = type_name_regex_str;}
2037 
2038 /// Default constructor for the @ref function_suppression type.
2039 ///
2040 /// It defines no suppression for now.  Suppressions have to be
2041 /// specified by using the various accessors of the @ref
2042 /// function_suppression type.
function_suppression()2043 function_suppression::function_suppression()
2044   :  suppression_base(/*label=*/""), priv_(new priv)
2045 {}
2046 
2047 /// Constructor for the @ref function_suppression type.
2048 ///
2049 /// @param label an informative text string that the evalution code
2050 /// might use to designate this function suppression specification in
2051 /// error messages.  This parameter might be empty, in which case it's
2052 /// ignored at evaluation time.
2053 ///
2054 /// @param the name of the function the user wants the current
2055 /// specification to designate.  This parameter might be empty, in
2056 /// which case it's ignored at evaluation time.
2057 ///
2058 /// @param nr if @p name is empty this parameter is a regular
2059 /// expression for a family of names of functions the user wants the
2060 /// current specification to designate.  If @p name is not empty, this
2061 /// parameter is ignored at specification evaluation time.  This
2062 /// parameter might be empty, in which case it's ignored at evaluation
2063 /// time.
2064 ///
2065 /// @param ret_tn the name of the return type of the function the user
2066 /// wants this specification to designate.  This parameter might be
2067 /// empty, in which case it's ignored at evaluation time.
2068 ///
2069 /// @param ret_tr if @p ret_tn is empty, then this is a regular
2070 /// expression for a family of return type names for functions the
2071 /// user wants the current specification to designate.  If @p ret_tn
2072 /// is not empty, then this parameter is ignored at specification
2073 /// evaluation time.  This parameter might be empty, in which case
2074 /// it's ignored at evaluation time.
2075 ///
2076 /// @param ps a vector of parameter specifications to specify
2077 /// properties of the parameters of the functions the user wants this
2078 /// specification to designate.  This parameter might be empty, in
2079 /// which case it's ignored at evaluation time.
2080 ///
2081 /// @param sym_n the name of symbol of the function the user wants
2082 /// this specification to designate.  This parameter might be empty,
2083 /// in which case it's ignored at evaluation time.
2084 ///
2085 /// @param sym_nr if the parameter @p sym_n is empty, then this
2086 /// parameter is a regular expression for a family of names of symbols
2087 /// of functions the user wants this specification to designate.  If
2088 /// the parameter @p sym_n is not empty, then this parameter is
2089 /// ignored at specification evaluation time.  This parameter might be
2090 /// empty, in which case it's ignored at evaluation time.
2091 ///
2092 /// @param sym_v the name of the version of the symbol of the function
2093 /// the user wants this specification to designate.  This parameter
2094 /// might be empty, in which case it's ignored at evaluation time.
2095 ///
2096 /// @param sym_vr if the parameter @p sym_v is empty, then this
2097 /// parameter is a regular expression for a family of versions of
2098 /// symbols of functions the user wants the current specification to
2099 /// designate.  If the parameter @p sym_v is non empty, then this
2100 /// parameter is ignored.  This parameter might be empty, in which
2101 /// case it's ignored at evaluation time.
function_suppression(const string & label,const string & name,const string & nr,const string & ret_tn,const string & ret_tr,parameter_specs_type & ps,const string & sym_n,const string & sym_nr,const string & sym_v,const string & sym_vr)2102 function_suppression::function_suppression(const string&		label,
2103 					   const string&		name,
2104 					   const string&		nr,
2105 					   const string&		ret_tn,
2106 					   const string&		ret_tr,
2107 					   parameter_specs_type&	ps,
2108 					   const string&		sym_n,
2109 					   const string&		sym_nr,
2110 					   const string&		sym_v,
2111 					   const string&		sym_vr)
2112   : suppression_base(label),
2113     priv_(new priv(name, nr, ret_tn, ret_tr, ps,
2114 		   sym_n, sym_nr, sym_v, sym_vr))
2115 {}
2116 
~function_suppression()2117 function_suppression::~function_suppression()
2118 {}
2119 
2120 /// Parses a string containing the content of the "change-kind"
2121 /// property and returns the an instance of @ref
2122 /// function_suppression::change_kind as a result.
2123 ///
2124 /// @param s the string to parse.
2125 ///
2126 /// @return the resulting @ref function_suppression::change_kind.
2127 function_suppression::change_kind
parse_change_kind(const string & s)2128 function_suppression::parse_change_kind(const string& s)
2129 {
2130   if (s == "function-subtype-change")
2131     return FUNCTION_SUBTYPE_CHANGE_KIND;
2132   else if (s == "added-function")
2133     return ADDED_FUNCTION_CHANGE_KIND;
2134   else if (s == "deleted-function")
2135     return DELETED_FUNCTION_CHANGE_KIND;
2136   else if (s == "all")
2137     return ALL_CHANGE_KIND;
2138   else
2139     return UNDEFINED_CHANGE_KIND;
2140 }
2141 
2142 /// Getter of the "change-kind" property.
2143 ///
2144 /// @param returnthe "change-kind" property.
2145 function_suppression::change_kind
get_change_kind() const2146 function_suppression::get_change_kind() const
2147 {return priv_->change_kind_;}
2148 
2149 /// Setter of the "change-kind" property.
2150 ///
2151 /// @param k the new value of the change_kind property.
2152 void
set_change_kind(change_kind k)2153 function_suppression::set_change_kind(change_kind k)
2154 {priv_->change_kind_ = k;}
2155 
2156 /// Getter for the name of the function the user wants the current
2157 /// specification to designate.  This might be empty, in which case
2158 /// it's ignored at evaluation time.
2159 ///
2160 /// @return the name of the function.
2161 const string&
get_name() const2162 function_suppression::get_name() const
2163 {return priv_->name_;}
2164 
2165 /// Setter for the name of the function the user wants the current
2166 /// specification to designate.  This might be empty, in which case
2167 /// it's ignored at evaluation time.
2168 ///
2169 /// @param n the new function name to set.
2170 void
set_name(const string & n)2171 function_suppression::set_name(const string& n)
2172 {priv_->name_ = n;}
2173 
2174 /// Getter for a regular expression for a family of names of functions
2175 /// the user wants the current specification to designate.
2176 ///
2177 /// @return the regular expression for the possible names of the
2178 /// function(s).
2179 const string&
get_name_regex_str() const2180 function_suppression::get_name_regex_str() const
2181 {return priv_->name_regex_str_;}
2182 
2183 /// Setter for a regular expression for a family of names of functions
2184 /// the user wants the current specification to designate.
2185 ///
2186 /// @param r the new the regular expression for the possible names of
2187 /// the function(s).
2188 void
set_name_regex_str(const string & r)2189 function_suppression::set_name_regex_str(const string& r)
2190 {priv_->name_regex_str_ = r;}
2191 
2192 /// Getter for a regular expression of a family of names of functions
2193 /// the user wants the current specification to designate the negation
2194 /// of.
2195 ///
2196 /// @return the regular expression for the possible names of the
2197 /// function(s).
2198 const string&
get_name_not_regex_str() const2199 function_suppression::get_name_not_regex_str() const
2200 {return priv_->name_not_regex_str_;}
2201 
2202 /// Setter for a regular expression for a family of names of functions
2203 /// the user wants the current specification to designate the negation
2204 /// of.
2205 ///
2206 /// @param r the new the regular expression for the possible names of
2207 /// the function(s).
2208 void
set_name_not_regex_str(const string & r)2209 function_suppression::set_name_not_regex_str(const string& r)
2210 {priv_->name_not_regex_str_ = r;}
2211 
2212 /// Getter for the name of the return type of the function the user
2213 /// wants this specification to designate.  This property might be
2214 /// empty, in which case it's ignored at evaluation time.
2215 ///
2216 /// @return the name of the return type of the function.
2217 const string&
get_return_type_name() const2218 function_suppression::get_return_type_name() const
2219 {return priv_->return_type_name_;}
2220 
2221 /// Setter for the name of the return type of the function the user
2222 /// wants this specification to designate.  This property might be
2223 /// empty, in which case it's ignored at evaluation time.
2224 ///
2225 /// @param tr the new name of the return type of the function to set.
2226 void
set_return_type_name(const string & tr)2227 function_suppression::set_return_type_name(const string& tr)
2228 {priv_->return_type_name_ = tr;}
2229 
2230 /// Getter for a regular expression for a family of return type names
2231 /// for functions the user wants the current specification to
2232 /// designate.
2233 ///
2234 /// If the name of the return type of the function as returned by
2235 /// function_suppression::get_return_type_name() is not empty, then
2236 /// this property is ignored at specification evaluation time.  This
2237 /// property might be empty, in which case it's ignored at evaluation
2238 /// time.
2239 ///
2240 /// @return the regular expression for the possible names of the
2241 /// return types of the function(s).
2242 const string&
get_return_type_regex_str() const2243 function_suppression::get_return_type_regex_str() const
2244 {return priv_->return_type_regex_str_;}
2245 
2246 /// Setter for a regular expression for a family of return type names
2247 /// for functions the user wants the current specification to
2248 /// designate.
2249 ///
2250 /// If the name of the return type of the function as returned by
2251 /// function_suppression::get_return_type_name() is not empty, then
2252 /// this property is ignored at specification evaluation time.  This
2253 /// property might be empty, in which case it's ignored at evaluation
2254 /// time.
2255 ///
2256 /// @param r the new regular expression for the possible names of the
2257 /// return types of the function(s) to set.
2258 void
set_return_type_regex_str(const string & r)2259 function_suppression::set_return_type_regex_str(const string& r)
2260 {priv_->return_type_regex_str_ = r;}
2261 
2262 /// Getter for a vector of parameter specifications to specify
2263 /// properties of the parameters of the functions the user wants this
2264 /// specification to designate.
2265 ///
2266 /// This property might be empty, in which case it's ignored at
2267 /// evaluation time.
2268 ///
2269 /// @return the specifications of the parameters of the function(s).
2270 const function_suppression::parameter_specs_type&
get_parameter_specs() const2271 function_suppression::get_parameter_specs() const
2272 {return priv_->parm_specs_;}
2273 
2274 /// Setter for a vector of parameter specifications to specify
2275 /// properties of the parameters of the functions the user wants this
2276 /// specification to designate.
2277 ///
2278 /// This property might be empty, in which case it's ignored at
2279 /// evaluation time.
2280 ///
2281 /// @param p the new specifications of the parameters of the
2282 /// function(s) to set.
2283 void
set_parameter_specs(parameter_specs_type & p)2284 function_suppression::set_parameter_specs(parameter_specs_type& p)
2285 {priv_->parm_specs_ = p;}
2286 
2287 /// Append a specification of a parameter of the function specification.
2288 ///
2289 /// @param p the parameter specification to add.
2290 void
append_parameter_specs(const parameter_spec_sptr p)2291 function_suppression::append_parameter_specs(const parameter_spec_sptr p)
2292 {priv_->parm_specs_.push_back(p);}
2293 
2294 /// Getter for the name of symbol of the function the user wants this
2295 /// specification to designate.
2296 ///
2297 /// This property might be empty, in which case it's ignored at
2298 /// evaluation time.
2299 ///
2300 /// @return name of the symbol of the function.
2301 const string&
get_symbol_name() const2302 function_suppression::get_symbol_name() const
2303 {return priv_->symbol_name_;}
2304 
2305 /// Setter for the name of symbol of the function the user wants this
2306 /// specification to designate.
2307 ///
2308 /// This property might be empty, in which case it's ignored at
2309 /// evaluation time.
2310 ///
2311 /// @return name of the symbol of the function.
2312 void
set_symbol_name(const string & n)2313 function_suppression::set_symbol_name(const string& n)
2314 {priv_->symbol_name_ = n;}
2315 
2316 /// Getter for a regular expression for a family of names of symbols
2317 /// of functions the user wants this specification to designate.
2318 ///
2319 /// If the symbol name as returned by
2320 /// function_suppression::get_symbol_name() is not empty, then this
2321 /// property is ignored at specification evaluation time.
2322 ///
2323 /// This property might be empty, in which case it's ignored at
2324 /// evaluation time.
2325 ///
2326 /// @return the regular expression for a family of names of symbols of
2327 /// functions to designate.
2328 const string&
get_symbol_name_regex_str() const2329 function_suppression::get_symbol_name_regex_str() const
2330 {return priv_->symbol_name_regex_str_;}
2331 
2332 /// Setter for a regular expression for a family of names of symbols
2333 /// of functions the user wants this specification to designate.
2334 ///
2335 /// If the symbol name as returned by
2336 /// function_suppression::get_symbol_name() is not empty, then this
2337 /// property is ignored at specification evaluation time.
2338 ///
2339 /// This property might be empty, in which case it's ignored at
2340 /// evaluation time.
2341 ///
2342 /// @param r the new regular expression for a family of names of
2343 /// symbols of functions to set.
2344 void
set_symbol_name_regex_str(const string & r)2345 function_suppression::set_symbol_name_regex_str(const string& r)
2346 {priv_->symbol_name_regex_str_ = r;}
2347 
2348 /// Getter for a regular expression for a family of names of symbols
2349 /// of functions the user wants this specification to designate.
2350 ///
2351 /// If a symbol name is matched by this regular expression, then the
2352 /// suppression specification will *NOT* suppress the symbol.
2353 ///
2354 /// If the symbol name as returned by
2355 /// function_suppression::get_symbol_name() is not empty, then this
2356 /// property is ignored at specification evaluation time.
2357 ///
2358 /// This property might be empty, in which case it's ignored at
2359 /// evaluation time.
2360 ///
2361 /// @return the regular expression string for a family of names of
2362 /// symbols that is to be *NOT* suppressed by this suppression specification.
2363 const string&
get_symbol_name_not_regex_str() const2364 function_suppression::get_symbol_name_not_regex_str() const
2365 {return priv_->symbol_name_not_regex_str_;}
2366 
2367 /// Setter for a regular expression for a family of names of symbols
2368 /// of functions the user wants this specification to designate.
2369 ///
2370 /// If a symbol name is matched by this regular expression, then the
2371 /// suppression specification will *NOT* suppress the symbol.
2372 ///
2373 /// If the symbol name as returned by
2374 /// function_suppression::get_symbol_name() is not empty, then this
2375 /// property is ignored at specification evaluation time.
2376 ///
2377 /// This property might be empty, in which case it's ignored at
2378 /// evaluation time.
2379 ///
2380 /// @param the new regular expression string for a family of names of
2381 /// symbols that is to be *NOT* suppressed by this suppression
2382 /// specification.
2383 void
set_symbol_name_not_regex_str(const string & r)2384 function_suppression::set_symbol_name_not_regex_str(const string& r)
2385 {priv_->symbol_name_not_regex_str_ = r;}
2386 
2387 /// Getter for the name of the version of the symbol of the function
2388 /// the user wants this specification to designate.
2389 ///
2390 /// This property might be empty, in which case it's ignored at
2391 /// evaluation time.
2392 ///
2393 /// @return the symbol version of the function.
2394 const string&
get_symbol_version() const2395 function_suppression::get_symbol_version() const
2396 {return priv_->symbol_version_;}
2397 
2398 /// Setter for the name of the version of the symbol of the function
2399 /// the user wants this specification to designate.
2400 ///
2401 /// This property might be empty, in which case it's ignored at
2402 /// evaluation time.
2403 ///
2404 /// @param v the new symbol version of the function.
2405 void
set_symbol_version(const string & v)2406 function_suppression::set_symbol_version(const string& v)
2407 {priv_->symbol_version_ = v;}
2408 
2409 /// Getter for a regular expression for a family of versions of
2410 /// symbols of functions the user wants the current specification to
2411 /// designate.
2412 ///
2413 /// If the symbol version as returned by
2414 /// function_suppression::get_symbol_version() is non empty, then this
2415 /// property is ignored.  This property might be empty, in which case
2416 /// it's ignored at evaluation time.
2417 ///
2418 /// @return the regular expression for the versions of symbols of
2419 /// functions to designate.
2420 const string&
get_symbol_version_regex_str() const2421 function_suppression::get_symbol_version_regex_str() const
2422 {return priv_->symbol_version_regex_str_;}
2423 
2424 /// Setter for a regular expression for a family of versions of
2425 /// symbols of functions the user wants the current specification to
2426 /// designate.
2427 ///
2428 /// If the symbol version as returned by
2429 /// function_suppression::get_symbol_version() is non empty, then this
2430 /// property is ignored.  This property might be empty, in which case
2431 /// it's ignored at evaluation time.
2432 ///
2433 /// @param the new regular expression for the versions of symbols of
2434 /// functions to designate.
2435 void
set_symbol_version_regex_str(const string & r)2436 function_suppression::set_symbol_version_regex_str(const string& r)
2437 {priv_->symbol_version_regex_str_ = r;}
2438 
2439 /// Getter for the "allow_other_aliases" property of the function
2440 /// suppression specification.
2441 ///
2442 /// @return the value of the "allow_other_aliases" property.
2443 bool
get_allow_other_aliases() const2444 function_suppression::get_allow_other_aliases() const
2445 {return priv_->allow_other_aliases_;}
2446 
2447 /// Setter for the "allow_other_aliases" property of the function
2448 /// suppression specification.
2449 ///
2450 /// @param f the new value of the property.
2451 void
set_allow_other_aliases(bool f)2452 function_suppression::set_allow_other_aliases(bool f)
2453 {priv_->allow_other_aliases_ = f;}
2454 
2455 /// Evaluate this suppression specification on a given diff node and
2456 /// say if the diff node should be suppressed or not.
2457 ///
2458 /// @param diff the diff node to evaluate this suppression
2459 /// specification against.
2460 ///
2461 /// @return true if @p diff should be suppressed.
2462 bool
suppresses_diff(const diff * diff) const2463 function_suppression::suppresses_diff(const diff* diff) const
2464 {
2465   const function_decl_diff* d = is_function_decl_diff(diff);
2466   if (!d)
2467     return false;
2468 
2469   function_decl_sptr ff = is_function_decl(d->first_function_decl()),
2470     sf = is_function_decl(d->second_function_decl());
2471   ABG_ASSERT(ff && sf);
2472 
2473   return (suppresses_function(ff,
2474 			      FUNCTION_SUBTYPE_CHANGE_KIND,
2475 			      diff->context())
2476 	  || suppresses_function(sf,
2477 				 FUNCTION_SUBTYPE_CHANGE_KIND,
2478 				 diff->context()));
2479 }
2480 
2481 /// Evaluate the current function suppression specification on a given
2482 /// @ref function_decl and say if a report about a change involving this
2483 /// @ref function_decl should be suppressed or not.
2484 ///
2485 /// @param fn the @ref function_decl to evaluate this suppression
2486 /// specification against.
2487 ///
2488 /// @param k the kind of function change @p fn is supposed to have.
2489 ///
2490 /// @param ctxt the context of the current diff.
2491 ///
2492 /// @return true iff a report about a change involving the function @p
2493 /// fn should be suppressed.
2494 bool
suppresses_function(const function_decl * fn,change_kind k,const diff_context_sptr ctxt) const2495 function_suppression::suppresses_function(const function_decl* fn,
2496 					  change_kind k,
2497 					  const diff_context_sptr ctxt) const
2498 {
2499   if (!(get_change_kind() & k))
2500     return false;
2501 
2502   // Check if the name and soname of the binaries match the current
2503   // suppr spec
2504   if (ctxt)
2505     {
2506       // Check if the name of the binaries match the current suppr spec
2507       if (!names_of_binaries_match(*this, *ctxt))
2508 	if (has_file_name_related_property())
2509 	  return false;
2510 
2511       // Check if the soname of the binaries match the current suppr spec
2512       if (!sonames_of_binaries_match(*this, *ctxt))
2513 	if (has_soname_related_property())
2514 	  return false;
2515     }
2516 
2517   string fname = fn->get_qualified_name();
2518 
2519   // Check if the "name" property matches.
2520   if (!get_name().empty())
2521     {
2522       if (get_name() != fn->get_qualified_name())
2523 	return false;
2524 
2525       if (get_allow_other_aliases()
2526 	  && fn->get_symbol()
2527 	  && fn->get_symbol()->get_alias_from_name(fname))
2528 	{
2529 	  // So we are in a case of a languages in which the symbol
2530 	  // name is the same as the function name and we want to
2531 	  // allow the removal of change reports on an aliased
2532 	  // function only if the suppression condition matches the
2533 	  // names of all aliases.
2534 	  string symbol_name;
2535 	  elf_symbol_sptr sym = fn->get_symbol();
2536 	  ABG_ASSERT(sym);
2537 	  symbol_name = sym->get_name();
2538 	  if (sym->has_aliases() && sym->get_alias_from_name(fname))
2539 	    {
2540 	      for (elf_symbol_sptr a = sym->get_next_alias();
2541 		   a && !a->is_main_symbol();
2542 		   a = a->get_next_alias())
2543 		if (a->get_name() != symbol_name)
2544 		  // There is an alias which name is different from
2545 		  // the function (symbol) name given in the
2546 		  // suppression condition.
2547 		  return false;
2548 	    }
2549 	}
2550     }
2551 
2552   // check if the "name_regexp" property matches.
2553   const regex_t_sptr name_regex = priv_->get_name_regex();
2554   if (name_regex)
2555     {
2556       if (!regex::match(name_regex, fname))
2557 	return false;
2558 
2559       if (get_allow_other_aliases()
2560 	  && fn->get_symbol()
2561 	  && fn->get_symbol()->get_alias_from_name(fname))
2562 	{
2563 	  // So we are in a case of a languages in which the symbol
2564 	  // name is the same as the function name and we want to
2565 	  // allow the removal of change reports on an aliased
2566 	  // function only if the suppression condition matches *all*
2567 	  // the aliases.
2568 	  string symbol_name;
2569 	  elf_symbol_sptr sym = fn->get_symbol();
2570 	  ABG_ASSERT(sym);
2571 	  symbol_name = sym->get_name();
2572 	  if (sym->has_aliases())
2573 	    {
2574 	      for (elf_symbol_sptr a = sym->get_next_alias();
2575 		   a && !a->is_main_symbol();
2576 		   a = a->get_next_alias())
2577 		if (!regex::match(name_regex, a->get_name()))
2578 		  return false;
2579 	    }
2580 	}
2581     }
2582 
2583   // check if the "name_not_regexp" property matches.
2584   const regex_t_sptr name_not_regex = priv_->get_name_not_regex();
2585   if (name_not_regex)
2586     {
2587       if (regex::match(name_not_regex, fname))
2588 	return false;
2589 
2590       if (get_allow_other_aliases()
2591 	  && fn->get_symbol()
2592 	  && fn->get_symbol()->get_alias_from_name(fname))
2593 	{
2594 	  // So we are in a case of a languages in which the symbol
2595 	  // name is the same as the function name and we want to
2596 	  // allow the removal of change reports on an aliased
2597 	  // function only if the suppression condition matches *all*
2598 	  // the aliases.
2599 	  string symbol_name;
2600 	  elf_symbol_sptr sym = fn->get_symbol();
2601 	  ABG_ASSERT(sym);
2602 	  symbol_name = sym->get_name();
2603 	  if (sym->has_aliases())
2604 	    {
2605 	      for (elf_symbol_sptr a = sym->get_next_alias();
2606 		   a && !a->is_main_symbol();
2607 		   a = a->get_next_alias())
2608 		if (regex::match(name_regex, a->get_name()))
2609 		  return false;
2610 	    }
2611 	}
2612     }
2613 
2614   // Check if the "return_type_name" or "return_type_regexp"
2615   // properties matches.
2616 
2617   string fn_return_type_name = fn->get_type()->get_return_type()
2618     ? static_cast<string>
2619     ((get_type_declaration(fn->get_type()->get_return_type())
2620       ->get_qualified_name()))
2621     : "";
2622 
2623   if (!get_return_type_name().empty())
2624     {
2625       if (fn_return_type_name != get_return_type_name())
2626 	return false;
2627     }
2628   else
2629     {
2630       const regex_t_sptr return_type_regex = priv_->get_return_type_regex();
2631       if (return_type_regex
2632 	  && !regex::match(return_type_regex, fn_return_type_name))
2633 	return false;
2634     }
2635 
2636   // Check if the "symbol_name", "symbol_name_regexp", and
2637   // "symbol_name_not_regexp" properties match.
2638   string fn_sym_name, fn_sym_version;
2639   elf_symbol_sptr sym = fn->get_symbol();
2640   if (sym)
2641     {
2642       fn_sym_name = sym->get_name();
2643       fn_sym_version = sym->get_version().str();
2644     }
2645 
2646   if (sym && !get_symbol_name().empty())
2647     {
2648       if (fn_sym_name != get_symbol_name())
2649 	return false;
2650 
2651       if (sym && get_allow_other_aliases())
2652 	{
2653 	  // In this case, we want to allow the suppression of change
2654 	  // reports about an aliased symbol only if the suppression
2655 	  // condition matches the name of all aliases.
2656 	  if (sym->has_aliases())
2657 	    {
2658 	      for (elf_symbol_sptr a = sym->get_next_alias();
2659 		   a && !a->is_main_symbol();
2660 		   a = a->get_next_alias())
2661 		if (a->get_name() != fn_sym_name)
2662 		  return false;
2663 	    }
2664 	}
2665     }
2666   else if (sym)
2667     {
2668       const regex_t_sptr symbol_name_regex = priv_->get_symbol_name_regex();
2669       if (symbol_name_regex && !regex::match(symbol_name_regex, fn_sym_name))
2670 	return false;
2671 
2672       const regex_t_sptr symbol_name_not_regex =
2673 	priv_->get_symbol_name_not_regex();
2674       if (symbol_name_not_regex
2675 	  && regex::match(symbol_name_not_regex, fn_sym_name))
2676 	return false;
2677 
2678       if (get_allow_other_aliases())
2679 	{
2680 	  // In this case, we want to allow the suppression of change
2681 	  // reports about an aliased symbol only if the suppression
2682 	  // condition matches the name of all aliases.
2683 	  if (sym->has_aliases())
2684 	    {
2685 	      for (elf_symbol_sptr a = sym->get_next_alias();
2686 		   a && !a->is_main_symbol();
2687 		   a = a->get_next_alias())
2688 		{
2689 		  if (symbol_name_regex
2690 		      && !regex::match(symbol_name_regex, a->get_name()))
2691 		    return false;
2692 
2693 		  if (symbol_name_not_regex
2694 		      && regex::match(symbol_name_not_regex, a->get_name()))
2695 		    return false;
2696 		}
2697 	    }
2698 	}
2699     }
2700 
2701   // Check if the "symbol_version" and "symbol_version_regexp"
2702   // properties match.
2703   if (sym && !get_symbol_version().empty())
2704     {
2705       if (fn_sym_version != get_symbol_version())
2706 	return false;
2707     }
2708   else if (sym)
2709     {
2710       const regex_t_sptr symbol_version_regex =
2711 	priv_->get_symbol_version_regex();
2712       if (symbol_version_regex
2713 	  && !regex::match(symbol_version_regex, fn_sym_version))
2714 	return false;
2715     }
2716 
2717   // Check the 'parameter' property.
2718   if (!get_parameter_specs().empty())
2719     {
2720       function_type_sptr fn_type = fn->get_type();
2721       type_base_sptr parm_type;
2722 
2723       for (parameter_specs_type::const_iterator p =
2724 	     get_parameter_specs().begin();
2725 	   p != get_parameter_specs().end();
2726 	   ++p)
2727 	{
2728 	  size_t index = (*p)->get_index();
2729 	  function_decl::parameter_sptr fn_parm =
2730 	    fn_type->get_parm_at_index_from_first_non_implicit_parm(index);
2731 	  if (!fn_parm)
2732 	    return false;
2733 
2734 	  string fn_parm_type_qualified_name;
2735 	  if (fn_parm)
2736 	    {
2737 	      parm_type = fn_parm->get_type();
2738 	      fn_parm_type_qualified_name =
2739 		get_type_declaration(parm_type)->get_qualified_name();
2740 	    }
2741 
2742 	  const string& tn = (*p)->get_parameter_type_name();
2743 	  if (!tn.empty())
2744 	    {
2745 	      if (tn != fn_parm_type_qualified_name)
2746 		return false;
2747 	    }
2748 	  else
2749 	    {
2750 	      const regex_t_sptr parm_type_name_regex =
2751 		(*p)->priv_->get_type_name_regex();
2752 	      if (parm_type_name_regex)
2753 		{
2754 		  if (!regex::match(parm_type_name_regex,
2755 				    fn_parm_type_qualified_name))
2756 		    return false;
2757 		}
2758 	    }
2759 	}
2760     }
2761 
2762   return true;
2763 }
2764 
2765 /// Evaluate the current function suppression specification on a given
2766 /// @ref function_decl and say if a report about a change involving this
2767 /// @ref function_decl should be suppressed or not.
2768 ///
2769 /// @param fn the @ref function_decl to evaluate this suppression
2770 /// specification against.
2771 ///
2772 /// @param k the kind of function change @p fn is supposed to have.
2773 ///
2774 /// @param ctxt the context of the current diff.
2775 ///
2776 /// @return true iff a report about a change involving the function @p
2777 /// fn should be suppressed.
2778 bool
suppresses_function(const function_decl_sptr fn,change_kind k,const diff_context_sptr ctxt) const2779 function_suppression::suppresses_function(const function_decl_sptr fn,
2780 					  change_kind k,
2781 					  const diff_context_sptr ctxt) const
2782 {return suppresses_function(fn.get(), k, ctxt);}
2783 
2784 /// Evaluate the current function suppression specification on a given
2785 /// @ref elf_symbol and say if a report about a change involving this
2786 /// @ref elf_symbol should be suppressed or not.
2787 ///
2788 /// @param sym the @ref elf_symbol to evaluate this suppression
2789 /// specification against.
2790 ///
2791 /// @param k the kind of function change @p sym is supposed to have.
2792 ///
2793 /// @param ctxt the context of the current diff.
2794 ///
2795 /// @return true iff a report about a change involving the symbol @p
2796 /// sym should be suppressed.
2797 bool
suppresses_function_symbol(const elf_symbol * sym,change_kind k,const diff_context_sptr ctxt)2798 function_suppression::suppresses_function_symbol(const elf_symbol* sym,
2799 						 change_kind k,
2800 						 const diff_context_sptr ctxt)
2801 {
2802   if (!sym)
2803     return false;
2804 
2805   if (!(get_change_kind() & k))
2806     return false;
2807 
2808   if (!sym->is_function())
2809     return false;
2810 
2811   ABG_ASSERT(k & function_suppression::ADDED_FUNCTION_CHANGE_KIND
2812 	 || k & function_suppression::DELETED_FUNCTION_CHANGE_KIND);
2813 
2814   // Check if the name and soname of the binaries match the current
2815   // suppr spect
2816   if (ctxt)
2817     {
2818       // Check if the name of the binaries match the current
2819       // suppr spect
2820       if (!names_of_binaries_match(*this, *ctxt))
2821 	if (has_file_name_related_property())
2822 	  return false;
2823 
2824       // Check if the soname of the binaries match the current
2825       // suppr spect
2826       if (!sonames_of_binaries_match(*this, *ctxt))
2827 	if (has_soname_related_property())
2828 	  return false;
2829     }
2830 
2831   string sym_name = sym->get_name(), sym_version = sym->get_version().str();
2832   bool no_symbol_name = false, no_symbol_version = false;
2833 
2834   // Consider the symbol name.
2835   if (!get_symbol_name().empty())
2836     {
2837       if (sym_name != get_symbol_name())
2838 	return false;
2839     }
2840   else if (!get_symbol_name_regex_str().empty())
2841     {
2842       const regex_t_sptr symbol_name_regex = priv_->get_symbol_name_regex();
2843       if (symbol_name_regex && !regex::match(symbol_name_regex, sym_name))
2844 	return false;
2845     }
2846   else
2847     no_symbol_name = true;
2848 
2849   // Consider the symbol version
2850   if (!get_symbol_version().empty())
2851     {
2852       if (sym_version != get_symbol_version())
2853 	return false;
2854     }
2855   else if (!get_symbol_version_regex_str().empty())
2856     {
2857       const regex_t_sptr symbol_version_regex =
2858 	priv_->get_symbol_version_regex();
2859       if (symbol_version_regex
2860 	  && !regex::match(symbol_version_regex, sym_version))
2861 	return false;
2862     }
2863   else
2864     no_symbol_version = true;
2865 
2866   if (no_symbol_name && no_symbol_version)
2867     return false;
2868 
2869   return true;
2870 }
2871 
2872 /// Evaluate the current function suppression specification on a given
2873 /// @ref elf_symbol and say if a report about a change involving this
2874 /// @ref elf_symbol should be suppressed or not.
2875 ///
2876 /// @param sym the @ref elf_symbol to evaluate this suppression
2877 /// specification against.
2878 ///
2879 /// @param k the kind of function change @p sym is supposed to have.
2880 ///
2881 /// @param ctxt the context of the current diff.
2882 ///
2883 /// @return true iff a report about a change involving the symbol @p
2884 /// sym should be suppressed.
2885 bool
suppresses_function_symbol(const elf_symbol_sptr sym,change_kind k,const diff_context_sptr ctxt)2886 function_suppression::suppresses_function_symbol(const elf_symbol_sptr sym,
2887 						 change_kind k,
2888 						 const diff_context_sptr ctxt)
2889 {return suppresses_function_symbol(sym.get(), k, ctxt);}
2890 
2891 /// Test if an instance of @ref suppression is an instance of @ref
2892 /// function_suppression.
2893 ///
2894 /// @param suppr the instance of @ref suppression to test for.
2895 ///
2896 /// @return if @p suppr is an instance of @ref function_suppression, then
2897 /// return the sub-object of the @p suppr of type @ref
2898 /// function_suppression, otherwise return a nil pointer.
2899 function_suppression_sptr
is_function_suppression(const suppression_sptr suppr)2900 is_function_suppression(const suppression_sptr suppr)
2901 {return dynamic_pointer_cast<function_suppression>(suppr);}
2902 
2903 /// The bitwise 'and' operator for the enum @ref
2904 /// function_suppression::change_kind.
2905 ///
2906 /// @param l the first operand of the 'and' operator.
2907 ///
2908 /// @param r the second operand of the 'and' operator.
2909 ///
2910 /// @return the result of 'and' operation on @p l and @p r.
2911 function_suppression::change_kind
operator &(function_suppression::change_kind l,function_suppression::change_kind r)2912 operator&(function_suppression::change_kind l,
2913 	  function_suppression::change_kind r)
2914 {
2915   return static_cast<function_suppression::change_kind>
2916     (static_cast<unsigned>(l) & static_cast<unsigned>(r));
2917 }
2918 
2919 /// The bitwise 'or' operator for the enum @ref
2920 /// function_suppression::change_kind.
2921 ///
2922 /// @param l the first operand of the 'or' operator.
2923 ///
2924 /// @param r the second operand of the 'or' operator.
2925 ///
2926 /// @return the result of 'or' operation on @p l and @p r.
2927 function_suppression::change_kind
operator |(function_suppression::change_kind l,function_suppression::change_kind r)2928 operator|(function_suppression::change_kind l,
2929 	  function_suppression::change_kind r)
2930 {
2931     return static_cast<function_suppression::change_kind>
2932       (static_cast<unsigned>(l) | static_cast<unsigned>(r));
2933 }
2934 
2935   /// Test whether if a given function suppression matches a function
2936   /// designated by a regular expression that describes its name.
2937   ///
2938   /// @param s the suppression specification to evaluate to see if it
2939   /// matches a given function name.
2940   ///
2941   /// @param fn_name the name of the function of interest.  Note that
2942   /// this name must be *non* qualified.
2943   ///
2944   /// @return true iff the suppression specification @p s matches the
2945   /// function whose name is @p fn_name.
2946 bool
suppression_matches_function_name(const suppr::function_suppression & s,const string & fn_name)2947 suppression_matches_function_name(const suppr::function_suppression& s,
2948 				  const string& fn_name)
2949 {
2950   if (regex_t_sptr regexp = s.priv_->get_name_regex())
2951     {
2952       if (!regex::match(regexp, fn_name))
2953 	return false;
2954     }
2955   else if (regex_t_sptr regexp = s.priv_->get_name_not_regex())
2956     {
2957       if (regex::match(regexp, fn_name))
2958 	return false;
2959     }
2960   else if (s.priv_->name_.empty())
2961     return false;
2962   else // if (!s.priv_->name_.empty())
2963     {
2964       if (s.priv_->name_ != fn_name)
2965 	return false;
2966     }
2967 
2968   return true;
2969 }
2970 
2971 /// Test whether if a given function suppression matches a function
2972 /// designated by a regular expression that describes its linkage
2973 /// name (symbol name).
2974 ///
2975 /// @param s the suppression specification to evaluate to see if it
2976 /// matches a given function linkage name
2977 ///
2978 /// @param fn_linkage_name the linkage name of the function of interest.
2979 ///
2980 /// @return true iff the suppression specification @p s matches the
2981 /// function whose linkage name is @p fn_linkage_name.
2982 bool
suppression_matches_function_sym_name(const suppr::function_suppression & s,const string & fn_linkage_name)2983 suppression_matches_function_sym_name(const suppr::function_suppression& s,
2984 				      const string& fn_linkage_name)
2985 {
2986   if (regex_t_sptr regexp = s.priv_->get_symbol_name_regex())
2987     {
2988       if (!regex::match(regexp, fn_linkage_name))
2989 	return false;
2990     }
2991   else if (regex_t_sptr regexp = s.priv_->get_symbol_name_not_regex())
2992     {
2993       if (regex::match(regexp, fn_linkage_name))
2994 	return false;
2995     }
2996   else if (s.priv_->symbol_name_.empty())
2997     return false;
2998   else // if (!s.priv_->symbol_name_.empty())
2999     {
3000       if (s.priv_->symbol_name_ != fn_linkage_name)
3001 	return false;
3002     }
3003 
3004   return true;
3005 }
3006 
3007 /// Test if a variable suppression matches a variable denoted by its name.
3008 ///
3009 /// @param s the variable suppression to consider.
3010 ///
3011 /// @param var_name the name of the variable to consider.
3012 ///
3013 /// @return true if the variable is matches by the suppression
3014 /// specification.
3015 bool
suppression_matches_variable_name(const suppr::variable_suppression & s,const string & var_name)3016 suppression_matches_variable_name(const suppr::variable_suppression& s,
3017 				  const string& var_name)
3018 {
3019   if (regex_t_sptr regexp = s.priv_->get_name_regex())
3020     {
3021       if (!regex::match(regexp, var_name))
3022 	return false;
3023     }
3024   else if (regex_t_sptr regexp = s.priv_->get_name_not_regex())
3025     {
3026       if (regex::match(regexp, var_name))
3027 	return false;
3028     }
3029   else if (s.priv_->name_.empty())
3030     return false;
3031   else // if (!s.priv_->name_.empty())
3032     {
3033       if (s.priv_->name_ != var_name)
3034 	return false;
3035     }
3036 
3037   return true;
3038 }
3039 
3040 /// Test if a variable suppression matches a variable denoted by its
3041 /// symbol name.
3042 ///
3043 /// @param s the variable suppression to consider.
3044 ///
3045 /// @param var_linkage_name the name of the variable to consider.
3046 ///
3047 /// @return true if the variable is matches by the suppression
3048 /// specification.
3049 bool
suppression_matches_variable_sym_name(const suppr::variable_suppression & s,const string & var_linkage_name)3050 suppression_matches_variable_sym_name(const suppr::variable_suppression& s,
3051 				      const string& var_linkage_name)
3052 {
3053   if (regex_t_sptr regexp = s.priv_->get_symbol_name_regex())
3054     {
3055       if (!regex::match(regexp, var_linkage_name))
3056 	return false;
3057     }
3058   else if (regex_t_sptr regexp =
3059 	   s.priv_->get_symbol_name_not_regex())
3060     {
3061       if (regex::match(regexp, var_linkage_name))
3062 	return false;
3063     }
3064   else if (s.priv_->symbol_name_.empty())
3065     return false;
3066   else // if (!s.priv_->symbol_name_.empty())
3067     {
3068       if (s.priv_->symbol_name_ != var_linkage_name)
3069 	return false;
3070     }
3071 
3072   return true;
3073 }
3074 
3075 /// Test if a type suppression matches a type designated by its fully
3076 /// qualified name.
3077 ///
3078 /// @param s the type suppression to consider.
3079 ///
3080 /// @param type_name the name of the type to consider.
3081 ///
3082 /// @return true iff the suppression s matches the type denoted by
3083 /// name @p type_name.
3084 bool
suppression_matches_type(const suppr::type_suppression & s,const string & type_name)3085 suppression_matches_type(const suppr::type_suppression& s,
3086 			 const string& type_name)
3087 {
3088   if (regex_t_sptr regexp = s.priv_->get_type_name_regex())
3089     {
3090       if (!regex::match(regexp, type_name))
3091 	return false;
3092     }
3093   else if (!s.get_type_name().empty())
3094     {
3095       if (s.get_type_name() != type_name)
3096 	return false;
3097     }
3098   else
3099     return false;
3100 
3101   return true;
3102 }
3103 
3104 /// Parse a string containing a parameter spec, build an instance of
3105 /// function_suppression::parameter_spec from it and return a pointer
3106 /// to that object.
3107 ///
3108 /// @return a shared pointer pointer to the newly built instance of
3109 /// function_suppression::parameter_spec.  If the parameter
3110 /// specification could not be parsed, return a nil object.
3111 static function_suppression::parameter_spec_sptr
read_parameter_spec_from_string(const string & str)3112 read_parameter_spec_from_string(const string& str)
3113 {
3114   string::size_type cur = 0;
3115   function_suppression::parameter_spec_sptr result;
3116 
3117   // skip leading white spaces.
3118   for (; cur < str.size(); ++cur)
3119     if (!isspace(str[cur]))
3120       break;
3121 
3122   // look for the parameter index
3123   string index_str;
3124   if (str[cur] == '\'')
3125     {
3126       ++cur;
3127       for (; cur < str.size(); ++cur)
3128 	if (!isdigit(str[cur]))
3129 	  break;
3130 	else
3131 	  index_str += str[cur];
3132     }
3133 
3134   // skip white spaces.
3135   for (; cur < str.size(); ++cur)
3136     if (!isspace(str[cur]))
3137       break;
3138 
3139   bool is_regex = false;
3140   if (str[cur] == '/')
3141     {
3142       is_regex = true;
3143       ++cur;
3144     }
3145 
3146   // look for the type name (regex)
3147   string type_name;
3148   for (; cur < str.size(); ++cur)
3149     if (!isspace(str[cur]))
3150       {
3151 	if (is_regex && str[cur] == '/')
3152 	  break;
3153 	type_name += str[cur];
3154       }
3155 
3156   if (is_regex && str[cur] == '/')
3157     ++cur;
3158 
3159   if (!index_str.empty() || !type_name.empty())
3160     {
3161       std::string type_name_regex;
3162       if (is_regex)
3163 	{
3164 	  type_name_regex = type_name;
3165 	  type_name.clear();
3166 	}
3167       function_suppression::parameter_spec* p =
3168 	new function_suppression::parameter_spec(atoi(index_str.c_str()),
3169 						 type_name, type_name_regex);
3170       result.reset(p);
3171     }
3172 
3173   return result;
3174 }
3175 
3176 /// Parse function suppression specification, build a resulting @ref
3177 /// function_suppression type and return a shared pointer to that
3178 /// object.
3179 ///
3180 /// @return a shared pointer to the newly built @ref
3181 /// function_suppression.  If the function suppression specification
3182 /// could not be parsed then a nil shared pointer is returned.
3183 static function_suppression_sptr
read_function_suppression(const ini::config::section & section)3184 read_function_suppression(const ini::config::section& section)
3185 {
3186   function_suppression_sptr result;
3187 
3188   if (section.get_name() != "suppress_function")
3189     return result;
3190 
3191   static const char *const sufficient_props[] = {
3192     "label",
3193     "file_name_regexp",
3194     "file_name_not_regexp",
3195     "soname_regexp",
3196     "soname_not_regexp",
3197     "name",
3198     "name_regexp",
3199     "name_not_regexp",
3200     "parameter",
3201     "return_type_name",
3202     "return_type_regexp",
3203     "symbol_name",
3204     "symbol_name_regexp",
3205     "symbol_name_not_regexp",
3206     "symbol_version",
3207     "symbol_version_regexp",
3208   };
3209   if (!check_sufficient_props(sufficient_props,
3210 			      sizeof(sufficient_props)/sizeof(char*),
3211 			      section))
3212     return result;
3213 
3214   ini::simple_property_sptr drop_artifact =
3215     is_simple_property(section.find_property("drop_artifact"));
3216   if (!drop_artifact)
3217     drop_artifact = is_simple_property(section.find_property("drop"));
3218 
3219   string drop_artifact_str = drop_artifact
3220     ? drop_artifact->get_value()->as_string()
3221     : "";
3222 
3223   ini::simple_property_sptr change_kind_prop =
3224     is_simple_property(section.find_property("change_kind"));
3225   string change_kind_str = change_kind_prop
3226     ? change_kind_prop->get_value()->as_string()
3227     : "";
3228 
3229   ini::simple_property_sptr label_prop =
3230     is_simple_property(section.find_property("label"));
3231   string label_str = label_prop
3232     ? label_prop->get_value()->as_string()
3233     : "";
3234 
3235   ini::simple_property_sptr file_name_regex_prop =
3236     is_simple_property(section.find_property("file_name_regexp"));
3237   string file_name_regex_str =
3238     file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
3239 
3240   ini::simple_property_sptr file_name_not_regex_prop =
3241     is_simple_property(section.find_property("file_name_not_regexp"));
3242   string file_name_not_regex_str =
3243     file_name_not_regex_prop
3244     ? file_name_not_regex_prop->get_value()->as_string()
3245     : "";
3246 
3247   ini::simple_property_sptr soname_regex_prop =
3248     is_simple_property(section.find_property("soname_regexp"));
3249   string soname_regex_str =
3250     soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
3251 
3252   ini::simple_property_sptr soname_not_regex_prop =
3253     is_simple_property(section.find_property("soname_not_regexp"));
3254   string soname_not_regex_str =
3255     soname_not_regex_prop
3256     ? soname_not_regex_prop->get_value()->as_string()
3257     : "";
3258 
3259   ini::simple_property_sptr name_prop =
3260     is_simple_property(section.find_property("name"));
3261   string name = name_prop
3262     ? name_prop->get_value()->as_string()
3263     : "";
3264 
3265   ini::simple_property_sptr name_regex_prop =
3266     is_simple_property(section.find_property("name_regexp"));
3267   string name_regex_str = name_regex_prop
3268     ? name_regex_prop->get_value()->as_string()
3269     : "";
3270 
3271   ini::simple_property_sptr name_not_regex_prop =
3272     is_simple_property(section.find_property("name_not_regexp"));
3273   string name_not_regex_str = name_not_regex_prop
3274     ? name_not_regex_prop->get_value()->as_string()
3275     : "";
3276 
3277   ini::simple_property_sptr return_type_name_prop =
3278     is_simple_property(section.find_property("return_type_name"));
3279   string return_type_name = return_type_name_prop
3280     ? return_type_name_prop->get_value()->as_string()
3281     : "";
3282 
3283   ini::simple_property_sptr return_type_regex_prop =
3284     is_simple_property(section.find_property("return_type_regexp"));
3285   string return_type_regex_str = return_type_regex_prop
3286     ? return_type_regex_prop->get_value()->as_string()
3287     : "";
3288 
3289   ini::simple_property_sptr sym_name_prop =
3290     is_simple_property(section.find_property("symbol_name"));
3291   string sym_name = sym_name_prop
3292     ? sym_name_prop->get_value()->as_string()
3293     : "";
3294 
3295   ini::simple_property_sptr sym_name_regex_prop =
3296     is_simple_property(section.find_property("symbol_name_regexp"));
3297   string sym_name_regex_str = sym_name_regex_prop
3298     ? sym_name_regex_prop->get_value()->as_string()
3299     : "";
3300 
3301   ini::simple_property_sptr sym_name_not_regex_prop =
3302     is_simple_property(section.find_property("symbol_name_not_regexp"));
3303   string sym_name_not_regex_str = sym_name_not_regex_prop
3304     ? sym_name_not_regex_prop->get_value()->as_string()
3305     : "";
3306 
3307   ini::simple_property_sptr sym_ver_prop =
3308     is_simple_property(section.find_property("symbol_version"));
3309   string sym_version = sym_ver_prop
3310     ? sym_ver_prop->get_value()->as_string()
3311     : "";
3312 
3313   ini::simple_property_sptr sym_ver_regex_prop =
3314     is_simple_property(section.find_property("symbol_version_regexp"));
3315   string sym_ver_regex_str = sym_ver_regex_prop
3316     ? sym_ver_regex_prop->get_value()->as_string()
3317     : "";
3318 
3319   ini::simple_property_sptr allow_other_aliases_prop =
3320     is_simple_property(section.find_property("allow_other_aliases"));
3321   string allow_other_aliases = allow_other_aliases_prop
3322     ? allow_other_aliases_prop->get_value()->as_string()
3323     : "";
3324 
3325   function_suppression::parameter_spec_sptr parm;
3326   function_suppression::parameter_specs_type parms;
3327   for (ini::config::properties_type::const_iterator p =
3328 	 section.get_properties().begin();
3329        p != section.get_properties().end();
3330        ++p)
3331     if ((*p)->get_name() == "parameter")
3332       {
3333 	ini::simple_property_sptr prop = is_simple_property(*p);
3334 	ABG_ASSERT(prop);
3335 	if ((parm = read_parameter_spec_from_string
3336 	      (prop->get_value()->as_string())))
3337 	  parms.push_back(parm);
3338       }
3339 
3340   result.reset(new function_suppression(label_str,
3341 					name,
3342 					name_regex_str,
3343 					return_type_name,
3344 					return_type_regex_str,
3345 					parms,
3346 					sym_name,
3347 					sym_name_regex_str,
3348 					sym_version,
3349 					sym_ver_regex_str));
3350 
3351   if ((drop_artifact_str == "yes" || drop_artifact_str == "true")
3352       && (!name.empty()
3353 	  || !name_regex_str.empty()
3354 	  || !name_not_regex_str.empty()
3355 	  || !sym_name.empty()
3356 	  || !sym_name_regex_str.empty()
3357 	  || !sym_name_not_regex_str.empty()))
3358     result->set_drops_artifact_from_ir(true);
3359 
3360   if (!change_kind_str.empty())
3361     result->set_change_kind
3362       (function_suppression::parse_change_kind(change_kind_str));
3363 
3364   if (!allow_other_aliases.empty())
3365     result->set_allow_other_aliases(allow_other_aliases == "yes"
3366 				    || allow_other_aliases == "true");
3367 
3368   if (!name_not_regex_str.empty())
3369     result->set_name_not_regex_str(name_not_regex_str);
3370 
3371   if (!sym_name_not_regex_str.empty())
3372     result->set_symbol_name_not_regex_str(sym_name_not_regex_str);
3373 
3374   if (!file_name_regex_str.empty())
3375     result->set_file_name_regex_str(file_name_regex_str);
3376 
3377   if (!file_name_not_regex_str.empty())
3378     result->set_file_name_not_regex_str(file_name_not_regex_str);
3379 
3380   if (!soname_regex_str.empty())
3381     result->set_soname_regex_str(soname_regex_str);
3382 
3383   if (!soname_not_regex_str.empty())
3384     result->set_soname_not_regex_str(soname_not_regex_str);
3385 
3386   return result;
3387 }
3388 
3389 // </function_suppression stuff>
3390 
3391 // <variable_suppression stuff>
3392 
3393 /// Constructor for the @ref variable_suppression type.
3394 ///
3395 /// @param label an informative text string that the evalution code
3396 /// might use to designate this variable suppression specification in
3397 /// error messages.  This parameter might be empty, in which case it's
3398 /// ignored at evaluation time.
3399 ///
3400 /// @param name the name of the variable the user wants the current
3401 /// specification to designate.  This parameter might be empty, in
3402 /// which case it's ignored at evaluation time.
3403 ///
3404 /// @param name_regex_str if @p name is empty, this parameter is a
3405 /// regular expression for a family of names of variables the user
3406 /// wants the current specification to designate.  If @p name is not
3407 /// empty, then this parameter is ignored at evaluation time.  This
3408 /// parameter might be empty, in which case it's ignored at evaluation
3409 /// time.
3410 ///
3411 /// @param symbol_name the name of the symbol of the variable the user
3412 /// wants the current specification to designate.  This parameter
3413 /// might be empty, in which case it's ignored at evaluation time.
3414 ///
3415 /// @param symbol_name_str if @p symbol_name is empty, this parameter
3416 /// is a regular expression for a family of names of symbols of
3417 /// variables the user wants the current specification to designate.
3418 /// If @p symbol_name is not empty, then this parameter is ignored at
3419 /// evaluation time.  This parameter might be empty, in which case
3420 /// it's ignored at evaluation time.
3421 ///
3422 /// @param symbol_version the version of the symbol of the variable
3423 /// the user wants the current specification to designate.  This
3424 /// parameter might be empty, in which case it's ignored at evaluation
3425 /// time.
3426 ///
3427 /// @param symbol_version_regex if @p symbol_version is empty, then
3428 /// this parameter is a regular expression for a family of versions of
3429 /// symbol for the variables the user wants the current specification
3430 /// to designate.  If @p symbol_version is not empty, then this
3431 /// parameter is ignored at evaluation time.  This parameter might be
3432 /// empty, in which case it's ignored at evaluation time.
3433 ///
3434 /// @param type_name the name of the type of the variable the user
3435 /// wants the current specification to designate.  This parameter
3436 /// might be empty, in which case it's ignored at evaluation time.
3437 ///
3438 /// @param type_name_regex_str if @p type_name is empty, then this
3439 /// parameter is a regular expression for a family of type names of
3440 /// variables the user wants the current specification to designate.
3441 /// If @p type_name is not empty, then this parameter is ignored at
3442 /// evluation time.  This parameter might be empty, in which case it's
3443 /// ignored at evaluation time.
variable_suppression(const string & label,const string & name,const string & name_regex_str,const string & symbol_name,const string & symbol_name_regex_str,const string & symbol_version,const string & symbol_version_regex,const string & type_name,const string & type_name_regex_str)3444 variable_suppression::variable_suppression(const string& label,
3445 					   const string& name,
3446 					   const string& name_regex_str,
3447 					   const string& symbol_name,
3448 					   const string& symbol_name_regex_str,
3449 					   const string& symbol_version,
3450 					   const string& symbol_version_regex,
3451 					   const string& type_name,
3452 					   const string& type_name_regex_str)
3453   : suppression_base(label),
3454     priv_(new priv(name, name_regex_str,
3455 		   symbol_name, symbol_name_regex_str,
3456 		   symbol_version, symbol_version_regex,
3457 		   type_name, type_name_regex_str))
3458 {}
3459 
3460 /// Virtual destructor for the @erf variable_suppression type.
3461 /// variable_suppression type.
~variable_suppression()3462 variable_suppression::~variable_suppression()
3463 {}
3464 
3465 /// Parses a string containing the content of the "change-kind"
3466 /// property and returns the an instance of @ref
3467 /// variable_suppression::change_kind as a result.
3468 ///
3469 /// @param s the string to parse.
3470 ///
3471 /// @return the resulting @ref variable_suppression::change_kind.
3472 variable_suppression::change_kind
parse_change_kind(const string & s)3473 variable_suppression::parse_change_kind(const string& s)
3474 {
3475   if (s == "variable-subtype-change")
3476     return VARIABLE_SUBTYPE_CHANGE_KIND;
3477   else if (s == "added-variable")
3478     return ADDED_VARIABLE_CHANGE_KIND;
3479   else if (s == "deleted-variable")
3480     return DELETED_VARIABLE_CHANGE_KIND;
3481   else if (s == "all")
3482     return ALL_CHANGE_KIND;
3483   else
3484     return UNDEFINED_CHANGE_KIND;
3485 }
3486 
3487 /// Getter of the "change_king" property.
3488 ///
3489 /// @return the value of the "change_kind" property.
3490 variable_suppression::change_kind
get_change_kind() const3491 variable_suppression::get_change_kind() const
3492 {return priv_->change_kind_;}
3493 
3494 /// Setter of the "change_kind" property.
3495 ///
3496 /// @param k the new value of of the change_kind.
3497 void
set_change_kind(change_kind k)3498 variable_suppression::set_change_kind(change_kind k)
3499 {priv_->change_kind_ = k;}
3500 
3501 /// Getter for the name of the variable the user wants the current
3502 /// specification to designate.  This property might be empty, in
3503 /// which case it's ignored at evaluation time.
3504 ///
3505 /// @return the name of the variable.
3506 const string&
get_name() const3507 variable_suppression::get_name() const
3508 {return priv_->name_;}
3509 
3510 /// Setter for the name of the variable the user wants the current
3511 /// specification to designate.  This property might be empty, in
3512 /// which case it's ignored at evaluation time.
3513 ///
3514 /// @param n the new name of the variable to set.
3515 void
set_name(const string & n)3516 variable_suppression::set_name(const string& n)
3517 {priv_->name_ = n;}
3518 
3519 /// Getter for the regular expression for a family of names of
3520 /// variables the user wants the current specification to designate.
3521 /// If the variable name as returned by
3522 /// variable_suppression::get_name() is not empty, then this property
3523 /// is ignored at evaluation time.  This property might be empty, in
3524 /// which case it's ignored at evaluation time.
3525 ///
3526 /// @return the regular expression for the variable name.
3527 const string&
get_name_regex_str() const3528 variable_suppression::get_name_regex_str() const
3529 {return priv_->name_regex_str_;}
3530 
3531 /// Setter for the regular expression for a family of names of
3532 /// variables the user wants the current specification to designate.
3533 /// If the variable name as returned by
3534 /// variable_suppression::get_name() is not empty, then this property
3535 /// is ignored at evaluation time.  This property might be empty, in
3536 /// which case it's ignored at evaluation time.
3537 ///
3538 /// @param r the new regular expression for the variable name.
3539 void
set_name_regex_str(const string & r)3540 variable_suppression::set_name_regex_str(const string& r)
3541 {priv_->name_regex_str_ = r;}
3542 
3543 /// Getter for the "name_not_regexp" property of the specification.
3544 ///
3545 /// @return the value of the "name_not_regexp" property.
3546 const string&
get_name_not_regex_str() const3547 variable_suppression::get_name_not_regex_str() const
3548 {return priv_->name_not_regex_str_;}
3549 
3550 /// Setter for the "name_not_regexp" property of the specification.
3551 ///
3552 /// @param r the new value of the "name_not_regexp" property.
3553 void
set_name_not_regex_str(const string & r)3554 variable_suppression::set_name_not_regex_str(const string& r)
3555 {priv_->name_not_regex_str_ = r;}
3556 
3557 /// Getter for the name of the symbol of the variable the user wants
3558 /// the current specification to designate.
3559 ///
3560 /// This property might be empty, in which case it is ignored at
3561 /// evaluation time.
3562 ///
3563 /// @return the name of the symbol of the variable.
3564 const string&
get_symbol_name() const3565 variable_suppression::get_symbol_name() const
3566 {return priv_->symbol_name_;}
3567 
3568 /// Setter for the name of the symbol of the variable the user wants
3569 /// the current specification to designate.
3570 ///
3571 /// This property might be empty, in which case it is ignored at
3572 /// evaluation time.
3573 ///
3574 /// @param n the new name of the symbol of the variable.
3575 void
set_symbol_name(const string & n)3576 variable_suppression::set_symbol_name(const string& n)
3577 {priv_->symbol_name_ = n;}
3578 
3579 /// Getter of the regular expression for a family of symbol names of
3580 /// the variables this specification is about to designate.
3581 ///
3582 /// This property might be empty, in which case it's ignored at
3583 /// evaluation time.  Otherwise, it is taken in account iff the
3584 /// property returned by variable_suppression::get_symbol_name() is
3585 /// empty.
3586 ///
3587 /// @return the regular expression for a symbol name of the variable.
3588 const string&
get_symbol_name_regex_str() const3589 variable_suppression::get_symbol_name_regex_str() const
3590 {return priv_->symbol_name_regex_str_;}
3591 
3592 /// Setter of the regular expression for a family of symbol names of
3593 /// the variables this specification is about to designate.
3594 ///
3595 /// This property might be empty, in which case it's ignored at
3596 /// evaluation time.  Otherwise, it is taken in account iff the
3597 /// property returned by variable_suppression::get_symbol_name() is
3598 /// empty.
3599 ///
3600 /// @param r the regular expression for a symbol name of the variable.
3601 void
set_symbol_name_regex_str(const string & r)3602 variable_suppression::set_symbol_name_regex_str(const string& r)
3603 {priv_->symbol_name_regex_str_ = r;}
3604 
3605 /// Getter for a regular expression for a family of names of symbols
3606 /// of variables the user wants this specification to designate.
3607 ///
3608 /// If a symbol name is matched by this regular expression, then the
3609 /// suppression specification will *NOT* suppress the symbol.
3610 ///
3611 /// If the symbol name as returned by
3612 /// variable_suppression::get_symbol_name() is not empty, then this
3613 /// property is ignored at specification evaluation time.
3614 ///
3615 /// This property might be empty, in which case it's ignored at
3616 /// evaluation time.
3617 ///
3618 /// @return the regular expression string for a family of names of
3619 /// symbols that is to be *NOT* suppressed by this suppression specification.
3620 const string&
get_symbol_name_not_regex_str() const3621 variable_suppression::get_symbol_name_not_regex_str() const
3622 {return priv_->symbol_name_not_regex_str_;}
3623 
3624 /// Setter for a regular expression for a family of names of symbols
3625 /// of variables the user wants this specification to designate.
3626 ///
3627 /// If a symbol name is matched by this regular expression, then the
3628 /// suppression specification will *NOT* suppress the symbol.
3629 ///
3630 /// If the symbol name as returned by
3631 /// variable_suppression::get_symbol_name() is not empty, then this
3632 /// property is ignored at specification evaluation time.
3633 ///
3634 /// This property might be empty, in which case it's ignored at
3635 /// evaluation time.
3636 ///
3637 /// @param the new regular expression string for a family of names of
3638 /// symbols that is to be *NOT* suppressed by this suppression
3639 /// specification.
3640 void
set_symbol_name_not_regex_str(const string & r)3641 variable_suppression::set_symbol_name_not_regex_str(const string& r)
3642 {priv_->symbol_name_not_regex_str_ = r;}
3643 
3644 /// Getter for the version of the symbol of the variable the user
3645 /// wants the current specification to designate.  This property might
3646 /// be empty, in which case it's ignored at evaluation time.
3647 ///
3648 /// @return the symbol version of the variable.
3649 const string&
get_symbol_version() const3650 variable_suppression::get_symbol_version() const
3651 {return priv_->symbol_version_;}
3652 
3653 /// Setter for the version of the symbol of the variable the user
3654 /// wants the current specification to designate.  This property might
3655 /// be empty, in which case it's ignored at evaluation time.
3656 ///
3657 /// @return the new symbol version of the variable.
3658 void
set_symbol_version(const string & v)3659 variable_suppression::set_symbol_version(const string& v)
3660 {priv_->symbol_version_ = v;}
3661 
3662 /// Getter of the regular expression for a family of versions of
3663 /// symbol for the variables the user wants the current specification
3664 /// to designate.  If @p symbol_version is not empty, then this
3665 /// property is ignored at evaluation time.  This property might be
3666 /// empty, in which case it's ignored at evaluation time.
3667 ///
3668 /// @return the regular expression of the symbol version of the
3669 /// variable.
3670 const string&
get_symbol_version_regex_str() const3671 variable_suppression::get_symbol_version_regex_str() const
3672 {return priv_->symbol_version_regex_str_;}
3673 
3674 /// Setter of the regular expression for a family of versions of
3675 /// symbol for the variables the user wants the current specification
3676 /// to designate.  If @p symbol_version is not empty, then this
3677 /// property is ignored at evaluation time.  This property might be
3678 /// empty, in which case it's ignored at evaluation time.
3679 ///
3680 /// @param v the new regular expression of the symbol version of the
3681 /// variable.
3682 void
set_symbol_version_regex_str(const string & r)3683 variable_suppression::set_symbol_version_regex_str(const string& r)
3684 {priv_->symbol_version_regex_str_ = r;}
3685 
3686 /// Getter for the name of the type of the variable the user wants the
3687 /// current specification to designate.
3688 ///
3689 /// This property might be empty, in which case it's ignored at
3690 /// evaluation time.
3691 ///
3692 /// @return the name of the variable type.
3693 const string&
get_type_name() const3694 variable_suppression::get_type_name() const
3695 {return priv_->type_name_;}
3696 
3697 /// Setter for the name of the type of the variable the user wants the
3698 /// current specification to designate.
3699 ///
3700 /// This property might be empty, in which case it's ignored at
3701 /// evaluation time.
3702 ///
3703 /// @param n the new name of the variable type.
3704 void
set_type_name(const string & n)3705 variable_suppression::set_type_name(const string& n)
3706 {priv_->type_name_ = n;}
3707 
3708 /// Getter for the regular expression for a family of type names of
3709 /// variables the user wants the current specification to designate.
3710 ///
3711 /// If the type name as returned by
3712 /// variable_suppression::get_type_name() is not empty, then this
3713 /// property is ignored at evaluation time.  This property might be
3714 /// empty, in which case it's ignored at evaluation time.
3715 ///
3716 /// @return the regular expression of the variable type name.
3717 const string&
get_type_name_regex_str() const3718 variable_suppression::get_type_name_regex_str() const
3719 {return priv_->type_name_regex_str_;}
3720 
3721 /// Setter for the regular expression for a family of type names of
3722 /// variables the user wants the current specification to designate.
3723 ///
3724 /// If the type name as returned by
3725 /// variable_suppression::get_type_name() is not empty, then this
3726 /// property is ignored at evaluation time.  This property might be
3727 /// empty, in which case it's ignored at evaluation time.
3728 ///
3729 /// @param r the regular expression of the variable type name.
3730 void
set_type_name_regex_str(const string & r)3731 variable_suppression::set_type_name_regex_str(const string& r)
3732 {priv_->type_name_regex_str_ = r;}
3733 
3734 /// Evaluate this suppression specification on a given diff node and
3735 /// say if the diff node should be suppressed or not.
3736 ///
3737 /// @param diff the diff node to evaluate this suppression
3738 /// specification against.
3739 ///
3740 /// @return true if @p diff should be suppressed.
3741 bool
suppresses_diff(const diff * diff) const3742 variable_suppression::suppresses_diff(const diff* diff) const
3743 {
3744   const var_diff* d = is_var_diff(diff);
3745   if (!d)
3746     return false;
3747 
3748   var_decl_sptr fv = is_var_decl(is_decl(d->first_subject())),
3749     sv = is_var_decl(is_decl(d->second_subject()));
3750 
3751   ABG_ASSERT(fv && sv);
3752 
3753   return (suppresses_variable(fv,
3754 			      VARIABLE_SUBTYPE_CHANGE_KIND,
3755 			      diff->context())
3756 	  || suppresses_variable(sv,
3757 				 VARIABLE_SUBTYPE_CHANGE_KIND,
3758 				 diff->context()));
3759 }
3760 
3761 /// Evaluate the current variable suppression specification on a given
3762 /// @ref var_decl and say if a report about a change involving this
3763 /// @ref var_decl should be suppressed or not.
3764 ///
3765 /// @param var the @ref var_decl to evaluate this suppression
3766 /// specification against.
3767 ///
3768 /// @param k the kind of variable change @p var is supposed to have.
3769 ///
3770 /// @param ctxt the context of the current diff.
3771 ///
3772 /// @return true iff a report about a change involving the variable @p
3773 /// var should be suppressed.
3774 bool
suppresses_variable(const var_decl * var,change_kind k,const diff_context_sptr ctxt) const3775 variable_suppression::suppresses_variable(const var_decl* var,
3776 					  change_kind k,
3777 					  const diff_context_sptr ctxt) const
3778 {
3779   if (!(get_change_kind() & k))
3780     return false;
3781 
3782   // Check if the name and soname of the binaries match
3783   if (ctxt)
3784     {
3785       // Check if the name of the binaries match the current
3786       // suppr spec
3787       if (!names_of_binaries_match(*this, *ctxt))
3788 	if (has_file_name_related_property())
3789 	  return false;
3790 
3791       // Check if the soname of the binaries match the current suppr
3792       // spec
3793       if (!sonames_of_binaries_match(*this, *ctxt))
3794 	if (has_soname_related_property())
3795 	  return false;
3796     }
3797 
3798   string var_name = var->get_qualified_name();
3799 
3800   // Check for "name" property match.
3801   if (!get_name().empty())
3802     {
3803       if (get_name() != var_name)
3804 	return false;
3805     }
3806   else
3807     {
3808       // If the "name" property is empty, then consider checking for the
3809       // "name_regex" and "name_not_regex" properties match
3810       if (get_name().empty())
3811 	{
3812 	  const regex_t_sptr name_regex = priv_->get_name_regex();
3813 	  if (name_regex && !regex::match(name_regex, var_name))
3814 	    return false;
3815 
3816 	  const regex_t_sptr name_not_regex = priv_->get_name_not_regex();
3817 	  if (name_not_regex && regex::match(name_not_regex, var_name))
3818 	    return false;
3819 	}
3820     }
3821 
3822   // Check for the symbol_name, symbol_name_regex and
3823   // symbol_name_not_regex property match.
3824   string var_sym_name = var->get_symbol() ? var->get_symbol()->get_name() : "";
3825   if (!get_symbol_name().empty())
3826     {
3827       if (get_symbol_name() != var_sym_name)
3828 	return false;
3829     }
3830   else
3831     {
3832       const regex_t_sptr sym_name_regex = priv_->get_symbol_name_regex();
3833       if (sym_name_regex && !regex::match(sym_name_regex, var_sym_name))
3834 	return false;
3835 
3836       const regex_t_sptr sym_name_not_regex =
3837 	priv_->get_symbol_name_not_regex();
3838       if (sym_name_not_regex && regex::match(sym_name_not_regex, var_sym_name))
3839 	return false;
3840     }
3841 
3842   // Check for symbol_version and symbol_version_regexp property match
3843   string var_sym_version =
3844     var->get_symbol() ? var->get_symbol()->get_version().str() : "";
3845   if (!get_symbol_version().empty())
3846     {
3847       if (get_symbol_version() != var_sym_version)
3848 	return false;
3849     }
3850   else
3851     {
3852       const regex_t_sptr symbol_version_regex =
3853 	priv_->get_symbol_version_regex();
3854       if (symbol_version_regex
3855 	  && !regex::match(symbol_version_regex, var_sym_version))
3856 	return false;
3857     }
3858 
3859   // Check for the "type_name" and type_name_regex properties match.
3860   string var_type_name =
3861     get_type_declaration(var->get_type())->get_qualified_name();
3862 
3863   if (!get_type_name().empty())
3864     {
3865       if (get_type_name() != var_type_name)
3866 	return false;
3867     }
3868   else
3869     {
3870       if (get_type_name().empty())
3871 	{
3872 	  const regex_t_sptr type_name_regex = priv_->get_type_name_regex();
3873 	  if (type_name_regex && !regex::match(type_name_regex, var_type_name))
3874 	    return false;
3875 	}
3876     }
3877 
3878   return true;
3879 }
3880 
3881 /// Evaluate the current variable suppression specification on a given
3882 /// @ref var_decl and say if a report about a change involving this
3883 /// @ref var_decl should be suppressed or not.
3884 ///
3885 /// @param var the @ref var_decl to evaluate this suppression
3886 /// specification against.
3887 ///
3888 /// @param k the kind of variable change @p var is supposed to have.
3889 ///
3890 /// @param ctxt the context of the current diff.
3891 ///
3892 /// @return true iff a report about a change involving the variable @p
3893 /// var should be suppressed.
3894 bool
suppresses_variable(const var_decl_sptr var,change_kind k,const diff_context_sptr ctxt) const3895 variable_suppression::suppresses_variable(const var_decl_sptr var,
3896 					  change_kind k,
3897 					  const diff_context_sptr ctxt) const
3898 {return suppresses_variable(var.get(), k, ctxt);}
3899 
3900 /// Evaluate the current variable suppression specification on a given
3901 /// @ref elf_symbol and say if a report about a change involving this
3902 /// @ref elf_symbol should be suppressed or not.
3903 ///
3904 /// @param sym the @ref elf_symbol to evaluate this suppression
3905 /// specification against.
3906 ///
3907 /// @param k the kind of variable change @p sym is supposed to have.
3908 ///
3909 /// @param ctxt the context of the current diff.
3910 ///
3911 /// @return true iff a report about a change involving the symbol @p
3912 /// sym should be suppressed.
3913 bool
suppresses_variable_symbol(const elf_symbol * sym,change_kind k,const diff_context_sptr ctxt) const3914 variable_suppression::suppresses_variable_symbol(const elf_symbol* sym,
3915 						 change_kind k,
3916 						 const diff_context_sptr ctxt) const
3917 {
3918   if (!sym)
3919     return false;
3920 
3921   if (!(get_change_kind() & k))
3922     return false;
3923 
3924   if (!sym->is_variable())
3925     return false;
3926 
3927   ABG_ASSERT(k & ADDED_VARIABLE_CHANGE_KIND
3928 	 || k & DELETED_VARIABLE_CHANGE_KIND);
3929 
3930   // Check if the name and soname of the binaries match the current
3931   // suppr spec.
3932   if (ctxt)
3933     {
3934       // Check if the name of the binaries match the current suppr
3935       // spec
3936       if (!names_of_binaries_match(*this, *ctxt))
3937 	if (has_file_name_related_property())
3938 	  return false;
3939 
3940       // Check if the soname of the binaries match the current suppr spec
3941       if (!sonames_of_binaries_match(*this, *ctxt))
3942 	if (has_soname_related_property())
3943 	  return false;
3944     }
3945 
3946   string sym_name = sym->get_name(), sym_version = sym->get_version().str();
3947 
3948   bool no_symbol_name = false, no_symbol_version = false;
3949 
3950   // Consider the symbol name
3951   if (!get_name().empty())
3952     {
3953       if (get_name() != sym_name)
3954 	return false;
3955     }
3956   else if (!get_symbol_name().empty())
3957     {
3958       if (get_symbol_name() != sym_name)
3959 	return false;
3960     }
3961   else if (!get_symbol_name_regex_str().empty())
3962     {
3963       const regex_t_sptr sym_name_regex = priv_->get_symbol_name_regex();
3964       if (sym_name_regex && !regex::match(sym_name_regex, sym_name))
3965 	return false;
3966     }
3967   else
3968     no_symbol_name = true;
3969 
3970   // Consider the symbol version.
3971   if (!get_symbol_version().empty())
3972     {
3973       if (get_symbol_version() != sym_version)
3974 	return false;
3975     }
3976   else if (!get_symbol_version_regex_str().empty())
3977     {
3978       const regex_t_sptr symbol_version_regex =
3979 	priv_->get_symbol_version_regex();
3980       if (symbol_version_regex
3981 	  && !regex::match(symbol_version_regex, sym_version))
3982 	return false;
3983     }
3984   else
3985     no_symbol_version = true;
3986 
3987   if (no_symbol_name && no_symbol_version)
3988     return false;
3989 
3990   return true;
3991 }
3992 
3993 /// Evaluate the current variable suppression specification on a given
3994 /// @ref elf_symbol and say if a report about a change involving this
3995 /// @ref elf_symbol should be suppressed or not.
3996 ///
3997 /// @param sym the @ref elf_symbol to evaluate this suppression
3998 /// specification against.
3999 ///
4000 /// @param k the kind of variable change @p sym is supposed to have.
4001 ///
4002 /// @param ctxt the context of the current diff.
4003 ///
4004 /// @return true iff a report about a change involving the symbol @p
4005 /// sym should be suppressed.
4006 bool
suppresses_variable_symbol(const elf_symbol_sptr sym,change_kind k,const diff_context_sptr ctxt) const4007 variable_suppression::suppresses_variable_symbol(const elf_symbol_sptr sym,
4008 						 change_kind k,
4009 						 const diff_context_sptr ctxt) const
4010 {return suppresses_variable_symbol(sym.get(), k, ctxt);}
4011 
4012 /// Test if an instance of @ref suppression is an instance of @ref
4013 /// variable_suppression.
4014 ///
4015 /// @param suppr the instance of @ref suppression to test for.
4016 ///
4017 /// @return if @p suppr is an instance of @ref variable_suppression, then
4018 /// return the sub-object of the @p suppr of type @ref
4019 /// variable_suppression, otherwise return a nil pointer.
4020 variable_suppression_sptr
is_variable_suppression(const suppression_sptr s)4021 is_variable_suppression(const suppression_sptr s)
4022 {return dynamic_pointer_cast<variable_suppression>(s);}
4023 
4024 /// The bitwise 'and' operator for the enum @ref
4025 /// variable_suppression::change_kind.
4026 ///
4027 /// @param l the first operand of the 'and' operator.
4028 ///
4029 /// @param r the second operand of the 'and' operator.
4030 ///
4031 /// @return the result of 'and' operation on @p l and @p r.
4032 variable_suppression::change_kind
operator &(variable_suppression::change_kind l,variable_suppression::change_kind r)4033 operator&(variable_suppression::change_kind l,
4034 	  variable_suppression::change_kind r)
4035 {
4036   return static_cast<variable_suppression::change_kind>
4037     (static_cast<unsigned>(l) & static_cast<unsigned>(r));
4038 }
4039 
4040 /// The bitwise 'or' operator for the enum @ref
4041 /// variable_suppression::change_kind.
4042 ///
4043 /// @param l the first operand of the 'or' operator.
4044 ///
4045 /// @param r the second operand of the 'or' operator.
4046 ///
4047 /// @return the result of 'or' operation on @p l and @p r.
4048 variable_suppression::change_kind
operator |(variable_suppression::change_kind l,variable_suppression::change_kind r)4049 operator|(variable_suppression::change_kind l,
4050 	  variable_suppression::change_kind r)
4051 {
4052     return static_cast<variable_suppression::change_kind>
4053     (static_cast<unsigned>(l) | static_cast<unsigned>(r));
4054 }
4055 
4056 /// Parse variable suppression specification, build a resulting @ref
4057 /// variable_suppression type and return a shared pointer to that
4058 /// object.
4059 ///
4060 /// @return a shared pointer to the newly built @ref
4061 /// variable_suppression.  If the variable suppression specification
4062 /// could not be parsed then a nil shared pointer is returned.
4063 static variable_suppression_sptr
read_variable_suppression(const ini::config::section & section)4064 read_variable_suppression(const ini::config::section& section)
4065 {
4066   variable_suppression_sptr result;
4067 
4068   if (section.get_name() != "suppress_variable")
4069     return result;
4070 
4071   static const char *const sufficient_props[] = {
4072     "label",
4073     "file_name_regexp",
4074     "file_name_not_regexp",
4075     "soname_regexp",
4076     "soname_not_regexp",
4077     "name",
4078     "name_regexp",
4079     "name_not_regexp",
4080     "symbol_name",
4081     "symbol_name_regexp",
4082     "symbol_name_not_regexp",
4083     "symbol_version",
4084     "symbol_version_regexp",
4085     "type_name",
4086     "type_name_regexp",
4087   };
4088   if (!check_sufficient_props(sufficient_props,
4089 			      sizeof(sufficient_props)/sizeof(char*),
4090 			      section))
4091     return result;
4092 
4093   ini::simple_property_sptr drop_artifact =
4094     is_simple_property(section.find_property("drop_artifact"));
4095   if (!drop_artifact)
4096     drop_artifact = is_simple_property(section.find_property("drop"));
4097 
4098   string drop_artifact_str = drop_artifact
4099     ? drop_artifact->get_value()->as_string()
4100     : "";
4101 
4102   ini::simple_property_sptr change_kind_prop =
4103     is_simple_property(section.find_property("change_kind"));
4104   string change_kind_str = change_kind_prop
4105     ? change_kind_prop->get_value()->as_string()
4106     : "";
4107 
4108   ini::simple_property_sptr label_prop =
4109     is_simple_property(section.find_property("label"));
4110   string label_str = (label_prop
4111 		      ? label_prop->get_value()->as_string()
4112 		      : "");
4113 
4114   ini::simple_property_sptr file_name_regex_prop =
4115     is_simple_property(section.find_property("file_name_regexp"));
4116   string file_name_regex_str =
4117     file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
4118 
4119  ini::simple_property_sptr file_name_not_regex_prop =
4120     is_simple_property(section.find_property("file_name_not_regexp"));
4121   string file_name_not_regex_str =
4122     file_name_not_regex_prop
4123     ? file_name_not_regex_prop->get_value()->as_string()
4124     : "";
4125 
4126   ini::simple_property_sptr soname_regex_prop =
4127     is_simple_property(section.find_property("soname_regexp"));
4128   string soname_regex_str =
4129     soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
4130 
4131   ini::simple_property_sptr soname_not_regex_prop =
4132     is_simple_property(section.find_property("soname_not_regexp"));
4133   string soname_not_regex_str =
4134     soname_not_regex_prop
4135     ? soname_not_regex_prop->get_value()->as_string()
4136     : "";
4137 
4138   ini::simple_property_sptr name_prop =
4139     is_simple_property(section.find_property("name"));
4140   string name_str = (name_prop
4141 		     ? name_prop->get_value()->as_string()
4142 		     : "");
4143 
4144   ini::simple_property_sptr name_regex_prop =
4145     is_simple_property(section.find_property("name_regexp"));
4146   string name_regex_str = (name_regex_prop
4147 			   ? name_regex_prop->get_value()->as_string()
4148 			   : "");
4149 
4150   ini::simple_property_sptr name_not_regex_prop =
4151     is_simple_property(section.find_property("name_not_regexp"));
4152   string name_not_regex_str = name_not_regex_prop
4153     ? name_not_regex_prop->get_value()->as_string()
4154     : "";
4155 
4156   ini::simple_property_sptr sym_name_prop =
4157     is_simple_property(section.find_property("symbol_name"));
4158   string symbol_name = (sym_name_prop
4159 			? sym_name_prop->get_value()->as_string()
4160 			: "");
4161 
4162   ini::simple_property_sptr sym_name_regex_prop =
4163     is_simple_property(section.find_property("symbol_name_regexp"));
4164   string symbol_name_regex_str = sym_name_regex_prop
4165     ? sym_name_regex_prop->get_value()->as_string()
4166     : "";
4167 
4168   ini::simple_property_sptr sym_name_not_regex_prop =
4169     is_simple_property(section.find_property("symbol_name_not_regexp"));
4170   string symbol_name_not_regex_str = sym_name_not_regex_prop
4171     ? sym_name_not_regex_prop->get_value()->as_string()
4172     : "";
4173 
4174   ini::simple_property_sptr sym_version_prop =
4175     is_simple_property(section.find_property("symbol_version"));
4176   string symbol_version = sym_version_prop
4177     ? sym_version_prop->get_value()->as_string()
4178     : "";
4179 
4180   ini::simple_property_sptr sym_version_regex_prop =
4181     is_simple_property(section.find_property("symbol_version_regexp"));
4182   string symbol_version_regex_str = sym_version_regex_prop
4183     ? sym_version_regex_prop->get_value()->as_string()
4184      : "";
4185 
4186   ini::simple_property_sptr type_name_prop =
4187     is_simple_property(section.find_property("type_name"));
4188   string type_name_str = type_name_prop
4189     ? type_name_prop->get_value()->as_string()
4190     : "";
4191 
4192   ini::simple_property_sptr type_name_regex_prop =
4193     is_simple_property(section.find_property("type_name_regexp"));
4194   string type_name_regex_str = type_name_regex_prop
4195     ? type_name_regex_prop->get_value()->as_string()
4196      : "";
4197 
4198   result.reset(new variable_suppression(label_str,
4199 					name_str,
4200 					name_regex_str,
4201 					symbol_name,
4202 					symbol_name_regex_str,
4203 					symbol_version,
4204 					symbol_version_regex_str,
4205 					type_name_str,
4206 					type_name_regex_str));
4207 
4208   if ((drop_artifact_str == "yes" || drop_artifact_str == "true")
4209       && (!name_str.empty()
4210 	  || !name_regex_str.empty()
4211 	  || !name_not_regex_str.empty()
4212 	  || !symbol_name.empty()
4213 	  || !symbol_name_regex_str.empty()
4214 	  || !symbol_name_not_regex_str.empty()))
4215     result->set_drops_artifact_from_ir(true);
4216 
4217   if (!name_not_regex_str.empty())
4218     result->set_name_not_regex_str(name_not_regex_str);
4219 
4220   if (!symbol_name_not_regex_str.empty())
4221     result->set_symbol_name_not_regex_str(symbol_name_not_regex_str);
4222 
4223   if (!change_kind_str.empty())
4224     result->set_change_kind
4225       (variable_suppression::parse_change_kind(change_kind_str));
4226 
4227   if (!file_name_regex_str.empty())
4228     result->set_file_name_regex_str(file_name_regex_str);
4229 
4230   if (!file_name_not_regex_str.empty())
4231     result->set_file_name_not_regex_str(file_name_not_regex_str);
4232 
4233   if (!soname_regex_str.empty())
4234     result->set_soname_regex_str(soname_regex_str);
4235 
4236   if (!soname_not_regex_str.empty())
4237     result->set_soname_not_regex_str(soname_not_regex_str);
4238 
4239   return result;
4240 }
4241 
4242 // </variable_suppression stuff>
4243 
4244 // <file_suppression stuff>
4245 
4246 /// Constructor for the the @ref file_suppression type.
4247 ///
4248 /// @param label the label of the suppression directive.
4249 ///
4250 /// @param fname_regex_str the regular expression string that
4251 /// designates the file name that instances of @ref file_suppression
4252 /// should match.
4253 ///
4254 /// @param fname_not_regex_str the regular expression string that
4255 /// designates the file name that instances of @ref file_suppression
4256 /// shoult *NOT* match.  In other words, this file_suppression should
4257 /// be activated if its file name does not match the regular
4258 /// expression @p fname_not_regex_str.
file_suppression(const string & label,const string & fname_regex_str,const string & fname_not_regex_str)4259 file_suppression::file_suppression(const string& label,
4260 				   const string& fname_regex_str,
4261 				   const string& fname_not_regex_str)
4262   : suppression_base(label,
4263 		     fname_regex_str,
4264 		     fname_not_regex_str)
4265 {}
4266 
4267 /// Test if instances of this @ref file_suppression suppresses a
4268 /// certain instance of @ref diff.
4269 ///
4270 /// This function always returns false because, obviously, a
4271 /// file_suppression is meants to prevents Abigail tools from loading
4272 /// some files.  It is not meant to act on instance of @ref diff.
4273 /// @return false.
4274 bool
suppresses_diff(const diff *) const4275 file_suppression::suppresses_diff(const diff*) const
4276 {return false;}
4277 
4278 /// Test if a instances of this @ref file_suppression suppresses a
4279 /// given file.
4280 ///
4281 /// @param file_path the file path to test against.
4282 ///
4283 /// @return true iff this file_suppression matches the file path @p
4284 /// file_path.
4285 bool
suppresses_file(const string & file_path)4286 file_suppression::suppresses_file(const string& file_path)
4287 {
4288   if (file_path.empty())
4289     return false;
4290 
4291   string fname;
4292   tools_utils::base_name(file_path, fname);
4293 
4294   bool has_regexp = false;
4295 
4296   if (regex_t_sptr regexp = suppression_base::priv_->get_file_name_regex())
4297     {
4298       has_regexp = true;
4299       if (!regex::match(regexp, fname))
4300 	return false;
4301     }
4302 
4303   if (regex_t_sptr regexp = suppression_base::priv_->get_file_name_not_regex())
4304     {
4305       has_regexp = true;
4306       if (regex::match(regexp, fname))
4307 	return false;
4308     }
4309 
4310   if (!has_regexp)
4311     return false;
4312 
4313   return true;
4314 }
4315 
4316 /// Destructor of @ref file_suppression.
~file_suppression()4317 file_suppression::~file_suppression()
4318 {
4319 }
4320 
4321 /// Read a file suppression from an instance of ini::config::section
4322 /// and build a @ref type_suppression as a result.
4323 ///
4324 /// @param section the section (from an ini file) to read the file
4325 /// suppression from.
4326 ///
4327 /// @return file_suppression_sptr.
4328 static file_suppression_sptr
read_file_suppression(const ini::config::section & section)4329 read_file_suppression(const ini::config::section& section)
4330 {
4331   file_suppression_sptr result;
4332 
4333   if (section.get_name() != "suppress_file")
4334     return result;
4335 
4336   static const char *const sufficient_props[] = {
4337     "file_name_regexp",
4338     "file_name_not_regexp",
4339     "soname_regexp",
4340     "soname_not_regexp",
4341   };
4342   if (!check_sufficient_props(sufficient_props,
4343 			      sizeof(sufficient_props)/sizeof(char*),
4344 			      section))
4345     return result;
4346 
4347   ini::simple_property_sptr label_prop =
4348     is_simple_property(section.find_property("label"));
4349   string label_str = (label_prop
4350 		      ? label_prop->get_value()->as_string()
4351 		      : "");
4352 
4353   ini::simple_property_sptr file_name_regex_prop =
4354     is_simple_property(section.find_property("file_name_regexp"));
4355   string file_name_regex_str =
4356     file_name_regex_prop ? file_name_regex_prop->get_value()->as_string() : "";
4357 
4358  ini::simple_property_sptr file_name_not_regex_prop =
4359     is_simple_property(section.find_property("file_name_not_regexp"));
4360   string file_name_not_regex_str =
4361     file_name_not_regex_prop
4362     ? file_name_not_regex_prop->get_value()->as_string()
4363     : "";
4364 
4365   ini::simple_property_sptr soname_regex_prop =
4366     is_simple_property(section.find_property("soname_regexp"));
4367   string soname_regex_str =
4368     soname_regex_prop ? soname_regex_prop->get_value()->as_string() : "";
4369 
4370   ini::simple_property_sptr soname_not_regex_prop =
4371     is_simple_property(section.find_property("soname_not_regexp"));
4372   string soname_not_regex_str =
4373     soname_not_regex_prop
4374     ? soname_not_regex_prop->get_value()->as_string()
4375     : "";
4376 
4377   result.reset(new file_suppression(label_str,
4378 				    file_name_regex_str,
4379 				    file_name_not_regex_str));
4380 
4381   if (!soname_regex_str.empty())
4382     {
4383       result->set_soname_regex_str(soname_regex_str);
4384       result->set_drops_artifact_from_ir(true);
4385     }
4386 
4387   if (!soname_not_regex_str.empty())
4388     {
4389       result->set_soname_not_regex_str(soname_not_regex_str);
4390       result->set_drops_artifact_from_ir(true);
4391     }
4392 
4393   return result;
4394 }
4395 
4396 /// Test if a given suppression specification is a file suppression
4397 /// specification.
4398 ///
4399 /// @param s the instance of @ref suppression_base to test.
4400 ///
4401 /// @return the instance of @ref file_suppression that @p s points to,
4402 /// iff s is an instance of @ref file_suppression.  Otherwise, returns
4403 /// nil.
4404 file_suppression_sptr
is_file_suppression(const suppression_sptr s)4405 is_file_suppression(const suppression_sptr s)
4406 {return dynamic_pointer_cast<file_suppression>(s);}
4407 
4408 /// Test if a given file path is "suppressed" by at least one file
4409 /// suppression specification among a vector of suppression
4410 /// specifications.
4411 ///
4412 /// @param file_path the file path to test.
4413 ///
4414 /// @param sprs the vector of suppressions to use to test if one of
4415 /// them at lease matches the file path @p file_path.
4416 ///
4417 /// @return a pointer to the first instance of @ref file_suppression
4418 /// that matches @p file_path, or nil if no file suppression matches.
4419 file_suppression_sptr
file_is_suppressed(const string & file_path,const suppressions_type & sprs)4420 file_is_suppressed(const string& file_path,
4421 		   const suppressions_type& sprs)
4422 {
4423   for (suppressions_type::const_iterator i = sprs.begin(); i != sprs.end(); ++i)
4424     if (file_suppression_sptr s = is_file_suppression(*i))
4425       if (s->suppresses_file(file_path))
4426 	return s;
4427 
4428   return file_suppression_sptr();
4429 }
4430 
4431 /// Test if a given SONAME is matched by a given suppression
4432 /// specification.
4433 ///
4434 /// @param soname the SONAME to consider.
4435 ///
4436 /// @param suppr the suppression specification to consider.
4437 ///
4438 /// @return true iff a given SONAME is matched by a given suppression
4439 /// specification.
4440 bool
suppression_matches_soname(const string & soname,const suppression_base & suppr)4441 suppression_matches_soname(const string& soname,
4442 			   const suppression_base& suppr)
4443 {
4444   return suppr.priv_->matches_soname(soname);
4445 }
4446 
4447 /// Test if a given SONAME or file name is matched by a given
4448 /// suppression specification.
4449 ///
4450 /// @param soname the SONAME to consider.
4451 ///
4452 /// @param filename the file name to consider.
4453 ///
4454 /// @param suppr the suppression specification to consider.
4455 ///
4456 /// @return true iff either @p soname or @p filename is matched by the
4457 /// suppression specification @p suppr.
4458 bool
suppression_matches_soname_or_filename(const string & soname,const string & filename,const suppression_base & suppr)4459 suppression_matches_soname_or_filename(const string& soname,
4460 				       const string& filename,
4461 				       const suppression_base& suppr)
4462 {
4463   return (suppression_matches_soname(soname, suppr)
4464 	 || suppr.priv_->matches_binary_name(filename));
4465 }
4466 
4467 /// @return the name of the artificial private type suppression
4468 /// specification that is auto-generated by libabigail to suppress
4469 /// change reports about types that are not defined in public headers.
4470 const char*
get_private_types_suppr_spec_label()4471 get_private_types_suppr_spec_label()
4472 {
4473   static const char *PRIVATE_TYPES_SUPPR_SPEC_NAME =
4474     "Artificial private types suppression specification";
4475 
4476   return PRIVATE_TYPES_SUPPR_SPEC_NAME;
4477 }
4478 
4479 /// Test if a type suppression specification represents a private type
4480 /// suppression automatically generated by libabigail from the user
4481 /// telling us where public headers are.
4482 ///
4483 /// @param s the suppression specification we are looking at.
4484 ///
4485 /// @return true iff @p s is a private type suppr spec.
4486 bool
is_private_type_suppr_spec(const type_suppression & s)4487 is_private_type_suppr_spec(const type_suppression& s)
4488 {return s.get_label() == get_private_types_suppr_spec_label();}
4489 
4490 /// Test if a type suppression specification represents a private type
4491 /// suppression automatically generated by libabigail from the user
4492 /// telling us where public headers are.
4493 ///
4494 /// @param s the suppression specification we are looking at.
4495 ///
4496 /// @return true iff @p s is a private type suppr spec.
4497 bool
is_private_type_suppr_spec(const suppression_sptr & s)4498 is_private_type_suppr_spec(const suppression_sptr& s)
4499 {
4500   type_suppression_sptr type_suppr = is_type_suppression(s);
4501   return (type_suppr
4502 	  && type_suppr->get_label() == get_private_types_suppr_spec_label());
4503 }
4504 
4505 // </file_suppression stuff>
4506 }// end namespace suppr
4507 } // end namespace abigail
4508