]> sourceware.org Git - libabigail.git/commitdiff
Initial support for function suppressions
authorDodji Seketeli <dodji@redhat.com>
Tue, 28 Oct 2014 10:32:15 +0000 (11:32 +0100)
committerDodji Seketeli <dodji@redhat.com>
Tue, 28 Oct 2014 16:36:32 +0000 (17:36 +0100)
* include/abg-comparison.h (enum visiting_kind): Change the
meaning of this.  It was to determine if traversal was to be done
in a pre or post manner.  But with the recent addition of
diff_node_visitor::visit_{begin,end}() notifiers, the pre/post
handling is taken care of in a different way.  So now the meaning
of this enum is changed to handle whether diff node children
should be visited or not.  So the enumerators are now
DEFAULT_VISITING_KIND, and SKIP_CHILDREN_VISITING_KIND.  And it's
a bit-field.
(operator{&,~}): Declare more bit manipulation operators for the
enum visiting_kind.
(function_suppression_sptr, function_suppressions_type): New
typedefs.
(function_suppression, function_suppression::parameter_spec):
Declare new types.
(read_function_suppressions): Declare new function.
(diff_node_visitor::diff_node_visitor): Adjust for the enum
visiting_kind change.  Value-initialize the visiting_kind_ data
member.
* src/abg-comparison.cc (operator{&,~}): Define these operators
for enum visiting_kind.
(read_type_suppressions): Forward declare this static function.
(read_function_suppression, read_parameter_spec_from_string):
Define new static functions.
(read_suppressions): Update to read function suppressions too,
using the new read_function_suppression function above.
(class function_suppression::parameter_spec::priv): Define new
type.
(function_suppression::parameter_spec::*): Define the member
functions of the new function_suppression::parameter_spec type.
(class function_suppression::priv): Define new type.
(function_suppression::*): Define the member functions of the new
function_suppression type.
(diff::traverse): There is no more {PRE,POST}_VISITING_KIND
enumerator.  So nuke the code that was dealing with it.
(redundancy_marking_visitor::skip_children_nodes_): New data
member flag.
(redundancy_marking_visitor::visit_begin): If the current diff
node is not be reported (is filtered out), do not bother visit its
children nodes for the purpose of marking redundant nodes.  So use
the new skip_children_nodes_ flag above to know we are in that case.
(redundancy_marking_visitor::visit_end): Unset the new
skip_children_nodes_ flag above when appropriate.
* include/abg-fwd.h (is_function_decl): Declare new function.
* include/abg-ir.h
(function_type::get_parm_at_index_from_first_non_implicit_parm):
Declare new member function.
* src/abg-ir.cc (is_function_decl): Define new function.
(function_type::get_parm_at_index_from_first_non_implicit_parm):
Define new member function.
* src/abg-comp-filter.cc (apply_filter): Adjust for the enum
visiting_kind change.  No need to set it for filters anymore
* doc/suppr-doc.txt: Update examples of function suppression.
* doc/manuals/libabigail-concepts.rst: Update the manual for the
function suppression addition.
* tests/data/test-diff-suppr/libtest5-fn-suppr-v0.so: New test input.
* tests/data/test-diff-suppr/libtest5-fn-suppr-v1.so: New test input.
* tests/data/test-diff-suppr/libtest6-fn-suppr-v0.so: New test input.
* tests/data/test-diff-suppr/libtest6-fn-suppr-v1.so: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-0.suppr: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-1.suppr: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-2.suppr: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-3.suppr: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-4.suppr: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-report-0.txt: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-report-1.txt: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-report-2.txt: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-report-3.txt: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-report-4.txt: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-report-5.txt: New test input.
* tests/data/test-diff-suppr/test5-fn-suppr-v0.cc: Source code for
new test input.
* tests/data/test-diff-suppr/test5-fn-suppr-v1.cc: Source code for
new test input.
* tests/data/test-diff-suppr/test6-fn-suppr-0.suppr: New test input.
* tests/data/test-diff-suppr/test6-fn-suppr-1.suppr: New test input.
* tests/data/test-diff-suppr/test6-fn-suppr-2.suppr: New test input.
* tests/data/test-diff-suppr/test6-fn-suppr-3.suppr: New test input.
* tests/data/test-diff-suppr/test6-fn-suppr-report-0.txt: New test input.
* tests/data/test-diff-suppr/test6-fn-suppr-report-1.txt: New test input.
* tests/data/test-diff-suppr/test6-fn-suppr-report-2.txt: New test input.
* tests/data/test-diff-suppr/test6-fn-suppr-report-3.txt: New test input.
* tests/data/test-diff-suppr/test6-fn-suppr-report-4.txt: New test input.
* tests/data/test-diff-suppr/test6-fn-suppr-v0.cc: Source code for
new test input.
* tests/data/test-diff-suppr/test6-fn-suppr-v1.cc: Source code for
new test input.
* tests/data/test-diff-suppr/test6-fn-suppr-version-script: New
test input.
* tests/Makefile.am: Add the new files above to source
the distribution.
* tests/test-diff-suppr.cc (in_out_specs): Add the test inputs
above to the list of tests to be run by this harness.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
39 files changed:
doc/manuals/libabigail-concepts.rst
doc/suppr-doc.txt
include/abg-comparison.h
include/abg-fwd.h
include/abg-ir.h
src/abg-comp-filter.cc
src/abg-comparison.cc
src/abg-ir.cc
tests/Makefile.am
tests/data/test-diff-suppr/libtest5-fn-suppr-v0.so [new file with mode: 0755]
tests/data/test-diff-suppr/libtest5-fn-suppr-v1.so [new file with mode: 0755]
tests/data/test-diff-suppr/libtest6-fn-suppr-v0.so [new file with mode: 0755]
tests/data/test-diff-suppr/libtest6-fn-suppr-v1.so [new file with mode: 0755]
tests/data/test-diff-suppr/test5-fn-suppr-0.suppr [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-1.suppr [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-2.suppr [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-3.suppr [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-4.suppr [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-report-0.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-report-1.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-report-2.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-report-3.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-report-4.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-report-5.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-v0.cc [new file with mode: 0644]
tests/data/test-diff-suppr/test5-fn-suppr-v1.cc [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-0.suppr [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-1.suppr [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-2.suppr [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-3.suppr [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-report-0.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-report-1.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-report-2.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-report-3.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-report-4.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-v0.cc [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-v1.cc [new file with mode: 0644]
tests/data/test-diff-suppr/test6-fn-suppr-version-script [new file with mode: 0644]
tests/test-diff-suppr.cc

index ae5dc886907c6c496ec0b23558e50e7e62432281..99c3e8cd5f0a24f00a0324d2cf6eed7cbe881caa 100644 (file)
@@ -94,6 +94,40 @@ Suppression specifications
      Leading and trailing white spaces are ignored around property
      name and values.
 
+.. _suppr_regexp_label:
+
+    * Regular expressions
+
+      The value of some properties might be a regular expression.  In
+      that case, they must comply with the syntax of `extended POSIX
+      regular expressions
+      <http://www.gnu.org/software/findutils/manual/html_node/find_html/posix_002dextended-regular-expression-syntax.html#posix_002dextended-regular-expression-syntax>`_.
+      Note that Libabigail uses the regular expression engine of the
+      `GNU C Library`_.
+
+    * Escaping a character in a regular expression
+
+      When trying to match a string that contains a ``*`` character,
+      like int the pointer type ``int*``, one must be careful to
+      notice that the character ``*`` is a special character in the
+      extended POSIX regular expression syntax.  And that character
+      must be escaped for the regular expression engine.  Thus the
+      regular expression that would match the string ``int*`` in a
+      suppression file should be ::
+
+        int\\*
+
+      Wait; but then why the two ``\`` characters?  Well, because the
+      ``\`` character is a special character in the `Ini File Syntax`_
+      used for specifying suppressions.  So it must be escaped as
+      well, so that the Ini File parser leaves a ``\`` character
+      intact in the data stream that is handed to the regular
+      expression engine.  Hence the ``\\`` targeted at the Ini File
+      parser.
+
+      So, in short, to escape a character in a regular expression,
+      always prefix the character with the ``\\`` sequence.
+
     * Sections
 
      Properties are then grouped into arbitrarily named sections that
@@ -117,7 +151,7 @@ Suppression specifications
        Suppresses report messages about a type change.  The potential
        properties of this sections are:
 
-         * ``name_regexp`` ``=`` <regular-expression>
+         * ``name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
 
             Suppresses change reports involving types whose name
             matches the regular expression specified as value of this
@@ -157,6 +191,7 @@ Suppression specifications
                native) types.  Example of built-in types are char,
                int, unsigned int, etc.
 
+.. _suppr_label_property_label:
 
          * ``label`` ``=`` <some-value>
 
@@ -164,6 +199,104 @@ Suppression specifications
            informative string that might be used by abidiff to refer
            to a type suppression in error messages.
 
+      * ``[suppress_function]``
+
+       Suppresses report messages about a change the sub-types of a
+       function.  The potential properties of this sections are:
+
+         * ``label`` ``=`` <some-value>
+
+            This property is the same as the :ref:`label property
+            <suppr_label_property_label>` defined above.
+
+         *  ``name`` ``=`` <some-value>
+
+           Suppresses change reports involving functions whose name
+           equals the value of this property.
+
+         *  ``name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
+
+           Suppresses change reports involving functions whose name
+           matches the regular expression specified as value of this
+           property.
+
+          * ``parameter`` ``=`` <function-parameter-specification>
+
+           Suppresses change reports involving functions whose
+           parameters match the parameter specification indicated as
+           value of this property.
+
+           The format of the function parameter specification is:
+
+             ``'``<parameter-index> `` `` <type-name-or-regular-expression>
+
+           That is, an apostrophe followed by a number that is the
+           index of the parameter, followed by one of several spaces,
+           followed by either the name of the type of the parameter,
+           or a regular expression describing a family of parameter
+           type names.
+
+           If the parameter type name is designated by a regular
+           expression, then said regular expression must be enclosed
+           between two slashes; like ``/some-regular-expression/``.
+
+           The index of the first parameter of the function is zero.
+           Note that for member functions (methods of classes), the
+           this is the first parameter that comes after the implicit
+           "this" pointer parameter.
+
+           Examples of function parameter specifications are: ::
+
+             '0 int
+
+            Which means, the parameter at index 0, whose type name is
+            ``int``. ::
+
+             '4 unsigned char*
+
+           Which means, the parameter at index 4, whose type name is
+           ``unsigned char*``.  ::
+
+             '2 /^foo.*&/
+
+           Which means, the parameter at index 2, whose type name
+           starts with the string "foo" and ends with an '&'.  In
+           other words, this is the third parameter and it's a
+           reference on a type that starts with the string "foo".
+
+         *  ``return_type_name`` ``=`` <some-value>
+
+           Suppresses change reports involving functions whose return
+           type name equals the value of this property.
+
+         *  ``return_type_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
+
+           Suppresses change reports involving functions whose return
+           type name matches the regular expression specified as
+           value of this property.
+
+         *  ``symbol_name`` ``=`` <some-value>
+
+           Suppresses change reports involving functions whose symbol
+           name equals the value of this property.
+
+         *  ``symbol_name_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
+
+           Suppresses change reports involving functions whose symbol
+           name matches the regular expression specified as value of
+           this property.
+
+         *  ``symbol_version`` ``=`` <some-value>
+
+           Suppresses change reports involving functions whose symbol
+           version equals the value of this property.
+
+         *  ``symbol_version_regexp`` ``=`` <:ref:`regular-expression <suppr_regexp_label>`>
+
+           Suppresses change reports involving functions whose symbol
+           version matches the regular expression specified as value
+           of this property.
+
     * Comments
 
       ``;`` or ``#`` ASCII character at the beginning of a line
@@ -171,8 +304,10 @@ Suppression specifications
 
   * Code examples
 
-    Suppose we have a library named ``libtest1-v0.so`` which contains this
-    very useful code: ::
+    1. Suppressing change reports about types.
+
+       Suppose we have a library named ``libtest1-v0.so`` which
+       contains this very useful code: ::
 
        $ cat -n test1-v0.cc
             1  // A forward declaration for a type considered to be opaque to
@@ -279,7 +414,225 @@ Suppression specifications
     As you can see, ``abidiff`` does not report the change anymore; it
     tells us that it was filtered out instead.
 
+  2. Suppressing change reports about functions.
+
+     Suppose we have a first version a library named
+     ``libtest2-v0.so`` whose source code is: ::
+
+        $ cat -n test2-v0.cc
+
+         1     struct S1
+         2     {
+         3       int m0;
+         4     
+         5       S1()
+         6         : m0()
+         7       {}
+         8     };
+         9     
+        10     struct S2
+        11     {
+        12       int m0;
+        13     
+        14       S2()
+        15         : m0()
+        16       {}
+        17     };
+        18     
+        19     struct S3
+        20     {
+        21       int m0;
+        22     
+        23       S3()
+        24         : m0()
+        25       {}
+        26     };
+        27     
+        28     int
+        29     func(S1&)
+        30     {
+        31       // suppose the code does something with the argument.
+        32       return 0;
+        33     
+        34     }
+        35     
+        36     char
+        37     func(S2*)
+        38     {
+        39       // suppose the code does something with the argument.
+        40       return 0;
+        41     }
+        42     
+        43     unsigned
+        44     func(S3)
+        45     {
+        46       // suppose the code does something with the argument.
+        47       return 0;
+        48     }
+       $
+       
+     And then we come up with a second version ``libtest2-v1.so`` of
+     that library; the source code is modified by making the
+     structures ``S1``, ``S2``, ``S3`` inherit another struct: ::
+
+       $ cat -n test2-v1.cc
+             1 struct base_type
+             2 {
+             3   int m_inserted;
+             4 };
+             5 
+             6 struct S1 : public base_type // <--- S1 now has base_type as its base
+             7                              // type.
+             8 {
+             9   int m0;
+            10 
+            11   S1()
+            12     : m0()
+            13   {}
+            14 };
+            15 
+            16 struct S2 : public base_type // <--- S2 now has base_type as its base
+            17                              // type.
+            18 {
+            19   int m0;
+            20 
+            21   S2()
+            22     : m0()
+            23   {}
+            24 };
+            25 
+            26 struct S3 : public base_type // <--- S3 now has base_type as its base
+            27                              // type.
+            28 {
+            29   int m0;
+            30 
+            31   S3()
+            32     : m0()
+            33   {}
+            34 };
+            35 
+            36 int
+            37 func(S1&)
+            38 {
+            39   // suppose the code does something with the argument.
+            40   return 0;
+            41 
+            42 }
+            43 
+            44 char
+            45 func(S2*)
+            46 {
+            47   // suppose the code does something with the argument.
+            48   return 0;
+            49 }
+            50 
+            51 unsigned
+            52 func(S3)
+            53 {
+            54   // suppose the code does something with the argument.
+            55   return 0;
+            56 }
+        $ 
+
+     Now let's build the two libraries: ::
+
+        g++ -Wall -g -shared -o libtest2-v0.so test2-v0.cc
+        g++ -Wall -g -shared -o libtest2-v0.so test2-v0.cc
+
+     Let's look at the output of ``abidiff``: ::
+
+        $ abidiff libtest2-v0.so libtest2-v1.so 
+        Functions changes summary: 0 Removed, 3 Changed, 0 Added functions
+        Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+        3 functions with some indirect sub-type change:
+
+          [C]'function unsigned int func(S3)' has some indirect sub-type changes:
+            parameter 0 of type 'struct S3' has sub-type changes:
+              size changed from 32 to 64 bits
+              1 base class insertion:
+                struct base_type
+              1 data member change:
+               'int S3::m0' offset changed from 0 to 32
+
+          [C]'function char func(S2*)' has some indirect sub-type changes:
+            parameter 0 of type 'S2*' has sub-type changes:
+              in pointed to type 'struct S2':
+                size changed from 32 to 64 bits
+                1 base class insertion:
+                  struct base_type
+                1 data member change:
+                 'int S2::m0' offset changed from 0 to 32
+
+          [C]'function int func(S1&)' has some indirect sub-type changes:
+            parameter 0 of type 'S1&' has sub-type changes:
+              in referenced type 'struct S1':
+                size changed from 32 to 64 bits
+                1 base class insertion:
+                  struct base_type
+                1 data member change:
+                 'int S1::m0' offset changed from 0 to 32
+        $
+
+     Let's tell ``abidiff`` to avoid showing us the differences on the
+     overloads of ``func`` that takes either a pointer or a reference.
+     For that, we author this simple suppression specification: ::
+
+        $ cat -n libtest2.suppr
+             1 [suppress_function]
+             2   name = func
+             3   parameter = '0 S1&
+             4 
+             5 [suppress_function]
+             6   name = func
+             7   parameter = '0 S2*
+        $
+     
+     And then let's invoke ``abidiff`` with the suppression
+     specification: ::
+
+       $ ../build/tools/abidiff --suppressions libtest2.suppr libtest2-v0.so libtest2-v1.so 
+       Functions changes summary: 0 Removed, 1 Changed (2 filtered out), 0 Added function
+       Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+       1 function with some indirect sub-type change:
+
+        [C]'function unsigned int func(S3)' has some indirect sub-type changes:
+          parameter 0 of type 'struct S3' has sub-type changes:
+            size changed from 32 to 64 bits
+            1 base class insertion:
+              struct base_type
+            1 data member change:
+             'int S3::m0' offset changed from 0 to 32
+
+
+     The suppression specification could be reduced using
+     :ref:`regular expressions <suppr_regexp_label>`: ::
+
+       $ cat -n libtest2-1.suppr
+           1   [suppress_function]
+           2     name = func
+           3     parameter = '0 /^S.(&|\\*)/
+       $
+
+       $ ../build/tools/abidiff --suppressions libtest2-1.suppr libtest2-v0.so libtest2-v1.so 
+       Functions changes summary: 0 Removed, 1 Changed (2 filtered out), 0 Added function
+       Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+       1 function with some indirect sub-type change:
+
+        [C]'function unsigned int func(S3)' has some indirect sub-type changes:
+          parameter 0 of type 'struct S3' has sub-type changes:
+            size changed from 32 to 64 bits
+            1 base class insertion:
+              struct base_type
+            1 data member change:
+             'int S3::m0' offset changed from 0 to 32
+
+       $
 
 .. _ELF: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
 
 .. _Ini File Syntax: http://en.wikipedia.org/wiki/INI_file
+
+.. _GNU C Library: http://www.gnu.org/software/libc
index 7eb85ac0d80caf318e98f4de0809513e063a7059..3d8c045748c6ad09c90019bc82a6ae12e684512c 100644 (file)
@@ -3,9 +3,19 @@
   name = Dwarf
   type_kind = enum
 # type_kind = typedef|enum|struct|class|union|array|builtin
+# name_regexp = <regex>
 
 [suppress_function]
-  name= .*
+  name = foo
+# name_regexp = blah
+# parameter = '0 <type-name>
+# parameter = '1 /<type-name-regexp>/
+# return_type_name = <return-type>
+# return_type_regexp = <return-type-regexp>
+# symbol_name
+# symbol_name_regexp = <symbol-regexp>
+# symbol_versin = <symbol-version>
+# symbol_version_regexp = <symbol-version-regex>
 
 [suppress_symbol]
   name= _init
index 14cb2f76ea48e5bf173058ca2c63547d03be502a..06b86e3d3104e40c8ebd0217ab3c8ae22be8c11f 100644 (file)
@@ -207,24 +207,27 @@ typedef shared_ptr<diff_traversable_base> diff_traversable_base_sptr;
 
 /// An enum for the different ways to visit a diff tree node.
 ///
-/// This is used by the node traversing code to know when to invoke a
-/// visitor on a diff tree node.
+/// This is used by the node traversing code, to know when to avoid
+/// visiting children nodes, for instance.
 enum visiting_kind
 {
   /// The default enumerator value of this enum.  It doesn't have any
   /// particular meaning yet.
-  NO_VISITING_KIND = 0,
-  /// This says that a visitor should be invoked on a tree node
-  /// *before* visiting the node's children.
-  PRE_VISITING_KIND = 1,
-  /// This says that a visotor should be invoked on a tree node
-  /// *after* visiting the node's children.
-  POST_VISITING_KIND =  1 << 1
+  DEFAULT_VISITING_KIND = 0,
+  /// This says that the traversing code should avoid visiting the
+  /// children nodes of the current node being visited.
+  SKIP_CHILDREN_VISITING_KIND = 1
 };
 
 visiting_kind
 operator|(visiting_kind l, visiting_kind r);
 
+visiting_kind
+operator&(visiting_kind l, visiting_kind r);
+
+visiting_kind
+operator~(visiting_kind l);
+
 ///  The base class for the diff classes that are to be traversed.
 class diff_traversable_base : public traversable_base
 {
@@ -372,6 +375,14 @@ public:
   virtual ~suppression_base();
 }; // end class suppression_base
 
+void
+read_suppressions(std::istream& input,
+                 suppressions_type& suppressions);
+
+void
+read_suppressions(const string& file_path,
+                 suppressions_type& suppressions);
+
 class type_suppression;
 
 /// Convenience typedef for a shared pointer to type_suppression.
@@ -446,15 +457,156 @@ public:
 
 void
 read_type_suppressions(std::istream& input,
-                     type_suppressions_type& suppressions);
+                      type_suppressions_type& suppressions);
 
-void
-read_suppressions(std::istream& input,
-                 suppressions_type& suppressions);
+class function_suppression;
+
+/// Convenience typedef for a shared pointer to function_suppression.
+typedef shared_ptr<function_suppression> function_suppression_sptr;
+
+/// Convenience typedef for a vector of @ref function_suppression_sptr.
+typedef vector<function_suppression_sptr> function_suppressions_type;
+
+/// Abstraction of a function suppression specification.
+///
+/// Specifies under which condition reports about a @ref
+/// function_decl_diff diff node should be dropped on the floor the
+/// purpose of reporting.
+class function_suppression : public suppression_base
+{
+  class priv;
+  typedef shared_ptr<priv> priv_sptr;
+
+  priv_sptr priv_;
+
+  // Forbid this.
+  function_suppression();
+
+public:
+
+  class parameter_spec;
+
+  /// Convenience typedef for shared_ptr of @ref parameter_spec.
+  typedef shared_ptr<parameter_spec> parameter_spec_sptr;
+
+  /// Convenience typedef for vector of @ref parameter_spec_sptr.
+  typedef vector<parameter_spec_sptr> parameter_specs_type;
+
+  function_suppression(const string&           label,
+                      const string&            name,
+                      const string&            name_regex,
+                      const string&            return_type_name,
+                      const string&            return_type_regex,
+                      parameter_specs_type&    parm_specs,
+                      const string&            symbol_name,
+                      const string&            symbol_name_regex,
+                      const string&            symbol_version,
+                      const string&            symbol_version_regex_str);
+
+  virtual ~function_suppression();
+
+  const string&
+  get_function_name() const;
+
+  void
+  set_function_name(const string&);
+
+  const string&
+  get_function_name_regex_str() const;
+
+  void
+  set_function_name_regex_str(const string&);
+
+  const string&
+  get_return_type_name() const;
+
+  void
+  set_return_type_name(const string&);
+
+  const string&
+  get_return_type_regex_str() const;
+
+  void
+  set_return_type_regex_str(const string& r);
+
+  const parameter_specs_type&
+  get_parameter_specs() const;
+
+  void
+  set_parameter_specs(parameter_specs_type&);
+
+  void
+  append_parameter_specs(const parameter_spec_sptr);
+
+  const string&
+  get_symbol_name() const;
+
+  void
+  set_symbol_name(const string& n);
+
+  const string&
+  get_symbol_name_regex_str() const;
+
+  void
+  set_symbol_name_regex_str(const string&);
+
+  const string&
+  get_symbol_version() const;
+
+  void
+  set_symbol_version(const string&);
+
+  const string&
+  get_symbol_version_regex_str() const;
+
+  void
+  set_symbol_version_regex_str(const string&);
+
+  virtual bool
+  suppresses_diff(const diff* diff) const;
+}; // end class function_suppression.
+
+/// Abstraction of the specification of a function parameter in a
+/// function suppression specification.
+class function_suppression::parameter_spec
+{
+  class priv;
+  typedef shared_ptr<priv> priv_sptr;
+
+  friend class function_suppression;
+
+  priv_sptr priv_;
+
+  // Forbid this.
+  parameter_spec();
+
+public:
+  parameter_spec(size_t index,
+                const string& type_name,
+                const string& type_name_regex);
+
+  size_t
+  get_index() const;
+
+  void
+  set_index(size_t);
+
+  const string&
+  get_parameter_type_name() const;
+
+  void
+  set_parameter_type_name(const string&);
+
+  const string&
+  get_parameter_type_name_regex_str() const;
+
+  void
+  set_parameter_type_name_regex_str(const string&);
+};// end class function_suppression::parameter_spec
 
 void
-read_suppressions(const string& file_path,
-                 suppressions_type& suppressions);
+read_function_suppressions(std::istream& input,
+                          function_suppressions_type& suppressions);
 
 /// The context of the diff.  This type holds various bits of
 /// information that is going to be used throughout the diffing of two
@@ -1835,7 +1987,7 @@ protected:
 public:
 
   diff_node_visitor()
-    : visiting_kind_(PRE_VISITING_KIND)
+    : visiting_kind_()
   {}
 
   /// Getter for the visiting policy of the traversing code while
index aefd762ff7d828137fc937bfaf214e3f5f22a553..e8953691a14cbd9e2d5939160b1e79a8ccc8c41c 100644 (file)
@@ -167,6 +167,9 @@ is_at_template_scope(const shared_ptr<decl_base>);
 bool
 is_template_parameter(const shared_ptr<decl_base>);
 
+shared_ptr<function_decl>
+is_function_decl(shared_ptr<decl_base>);
+
 bool
 is_type(const decl_base&);
 
index f540fb076b702c608183f1f0f8a516398f913103..30970d0cdee7a222636b6bd7fe166d4adae8006b 100644 (file)
@@ -1990,6 +1990,9 @@ public:
   parameters&
   get_parameters();
 
+  const parameter_sptr
+  get_parm_at_index_from_first_non_implicit_parm(size_t) const;
+
   void
   set_parameters(const parameters &p);
 
index 655db2871deaccd92fdb03fe10732d736bfcac84..324d86b7a8cd1a54bd0645cd489103169a0918b2 100644 (file)
@@ -46,7 +46,6 @@ using std::tr1::dynamic_pointer_cast;
 void
 apply_filter(filter_base& filter, corpus_diff_sptr d)
 {
-  filter.set_visiting_kind(PRE_VISITING_KIND | POST_VISITING_KIND);
   bool s = d->context()->traversing_a_node_twice_is_forbidden();
   d->context()->forbid_traversing_a_node_twice(false);
   d->traverse(filter);
@@ -63,7 +62,6 @@ apply_filter(filter_base& filter, corpus_diff_sptr d)
 void
 apply_filter(filter_base& filter, diff_sptr d)
 {
-  filter.set_visiting_kind(PRE_VISITING_KIND | POST_VISITING_KIND);
   bool s = d->context()->traversing_a_node_twice_is_forbidden();
   d->context()->forbid_traversing_a_node_twice(false);
   d->traverse(filter);
index 85d2bc13fee67f7ec81cd6242a36d9a8e9dc9cd9..cfdf0c2bb616bee86720f1f9ca426c1960dfd835 100644 (file)
@@ -25,6 +25,7 @@
 /// This contains the implementation of the comparison engine of
 /// libabigail.
 
+#include <ctype.h>
 #include <algorithm>
 #include <sstream>
 #include "abg-hash.h"
@@ -78,6 +79,17 @@ operator|(visiting_kind l, visiting_kind r)
 {return static_cast<visiting_kind>(static_cast<unsigned>(l)
                                   | static_cast<unsigned>(r));}
 
+visiting_kind
+operator&(visiting_kind l, visiting_kind r)
+{
+  return static_cast<visiting_kind>(static_cast<unsigned>(l)
+                                   & static_cast<unsigned>(r));
+}
+
+visiting_kind
+operator~(visiting_kind l)
+{return static_cast<visiting_kind>(~static_cast<unsigned>(l));}
+
 /// This is a subroutine of a *::report() function.
 ///
 /// If the diff about two subjects S1 and S2 was reported earlier or
@@ -211,6 +223,65 @@ suppression_base::set_label(const string& label)
 
 suppression_base::~suppression_base()
 {}
+
+static type_suppression_sptr
+read_type_suppression(const ini::config::section& section);
+
+static function_suppression_sptr
+read_function_suppression(const ini::config::section& section);
+
+/// Read a vector of suppression specifications from the sections of
+/// an ini::config.
+///
+/// Note that each time a new kind of suppression specification is
+/// added, this function needs to be updated.
+///
+/// @param config the config to read from.
+///
+/// @param suppressions out parameter.  The vector of suppressions to
+/// append the newly read suppressions to.
+static void
+read_suppressions(const ini::config& config,
+                 suppressions_type& suppressions)
+{
+  suppression_sptr s;
+  for (ini::config::sections_type::const_iterator i =
+        config.get_sections().begin();
+       i != config.get_sections().end();
+       ++i)
+    if ((s = read_type_suppression(**i))
+       || (s = read_function_suppression(**i)))
+      suppressions.push_back(s);
+
+}
+
+/// Read suppressions specifications from an input stream.
+///
+/// @param input the input stream to read from.
+///
+/// @param suppressions the vector of suppressions to append the newly
+/// read suppressions to.
+void
+read_suppressions(std::istream& input,
+                 suppressions_type& suppressions)
+{
+    if (ini::config_sptr config = ini::read_config(input))
+    read_suppressions(*config, suppressions);
+}
+
+/// Read suppressions specifications from an input file on disk.
+///
+/// @param input the path to the input file to read from.
+///
+/// @param suppressions the vector of suppressions to append the newly
+/// read suppressions to.
+void
+read_suppressions(const string& file_path,
+                 suppressions_type& suppressions)
+{
+  if (ini::config_sptr config = ini::read_config(file_path))
+    read_suppressions(*config, suppressions);
+}
 // </suppression_base stuff>
 
 // <type_suppression stuff>
@@ -572,25 +643,6 @@ read_type_suppressions(const ini::config& config,
       suppressions.push_back(s);
 }
 
-/// Read a vector of suppression specifications from the sections of
-/// an ini::config.
-///
-/// @param config the config to read from.
-///
-/// @param suppressions out parameter.  The vector of suppressions to
-/// append the newly read suppressions to.
-static void
-read_suppressions(const ini::config& config,
-                 suppressions_type& suppressions)
-{
-  for (ini::config::sections_type::const_iterator i =
-        config.get_sections().begin();
-       i != config.get_sections().end();
-       ++i)
-    if (suppression_sptr s = read_type_suppression(**i))
-      suppressions.push_back(s);
-}
-
 /// Read type suppressions specifications from an input stream.
 ///
 /// @param input the input stream to read from.
@@ -605,34 +657,924 @@ read_type_suppressions(std::istream& input,
     read_type_suppressions(*config, suppressions);
 }
 
-/// Read suppressions specifications from an input stream.
+// <function_suppression stuff>
+class function_suppression::parameter_spec::priv
+{
+  friend class function_suppression::parameter_spec;
+  friend class function_suppression;
+
+  size_t                               index_;
+  string                               type_name_;
+  string                               type_name_regex_str_;
+  mutable sptr_utils::regex_t_sptr     type_name_regex_;
+
+  priv()
+    : index_()
+  {}
+
+  priv(size_t i, const string& tn)
+    : index_(i), type_name_(tn)
+  {}
+
+  priv(size_t i, const string& tn, const string& tn_regex)
+    : index_(i), type_name_(tn), type_name_regex_str_(tn_regex)
+  {}
+
+  const sptr_utils::regex_t_sptr
+  get_type_name_regex() const
+  {
+    if (!type_name_regex_ && !type_name_regex_str_.empty())
+      {
+       sptr_utils::regex_t_sptr r(new regex_t);
+       if (regcomp(r.get(),
+                   type_name_regex_str_.c_str(),
+                   REG_EXTENDED) == 0)
+         type_name_regex_ = r;
+      }
+    return type_name_regex_;
+  }
+}; // end class function_suppression::parameter_spec::priv
+
+/// Constructor for the @ref the function_suppression::parameter_spec
+/// type.
 ///
-/// @param input the input stream to read from.
+/// @param i the index of the parameter designated by this specification.
 ///
-/// @param suppressions the vector of suppressions to append the newly
-/// read suppressions to.
+/// @param tn the type name of the parameter designated by this specification.
+///
+/// @param tn_regex a regular expression that defines a set of type
+/// names for the parameter designated by this specification.  Note
+/// that at evaluation time, this regular expression is taken in
+/// account only if the parameter @p tn is empty.
+function_suppression::parameter_spec::parameter_spec(size_t i,
+                                                    const string& tn,
+                                                    const string& tn_regex)
+  : priv_(new priv(i, tn, tn_regex))
+{}
+
+/// Getter for the index of the parameter designated by this
+/// specification.
+///
+/// @return the index of the parameter designated by this
+/// specification.
+size_t
+function_suppression::parameter_spec::get_index() const
+{return priv_->index_;}
+
+/// Setter for the index of the parameter designated by this
+/// specification.
+///
+/// @param i the new index to set.
 void
-read_suppressions(std::istream& input,
-                 suppressions_type& suppressions)
+function_suppression::parameter_spec::set_index(size_t i)
+{priv_->index_ = i;}
+
+/// Getter for the type name of the parameter designated by this specification.
+///
+/// @return the type name of the parameter.
+const string&
+function_suppression::parameter_spec::get_parameter_type_name() const
+{return priv_->type_name_;}
+
+/// Setter for the type name of the parameter designated by this
+/// specification.
+///
+/// @param tn new parameter type name to set.
+void
+function_suppression::parameter_spec::set_parameter_type_name(const string& tn)
+{priv_->type_name_ = tn;}
+
+/// Getter for the regular expression that defines a set of type names
+/// for the parameter designated by this specification.
+///
+/// Note that at evaluation time, this regular expression is taken in
+/// account only if the name of the parameter as returned by
+/// function_suppression::parameter_spec::get_parameter_type_name() is
+/// empty.
+///
+/// @return the regular expression or the parameter type name.
+const string&
+function_suppression::parameter_spec::get_parameter_type_name_regex_str() const
+{return priv_->type_name_regex_str_;}
+
+/// Setter for the regular expression that defines a set of type names
+/// for the parameter designated by this specification.
+///
+/// Note that at evaluation time, this regular expression is taken in
+/// account only if the name of the parameter as returned by
+/// function_suppression::parameter_spec::get_parameter_type_name() is
+/// empty.
+///
+/// @param type_name_regex_str the new type name regular expression to
+/// set.
+void
+function_suppression::parameter_spec::set_parameter_type_name_regex_str
+(const string& type_name_regex_str)
+{priv_->type_name_regex_str_ = type_name_regex_str;}
+
+/// The type of the private data of the @ref function_suppression
+/// type.
+class function_suppression::priv
+{
+  friend function_suppression;
+
+  string                               name_;
+  string                               name_regex_str_;
+  mutable sptr_utils::regex_t_sptr     name_regex_;
+  string                               return_type_name_;
+  string                               return_type_regex_str_;
+  mutable sptr_utils::regex_t_sptr     return_type_regex_;
+  parameter_specs_type                 parm_specs_;
+  string                               symbol_name_;
+  string                               symbol_name_regex_str_;
+  mutable sptr_utils::regex_t_sptr     symbol_name_regex_;
+  string                               symbol_version_;
+  string                               symbol_version_regex_str_;
+  mutable sptr_utils::regex_t_sptr     symbol_version_regex_;
+
+  priv(const string&                   name,
+       const string&                   name_regex_str,
+       const string&                   return_type_name,
+       const string&                   return_type_regex_str,
+       const parameter_specs_type&     parm_specs,
+       const string&                   symbol_name,
+       const string&                   symbol_name_regex_str,
+       const string&                   symbol_version,
+       const string&                   symbol_version_regex_str)
+    : name_(name),
+      name_regex_str_(name_regex_str),
+      return_type_name_(return_type_name),
+      return_type_regex_str_(return_type_regex_str),
+      parm_specs_(parm_specs),
+      symbol_name_(symbol_name),
+      symbol_name_regex_str_(symbol_name_regex_str),
+      symbol_version_(symbol_version),
+      symbol_version_regex_str_(symbol_version_regex_str)
+  {}
+
+
+  /// Getter for a pointer to a regular expression object built from
+  /// the regular expression string
+  /// function_suppression::priv::name_regex_str_.
+  ///
+  /// If that string is empty, then an empty regular expression object
+  /// pointer is returned.
+  ///
+  /// @return a pointer to the regular expression object of
+  /// function_suppression::priv::name_regex_str_..
+  const sptr_utils::regex_t_sptr
+  get_name_regex() const
+  {
+    if (!name_regex_ && !name_regex_str_.empty())
+      {
+       sptr_utils::regex_t_sptr r(new regex_t);
+       if (regcomp(r.get(),
+                   name_regex_str_.c_str(),
+                   REG_EXTENDED) == 0)
+         name_regex_ = r;
+      }
+    return name_regex_;
+  }
+
+  /// Getter for a pointer to a regular expression object built from
+  /// the regular expression string
+  /// function_suppression::priv::return_type_regex_str_.
+  ///
+  /// If that string is empty, then an empty regular expression object
+  /// pointer is returned.
+  ///
+  /// @return a pointer to the regular expression object of
+  /// function_suppression::priv::return_type_regex_str_.
+  const sptr_utils::regex_t_sptr
+  get_return_type_regex() const
+  {
+    if (!return_type_regex_ && !return_type_regex_str_.empty())
+      {
+       sptr_utils::regex_t_sptr r(new regex_t);
+       if (regcomp(r.get(),
+                   return_type_regex_str_.c_str(),
+                   REG_EXTENDED) == 0)
+         return_type_regex_ = r;
+      }
+    return return_type_regex_;
+  }
+
+  /// Getter for a pointer to a regular expression object built from
+  /// the regular expression string
+  /// function_suppression::priv::symbol_name_regex_str_.
+  ///
+  /// If that string is empty, then an empty regular expression object
+  /// pointer is returned.
+  ///
+  /// @return a pointer to the regular expression object of
+  /// function_suppression::priv::symbol_name_regex_str_.
+  const sptr_utils::regex_t_sptr
+  get_symbol_name_regex() const
+  {
+    if (!symbol_name_regex_ && !symbol_name_regex_str_.empty())
+      {
+       sptr_utils::regex_t_sptr r(new regex_t);
+       if (regcomp(r.get(),
+                   symbol_name_regex_str_.c_str(),
+                   REG_EXTENDED) == 0)
+         symbol_name_regex_ = r;
+      }
+    return symbol_name_regex_;
+  }
+
+  /// Getter for a pointer to a regular expression object built from
+  /// the regular expression string
+  /// function_suppression::priv::symbol_version_regex_str_.
+  ///
+  /// If that string is empty, then an empty regular expression object
+  /// pointer is returned.
+  ///
+  /// @return a pointer to the regular expression object of
+  /// function_suppression::priv::symbol_version_regex_str_.
+  const sptr_utils::regex_t_sptr
+  get_symbol_version_regex() const
+  {
+    if (!symbol_version_regex_ && ! symbol_version_regex_str_.empty())
+      {
+       sptr_utils::regex_t_sptr r(new regex_t);
+       if (regcomp(r.get(),
+                   symbol_version_regex_str_.c_str(),
+                   REG_EXTENDED) == 0)
+         symbol_version_regex_ = r;
+      }
+    return symbol_version_regex_;
+  }
+}; // end class function_suppression::priv
+
+/// Constructor for the @ref function_suppression type.
+///
+/// @param label an informative text string that the evalution code
+/// might use to designate this function suppression specification in
+/// error messages.  This parameter might be empty, in which case it's
+/// ignored at evaluation time.
+///
+/// @param the name of the function the user wants the current
+/// specification to designate.  This parameter might be empty, in
+/// which case it's ignored at evaluation time.
+///
+/// @param nr if @p name is empty this parameter is a regular
+/// expression for a family of names of functions the user wants the
+/// current specification to designate.  If @p name is not empty, this
+/// parameter is ignored at specification evaluation time.  This
+/// parameter might be empty, in which case it's ignored at evaluation
+/// time.
+///
+/// @param ret_tn the name of the return type of the function the user
+/// wants this specification to designate.  This parameter might be
+/// empty, in which case it's ignored at evaluation time.
+///
+/// @param ret_tr if @p ret_tn is empty, then this is a regular
+/// expression for a family of return type names for functions the
+/// user wants the current specification to designate.  If @p ret_tn
+/// is not empty, then this parameter is ignored at specification
+/// evaluation time.  This parameter might be empty, in which case
+/// it's ignored at evaluation time.
+///
+/// @param ps a vector of parameter specifications to specify
+/// properties of the parameters of the functions the user wants this
+/// specification to designate.  This parameter might be empty, in
+/// which case it's ignored at evaluation time.
+///
+/// @param sym_n the name of symbol of the function the user wants
+/// this specification to designate.  This parameter might be empty,
+/// in which case it's ignored at evaluation time.
+///
+/// @param sym_nr if the parameter @p sym_n is empty, then this
+/// parameter is a regular expression for a family of names of symbols
+/// of functions the user wants this specification to designate.  If
+/// the parameter @p sym_n is not empty, then this parameter is
+/// ignored at specification evaluation time.  This parameter might be
+/// empty, in which case it's ignored at evaluation time.
+///
+/// @param sym_v the name of the version of the symbol of the function
+/// the user wants this specification to designate.  This parameter
+/// might be empty, in which case it's ignored at evaluation time.
+///
+/// @param sym_vr if the parameter @p sym_v is empty, then this
+/// parameter is a regular expression for a family of versions of
+/// symbols of functions the user wants the current specification to
+/// designate.  If the parameter @p sym_v is non empty, then this
+/// parameter is ignored.  This parameter might be empty, in which
+/// case it's ignored at evaluation time.
+function_suppression::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)
+  : suppression_base(label),
+    priv_(new priv(name, nr, ret_tn, ret_tr, ps,
+                  sym_n, sym_nr, sym_v, sym_vr))
+{}
+
+function_suppression::~function_suppression()
+{}
+
+/// Getter for the name of the function the user wants the current
+/// specification to designate.  This might be empty, in which case
+/// it's ignored at evaluation time.
+///
+/// @return the name of the function.
+const string&
+function_suppression::get_function_name() const
+{return priv_->name_;}
+
+/// Setter for the name of the function the user wants the current
+/// specification to designate.  This might be empty, in which case
+/// it's ignored at evaluation time.
+///
+/// @param n the new function name to set.
+void
+function_suppression::set_function_name(const string& n)
+{priv_->name_ = n;}
+
+/// Getter for a regular expression for a family of names of functions
+/// the user wants the current specification to designate.
+///
+/// If the function name as returned by
+/// function_suppression::get_function_name() is not empty, this
+/// property is ignored at specification evaluation time.  This
+/// property might be empty, in which case it's ignored at evaluation
+/// time.
+///
+/// @return the regular expression for the possible names of the
+/// function(s).
+const string&
+function_suppression::get_function_name_regex_str() const
+{return priv_->name_regex_str_;}
+
+/// Setter for a regular expression for a family of names of functions
+/// the user wants the current specification to designate.
+///
+/// If the function name as returned by
+/// function_suppression::get_function_name() is not empty, this
+/// property is ignored at specification evaluation time.  This
+/// property might be empty, in which case it's ignored at evaluation
+/// time.
+///
+/// @param r the new the regular expression for the possible names of
+/// the function(s).
+void
+function_suppression::set_function_name_regex_str(const string& r)
+{priv_->name_regex_str_ = r;}
+
+/// Getter for the name of the return type of the function the user
+/// wants this specification to designate.  This property might be
+/// empty, in which case it's ignored at evaluation time.
+///
+/// @return the name of the return type of the function.
+const string&
+function_suppression::get_return_type_name() const
+{return priv_->return_type_name_;}
+
+/// Setter for the name of the return type of the function the user
+/// wants this specification to designate.  This property might be
+/// empty, in which case it's ignored at evaluation time.
+///
+/// @param tr the new name of the return type of the function to set.
+void
+function_suppression::set_return_type_name(const string& tr)
+{priv_->return_type_name_ = tr;}
+
+/// Getter for a regular expression for a family of return type names
+/// for functions the user wants the current specification to
+/// designate.
+///
+/// If the name of the return type of the function as returned by
+/// function_suppression::get_return_type_name() is not empty, then
+/// this property is ignored at specification evaluation time.  This
+/// property might be empty, in which case it's ignored at evaluation
+/// time.
+///
+/// @return the regular expression for the possible names of the
+/// return types of the function(s).
+const string&
+function_suppression::get_return_type_regex_str() const
+{return priv_->return_type_regex_str_;}
+
+/// Setter for a regular expression for a family of return type names
+/// for functions the user wants the current specification to
+/// designate.
+///
+/// If the name of the return type of the function as returned by
+/// function_suppression::get_return_type_name() is not empty, then
+/// this property is ignored at specification evaluation time.  This
+/// property might be empty, in which case it's ignored at evaluation
+/// time.
+///
+/// @param r the new regular expression for the possible names of the
+/// return types of the function(s) to set.
+void
+function_suppression::set_return_type_regex_str(const string& r)
+{priv_->return_type_regex_str_ = r;}
+
+/// Getter for a vector of parameter specifications to specify
+/// properties of the parameters of the functions the user wants this
+/// specification to designate.
+///
+/// This property might be empty, in which case it's ignored at
+/// evaluation time.
+///
+/// @return the specifications of the parameters of the function(s).
+const function_suppression::parameter_specs_type&
+function_suppression::get_parameter_specs() const
+{return priv_->parm_specs_;}
+
+/// Setter for a vector of parameter specifications to specify
+/// properties of the parameters of the functions the user wants this
+/// specification to designate.
+///
+/// This property might be empty, in which case it's ignored at
+/// evaluation time.
+///
+/// @param p the new specifications of the parameters of the
+/// function(s) to set.
+void
+function_suppression::set_parameter_specs(parameter_specs_type& p)
+{priv_->parm_specs_ = p;}
+
+/// Append a specification of a parameter of the function specification.
+///
+/// @param p the parameter specification to add.
+void
+function_suppression::append_parameter_specs(const parameter_spec_sptr p)
+{priv_->parm_specs_.push_back(p);}
+
+/// Getter for the name of symbol of the function the user wants this
+/// specification to designate.
+///
+/// This property might be empty, in which case it's ignored at
+/// evaluation time.
+///
+/// @return name of the symbol of the function.
+const string&
+function_suppression::get_symbol_name() const
+{return priv_->symbol_name_;}
+
+/// Setter for the name of symbol of the function the user wants this
+/// specification to designate.
+///
+/// This property might be empty, in which case it's ignored at
+/// evaluation time.
+///
+/// @return name of the symbol of the function.
+void
+function_suppression::set_symbol_name(const string& n)
+{priv_->symbol_name_ = n;}
+
+/// Getter for a regular expression for a family of names of symbols
+/// of functions the user wants this specification to designate.
+///
+/// If the symbol name as returned by
+/// function_suppression::get_symbol_name() is not empty, then this
+/// property is ignored at specification evaluation time.
+///
+/// This property might be empty, in which case it's ignored at
+/// evaluation time.
+///
+/// @return the regular expression for a family of names of symbols of
+/// functions to designate.
+const string&
+function_suppression::get_symbol_name_regex_str() const
+{return priv_->symbol_name_regex_str_;}
+
+/// Setter for a regular expression for a family of names of symbols
+/// of functions the user wants this specification to designate.
+///
+/// If the symbol name as returned by
+/// function_suppression::get_symbol_name() is not empty, then this
+/// property is ignored at specification evaluation time.
+///
+/// This property might be empty, in which case it's ignored at
+/// evaluation time.
+///
+/// @param r the new regular expression for a family of names of
+/// symbols of functions to set.
+void
+function_suppression::set_symbol_name_regex_str(const string& r)
+{priv_->symbol_name_regex_str_ = r;}
+
+/// Getter for the name of the version of the symbol of the function
+/// the user wants this specification to designate.
+///
+/// This property might be empty, in which case it's ignored at
+/// evaluation time.
+///
+/// @return the symbol version of the function.
+const string&
+function_suppression::get_symbol_version() const
+{return priv_->symbol_version_;}
+
+/// Setter for the name of the version of the symbol of the function
+/// the user wants this specification to designate.
+///
+/// This property might be empty, in which case it's ignored at
+/// evaluation time.
+///
+/// @param v the new symbol version of the function.
+void
+function_suppression::set_symbol_version(const string& v)
+{priv_->symbol_version_ = v;}
+
+/// Getter for a regular expression for a family of versions of
+/// symbols of functions the user wants the current specification to
+/// designate.
+///
+/// If the symbol version as returned by
+/// function_suppression::get_symbol_version() is non empty, then this
+/// property is ignored.  This property might be empty, in which case
+/// it's ignored at evaluation time.
+///
+/// @return the regular expression for the versions of symbols of
+/// functions to designate.
+const string&
+function_suppression::get_symbol_version_regex_str() const
+{return priv_->symbol_version_regex_str_;}
+
+/// Setter for a regular expression for a family of versions of
+/// symbols of functions the user wants the current specification to
+/// designate.
+///
+/// If the symbol version as returned by
+/// function_suppression::get_symbol_version() is non empty, then this
+/// property is ignored.  This property might be empty, in which case
+/// it's ignored at evaluation time.
+///
+/// @param the new regular expression for the versions of symbols of
+/// functions to designate.
+void
+function_suppression::set_symbol_version_regex_str(const string& r)
+{priv_->symbol_version_regex_str_ = r;}
+
+/// Evaluate this suppression specification on a given diff node and
+/// say if the diff node should be suppressed or not.
+///
+/// @param diff the diff node to evaluate this suppression
+/// specification against.
+///
+/// @return true if @p diff should be suppressed.
+bool
+function_suppression::suppresses_diff(const diff* diff) const
 {
-    if (ini::config_sptr config = ini::read_config(input))
-    read_suppressions(*config, suppressions);
+  const function_decl_diff* d = dynamic_cast<const function_decl_diff*>(diff);
+  if (!d)
+    return false;
+
+  function_decl_sptr ff = is_function_decl(d->first_function_decl()),
+    sf = is_function_decl(d->second_function_decl());
+  assert(ff && sf);
+
+  string ff_name = ff->get_qualified_name(), sf_name = sf->get_qualified_name();
+
+  // Check if the "name" property matches.
+  if (!get_function_name().empty())
+    {
+      string n = get_function_name();
+      if (n != ff->get_qualified_name()
+         && n != sf->get_qualified_name())
+       return false;
+    }
+
+  // Check if the "name_regexp" property matches.
+  const sptr_utils::regex_t_sptr name_regex = priv_->get_name_regex();
+  if (name_regex
+      && (regexec(name_regex.get(), ff_name.c_str(), 0, NULL, 0) != 0
+         && regexec(name_regex.get(), sf_name.c_str(), 0, NULL, 0) != 0))
+    return false;
+
+  // Check if the "return_type_name" or "return_type_regexp"
+  // properties matches.
+
+    string ff_return_type_name = ff->get_type()->get_return_type()
+      ? (get_type_declaration(ff->get_type()->get_return_type())
+        ->get_qualified_name())
+      : "";
+  string sf_return_type_name = sf->get_type()->get_return_type()
+    ? (get_type_declaration(sf->get_type()->get_return_type())
+       ->get_qualified_name())
+    : "";
+
+  if (!get_return_type_name().empty())
+    {
+      if (ff_return_type_name != get_return_type_name()
+         && sf_return_type_name != get_return_type_name())
+       return false;
+    }
+  else
+    {
+      const sptr_utils::regex_t_sptr return_type_regex =
+       priv_->get_return_type_regex();
+      if (return_type_regex
+         && (regexec(return_type_regex.get(),
+                     ff_return_type_name.c_str(),
+                     0, NULL, 0) != 0
+             && regexec(return_type_regex.get(),
+                        sf_return_type_name.c_str(),
+                        0, NULL, 0) != 0))
+       return false;
+    }
+
+  // Check if the "symbol_name" and "symbol_name_regexp" properties
+  // match.
+
+  string ff_sym_name, ff_sym_version, sf_sym_name, sf_sym_version;
+  if (ff->get_symbol())
+    {
+      ff_sym_name = ff->get_symbol()->get_name();
+      ff_sym_version = ff->get_symbol()->get_version().str();
+    }
+  if (sf->get_symbol())
+    {
+      sf_sym_name = sf->get_symbol()->get_name();
+      sf_sym_version = sf->get_symbol()->get_version().str();
+    }
+
+  if (!get_symbol_name().empty())
+    {
+      if (ff_sym_name != get_symbol_name()
+         && sf_sym_name != get_symbol_name())
+       return false;
+    }
+  else
+    {
+      const sptr_utils::regex_t_sptr symbol_name_regex =
+       priv_->get_symbol_name_regex();
+      if (symbol_name_regex
+         && (regexec(symbol_name_regex.get(),
+                     ff_sym_name.c_str(),
+                     0, NULL, 0) != 0
+             && regexec(symbol_name_regex.get(),
+                        sf_sym_name.c_str(),
+                        0, NULL, 0) != 0))
+       return false;
+    }
+
+// Check if the "symbol_version" and "symbol_version_regexp"
+// properties match.
+  if (!get_symbol_version().empty())
+    {
+      if (ff_sym_version != get_symbol_version()
+         && sf_sym_name != get_symbol_version())
+       return false;
+    }
+  else
+    {
+      const sptr_utils::regex_t_sptr symbol_version_regex =
+       priv_->get_symbol_version_regex();
+      if (symbol_version_regex
+         && (regexec(symbol_version_regex.get(),
+                     ff_sym_version.c_str(),
+                     0, NULL, 0) != 0
+             && regexec(symbol_version_regex.get(),
+                        sf_sym_version.c_str(),
+                        0, NULL, 0) != 0))
+       return false;
+    }
+
+  if (!get_parameter_specs().empty())
+    {
+      function_type_sptr ff_type = ff->get_type();
+      function_type_sptr sf_type = sf->get_type();
+      type_base_sptr parm_type;
+
+      for (parameter_specs_type::const_iterator p =
+            get_parameter_specs().begin();
+          p != get_parameter_specs().end();
+          ++p)
+       {
+         size_t index = (*p)->get_index();
+         function_decl::parameter_sptr ff_parm =
+           ff_type->get_parm_at_index_from_first_non_implicit_parm(index);
+         function_decl::parameter_sptr sf_parm =
+           sf_type->get_parm_at_index_from_first_non_implicit_parm(index);
+         if (!ff_parm && ! sf_parm)
+           return false;
+
+         string ff_parm_type_qualified_name, sf_parm_type_qualified_name;
+         if (ff_parm)
+           {
+             parm_type = ff_parm->get_type();
+             ff_parm_type_qualified_name =
+               get_type_declaration(parm_type)->get_qualified_name();
+           }
+
+         if (sf_parm)
+           {
+             parm_type = sf_parm->get_type();
+             sf_parm_type_qualified_name =
+               get_type_declaration(parm_type)->get_qualified_name();
+           }
+
+         const string& tn = (*p)->get_parameter_type_name();
+         if (!tn.empty())
+           {
+             if (tn != ff_parm_type_qualified_name
+                 && tn != sf_parm_type_qualified_name)
+               return false;
+           }
+         else
+           {
+             const sptr_utils::regex_t_sptr parm_type_name_regex =
+               (*p)->priv_->get_type_name_regex();
+             if (parm_type_name_regex)
+               {
+                 if ((regexec(parm_type_name_regex.get(),
+                              ff_parm_type_qualified_name.c_str(),
+                              0, NULL, 0) != 0
+                      && regexec(parm_type_name_regex.get(),
+                                 sf_parm_type_qualified_name.c_str(),
+                                 0, NULL, 0) != 0))
+                   return false;
+               }
+           }
+       }
+    }
+
+  return true;
 }
 
-/// Read suppressions specifications from an input file on disk.
+/// Parse a string containing a parameter spec, build an instance of
+/// function_suppression::parameter_spec from it and return a pointer
+/// to that object.
 ///
-/// @param input the path to the input file to read from.
+/// @return a shared pointer pointer to the newly built instance of
+/// function_suppression::parameter_spec.  If the parameter
+/// specification could not be parsed, return a nil object.
+static function_suppression::parameter_spec_sptr
+read_parameter_spec_from_string(const string& str)
+{
+  string::size_type cur = 0;
+  function_suppression::parameter_spec_sptr result;
+
+  // skip leading white spaces.
+  for (; cur < str.size(); ++cur)
+    if (!isspace(str[cur]))
+      break;
+
+  // look for the parameter index
+  string index_str;
+  if (str[cur] == '\'')
+    {
+      ++cur;
+      for (; cur < str.size(); ++cur)
+       if (!isdigit(str[cur]))
+         break;
+       else
+         index_str += str[cur];
+    }
+
+  // skip white spaces.
+  for (; cur < str.size(); ++cur)
+    if (!isspace(str[cur]))
+      break;
+
+  bool is_regex = false;
+  if (str[cur] == '/')
+    {
+      is_regex = true;
+      ++ cur;
+    }
+
+  // look for the type name (regex)
+  string type_name;
+  for (; cur < str.size(); ++cur)
+    if (!isspace(str[cur]))
+      {
+       if (is_regex && str[cur] == '/')
+         break;
+       type_name += str[cur];
+      }
+
+  if (is_regex && str[cur] == '/')
+    ++cur;
+
+  if (!index_str.empty() || !type_name.empty())
+    {
+      function_suppression::parameter_spec* p;
+      if (is_regex)
+       p = new function_suppression::parameter_spec(atoi(index_str.c_str()),
+                                                    "", type_name);
+      else
+       p = new function_suppression::parameter_spec(atoi(index_str.c_str()),
+                                                    type_name, "");
+      result.reset(p);
+    }
+
+  return result;
+}
+
+/// Parse function suppression specification, build a resulting @ref
+/// function_suppression type and return a shared pointer to that
+/// object.
 ///
-/// @param suppressions the vector of suppressions to append the newly
-/// read suppressions to.
-void
-read_suppressions(const string& file_path,
-                 suppressions_type& suppressions)
+/// @return a shared pointer to the newly built @ref
+/// function_suppression.  If the function suppression specification
+/// could not be parsed then a nil shared pointer is returned.
+static function_suppression_sptr
+read_function_suppression(const ini::config::section& section)
 {
-  if (ini::config_sptr config = ini::read_config(file_path))
-    read_suppressions(*config, suppressions);
+  function_suppression_sptr nil;
+
+  if (section.get_name() != "suppress_function")
+    return nil;
+
+  ini::config::property_sptr label_prop = section.find_property("label");
+  string label_str = (label_prop && !label_prop->second.empty())
+    ? label_prop->second
+    : "";
+
+  ini::config::property_sptr name_prop = section.find_property("name");
+  string name = name_prop && !name_prop->second.empty()
+    ? name_prop->second
+    : "";
+
+  ini::config::property_sptr name_regex_prop =
+    section.find_property("name_regexp");
+  string name_regex_str = name_regex_prop && !name_regex_prop->second.empty()
+    ? name_regex_prop->second
+    : "";
+
+  ini::config::property_sptr return_type_name_prop =
+    section.find_property("return_type_name");
+  string return_type_name = (return_type_name_prop)
+    ? return_type_name_prop->second
+    : "";
+
+  ini::config::property_sptr return_type_regex_prop =
+    section.find_property("return_type_regexp");
+  string return_type_regex_str =
+    (return_type_regex_prop
+     && !return_type_regex_prop->second.empty())
+    ? return_type_regex_prop->second
+    : "";
+
+  ini::config::property_sptr sym_name_prop =
+    section.find_property("symbol_name");
+  string sym_name = (sym_name_prop) ? sym_name_prop->second : "";
+
+  ini::config::property_sptr sym_name_regex_prop =
+    section.find_property("symbol_name_regexp");
+  string sym_name_regex_str =
+    (sym_name_regex_prop && !sym_name_regex_prop->second.empty())
+    ? sym_name_regex_prop->second
+    : "";
+
+  ini::config::property_sptr sym_ver_prop =
+    section.find_property("symbol_version");
+  string sym_version = (sym_ver_prop) ? sym_ver_prop->second : "";
+
+  ini::config::property_sptr sym_ver_regex_prop =
+    section.find_property("symbol_version_regexp");
+  string sym_ver_regex_str =
+    (sym_ver_regex_prop && !sym_ver_regex_prop->second.empty())
+    ? sym_ver_regex_prop->second
+    : "";
+
+  function_suppression::parameter_spec_sptr parm;
+  function_suppression::parameter_specs_type parms;
+  for (ini::config::property_vector::const_iterator p =
+        section.get_properties().begin();
+       p != section.get_properties().end();
+       ++p)
+    if ((*p)->first == "parameter")
+      if (parm = read_parameter_spec_from_string((*p)->second))
+       parms.push_back(parm);
+
+  function_suppression_sptr result;
+  if (!label_str.empty()
+      || !name.empty()
+      || !name_regex_str.empty()
+      || !return_type_name.empty()
+      || !return_type_regex_str.empty()
+      || !sym_name.empty()
+      || !sym_name_regex_str.empty()
+      || !sym_version.empty()
+      || !sym_ver_regex_str.empty()
+      || !parms.empty())
+    result.reset(new function_suppression(label_str, name,
+                                         name_regex_str,
+                                         return_type_name,
+                                         return_type_regex_str,
+                                         parms,
+                                         sym_name,
+                                         sym_name_regex_str,
+                                         sym_version,
+                                         sym_ver_regex_str));
+
+  return result;
 }
 
+// </function_suppression stuff>
+
 /// The private member (pimpl) for @ref diff_context.
 struct diff_context::priv
 {
@@ -1362,37 +2304,36 @@ diff::traverse(diff_node_visitor& v)
   begin_traversing();
   v.visit_begin(this);
 
-  if (v.get_visiting_kind() & PRE_VISITING_KIND)
-    if (!v.visit(this, /*pre=*/true))
-      {
-       v.visit_end(this);
-       end_traversing();
-       context()->mark_diff_as_traversed(this);
-       return false;
-      }
-
-  for (vector<diff*>::const_iterator i = children_nodes().begin();
-       i != children_nodes().end();
-       ++i)
+  if (!v.visit(this, /*pre=*/true))
     {
-      if (!(*i)->traverse(v))
-       {
-         v.visit_end(this);
-         end_traversing();
-         context()->mark_diff_as_traversed(this);
-         return false;
-       }
+      v.visit_end(this);
+      end_traversing();
+      context()->mark_diff_as_traversed(this);
+      return false;
     }
 
-  if (v.get_visiting_kind() & POST_VISITING_KIND)
-    if (!v.visit(this, /*pref=*/false))
+  if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND))
+    for (vector<diff*>::const_iterator i = children_nodes().begin();
+        i != children_nodes().end();
+        ++i)
       {
-       v.visit_end(this);
-       end_traversing();
-       context()->mark_diff_as_traversed(this);
-       return false;
+       if (!(*i)->traverse(v))
+         {
+           v.visit_end(this);
+           end_traversing();
+           context()->mark_diff_as_traversed(this);
+           return false;
+         }
       }
 
+  if (!v.visit(this, /*pref=*/false))
+    {
+      v.visit_end(this);
+      end_traversing();
+      context()->mark_diff_as_traversed(this);
+      return false;
+    }
+
   v.visit_end(this);
   end_traversing();
   context()->mark_diff_as_traversed(this);
@@ -9503,14 +10444,28 @@ print_diff_tree(corpus_diff_sptr diff_tree,
 /// appropriate.
 struct redundancy_marking_visitor : public diff_node_visitor
 {
+  bool skip_children_nodes_;
+
+  redundancy_marking_visitor()
+    : skip_children_nodes_()
+  {}
+
   virtual void
   visit_begin(diff* d)
   {
-    // A diff node that carries a change and that has been already
-    // traversed elsewhere is considered redundant.
-     if (d->context()->diff_has_been_traversed(d)
-        && d->length())
-      d->add_to_category(REDUNDANT_CATEGORY);
+    if (d->to_be_reported())
+      {
+       // A diff node that carries a change and that has been already
+       // been traversed elsewhere is considered redundant.
+       if (d->context()->diff_has_been_traversed(d) && d->length())
+         d->add_to_category(REDUNDANT_CATEGORY);
+      }
+    else
+      {
+       // If the node is not be reported, do not look at it children.
+       set_visiting_kind(get_visiting_kind() | SKIP_CHILDREN_VISITING_KIND);
+       skip_children_nodes_ = true;
+      }
   }
 
   virtual void
@@ -9521,34 +10476,46 @@ struct redundancy_marking_visitor : public diff_node_visitor
   virtual void
   visit_end(diff* d)
   {
-    // Propagate the redundancy categorization of the children nodes
-    // to this node.  But if this node has local changes, then it
-    // doesn't inherit redundancy from its children nodes.
-    if (!(d->get_category() & REDUNDANT_CATEGORY)
-       && !d->has_local_changes())
+    if (skip_children_nodes_)
+      // When visiting this node, we decided to skip its children
+      // node.  Now that we are done visiting the node, lets stop
+      // avoiding the children nodes visiting for the other tree
+      // nodes.
       {
-       bool has_non_redundant_child = false;
-       bool has_non_empty_child = false;
-       for (vector<diff*>::const_iterator i = d->children_nodes().begin();
-            i != d->children_nodes().end();
-            ++i)
+       set_visiting_kind(get_visiting_kind() & (~SKIP_CHILDREN_VISITING_KIND));
+       skip_children_nodes_ = false;
+      }
+    else
+      {
+       // Propagate the redundancy categorization of the children nodes
+       // to this node.  But if this node has local changes, then it
+       // doesn't inherit redundancy from its children nodes.
+       if (!(d->get_category() & REDUNDANT_CATEGORY)
+           && !d->has_local_changes())
          {
-           if ((*i)->length())
+           bool has_non_redundant_child = false;
+           bool has_non_empty_child = false;
+           for (vector<diff*>::const_iterator i = d->children_nodes().begin();
+                i != d->children_nodes().end();
+                ++i)
              {
-               has_non_empty_child = true;
-               if (((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
-                 has_non_redundant_child = true;
+               if ((*i)->length())
+                 {
+                   has_non_empty_child = true;
+                   if (((*i)->get_category() & REDUNDANT_CATEGORY) == 0)
+                     has_non_redundant_child = true;
+                 }
+               if (has_non_redundant_child)
+                 break;
              }
-           if (has_non_redundant_child)
-             break;
-         }
 
-       // A diff node for which at least a child node carries a
-       // change, and for which all the children are redundant is
-       // deemed redundant too, unless it has local changes.
-       if (has_non_empty_child
-           && !has_non_redundant_child)
-         d->add_to_category(REDUNDANT_CATEGORY);
+           // A diff node for which at least a child node carries a
+           // change, and for which all the children are redundant is
+           // deemed redundant too, unless it has local changes.
+           if (has_non_empty_child
+               && !has_non_redundant_child)
+             d->add_to_category(REDUNDANT_CATEGORY);
+         }
       }
   }
 
@@ -9559,9 +10526,7 @@ struct redundancy_marking_visitor : public diff_node_visitor
 
   virtual bool
   visit(diff*, bool)
-  {
-    return true;
-  }
+  {return true;}
 
   virtual bool
   visit(corpus_diff*, bool)
index e1b7d0cf10581ab2454aadb074fb62ee9a06c0c6..7a5c559007fee3950e191849207ac9f5fe3d3131 100644 (file)
@@ -2940,6 +2940,16 @@ is_template_parameter(const shared_ptr<decl_base> decl)
                   || dynamic_pointer_cast<template_tparameter>(decl)));
 }
 
+/// Test whether a declaration is a @ref function_decl.
+///
+/// @param d the declaration to test for.
+///
+/// @return a shared pointer to @ref function_decl if @p d is a @ref
+/// function_decl.  Otherwise, a nil shared pointer.
+function_decl_sptr
+is_function_decl(decl_base_sptr d)
+{return dynamic_pointer_cast<function_decl>(d);}
+
 /// Test whether a declaration is a type.
 ///
 /// @param d the declaration to test for.
@@ -5201,6 +5211,39 @@ function_decl::parameters&
 function_type::get_parameters()
 {return priv_->parms_;}
 
+/// Get the Ith parameter of the vector of parameters of the current
+/// instance of @ref function_type.
+///
+/// Note that the first parameter is at index 0.  That parameter is
+/// the first parameter that comes after the possible implicit "this"
+/// parameter, when the current instance @ref function_type is for a
+/// member function.  Otherwise, if the current instance of @ref
+/// function_type is for a non-member function, the parameter at index
+/// 0 is the first parameter of the function.
+///
+///
+/// @param i the index of the parameter to return.  If i is greater
+/// than the index of the last parameter, then this function returns
+/// an empty parameter (smart) pointer.
+///
+/// @return the @p i th parameter that is not implicit.
+const function_decl::parameter_sptr
+function_type::get_parm_at_index_from_first_non_implicit_parm(size_t i) const
+{
+  parameter_sptr result;
+  if (dynamic_cast<const method_type*>(this))
+    {
+      if (i + 1 < get_parameters().size())
+       result = get_parameters()[i + 1];
+    }
+  else
+    {
+      if (i < get_parameters().size())
+       result = get_parameters()[i];
+    }
+  return result;
+}
+
 /// Setter for the parameters of the current instance of @ref
 /// function_type.
 ///
index 58f5859c858e16bf245ed18f9ff620c8e8bc4131..30a4db65f76b868923a3b0a4685a475dfa04f9e3 100644 (file)
@@ -421,6 +421,35 @@ tests/data/test-diff-suppr/test4-local-suppr-v0.c \
 tests/data/test-diff-suppr/test4-local-suppr-v0.h \
 tests/data/test-diff-suppr/test4-local-suppr-v1.c \
 tests/data/test-diff-suppr/test4-local-suppr-v1.h \
+tests/data/test-diff-suppr/libtest5-fn-suppr-v0.so \
+tests/data/test-diff-suppr/libtest5-fn-suppr-v1.so \
+tests/data/test-diff-suppr/test5-fn-suppr-0.suppr \
+tests/data/test-diff-suppr/test5-fn-suppr-1.suppr \
+tests/data/test-diff-suppr/test5-fn-suppr-2.suppr \
+tests/data/test-diff-suppr/test5-fn-suppr-3.suppr \
+tests/data/test-diff-suppr/test5-fn-suppr-4.suppr \
+tests/data/test-diff-suppr/test5-fn-suppr-report-0.txt \
+tests/data/test-diff-suppr/test5-fn-suppr-report-1.txt \
+tests/data/test-diff-suppr/test5-fn-suppr-report-2.txt \
+tests/data/test-diff-suppr/test5-fn-suppr-report-3.txt \
+tests/data/test-diff-suppr/test5-fn-suppr-report-4.txt \
+tests/data/test-diff-suppr/test5-fn-suppr-report-5.txt \
+tests/data/test-diff-suppr/test5-fn-suppr-v0.cc \
+tests/data/test-diff-suppr/test5-fn-suppr-v1.cc \
+tests/data/test-diff-suppr/libtest6-fn-suppr-v0.so \
+tests/data/test-diff-suppr/libtest6-fn-suppr-v1.so \
+tests/data/test-diff-suppr/test6-fn-suppr-0.suppr \
+tests/data/test-diff-suppr/test6-fn-suppr-1.suppr \
+tests/data/test-diff-suppr/test6-fn-suppr-2.suppr \
+tests/data/test-diff-suppr/test6-fn-suppr-3.suppr \
+tests/data/test-diff-suppr/test6-fn-suppr-report-0.txt \
+tests/data/test-diff-suppr/test6-fn-suppr-report-1.txt \
+tests/data/test-diff-suppr/test6-fn-suppr-report-2.txt \
+tests/data/test-diff-suppr/test6-fn-suppr-report-3.txt \
+tests/data/test-diff-suppr/test6-fn-suppr-report-4.txt \
+tests/data/test-diff-suppr/test6-fn-suppr-v0.cc \
+tests/data/test-diff-suppr/test6-fn-suppr-v1.cc \
+tests/data/test-diff-suppr/test6-fn-suppr-version-script \
 \
 data/test-lookup-syms/test0.cc                 \
 data/test-lookup-syms/test0.o                  \
diff --git a/tests/data/test-diff-suppr/libtest5-fn-suppr-v0.so b/tests/data/test-diff-suppr/libtest5-fn-suppr-v0.so
new file mode 100755 (executable)
index 0000000..b281bdd
Binary files /dev/null and b/tests/data/test-diff-suppr/libtest5-fn-suppr-v0.so differ
diff --git a/tests/data/test-diff-suppr/libtest5-fn-suppr-v1.so b/tests/data/test-diff-suppr/libtest5-fn-suppr-v1.so
new file mode 100755 (executable)
index 0000000..4c13cc8
Binary files /dev/null and b/tests/data/test-diff-suppr/libtest5-fn-suppr-v1.so differ
diff --git a/tests/data/test-diff-suppr/libtest6-fn-suppr-v0.so b/tests/data/test-diff-suppr/libtest6-fn-suppr-v0.so
new file mode 100755 (executable)
index 0000000..d7ec579
Binary files /dev/null and b/tests/data/test-diff-suppr/libtest6-fn-suppr-v0.so differ
diff --git a/tests/data/test-diff-suppr/libtest6-fn-suppr-v1.so b/tests/data/test-diff-suppr/libtest6-fn-suppr-v1.so
new file mode 100755 (executable)
index 0000000..e64ef99
Binary files /dev/null and b/tests/data/test-diff-suppr/libtest6-fn-suppr-v1.so differ
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-0.suppr b/tests/data/test-diff-suppr/test5-fn-suppr-0.suppr
new file mode 100644 (file)
index 0000000..4e70869
--- /dev/null
@@ -0,0 +1,9 @@
+[suppress_function]
+
+  # suppress change reports for a function which name is 'bar' ...
+  name = bar
+
+  # ...and which first parameter has a type named 'S*'.
+  # Note that parameters' index start at 0.
+  parameter = '0 S*
+
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-1.suppr b/tests/data/test-diff-suppr/test5-fn-suppr-1.suppr
new file mode 100644 (file)
index 0000000..ad25dbc
--- /dev/null
@@ -0,0 +1,9 @@
+[suppress_function]
+
+  # suppress change reports for a function which name is 'bar' ...
+  name = bar
+
+  # ...and which first parameter has a type named 'S*'.
+  # Note that parameters' index start at 0.
+  parameter = '0 /S(\\*)/
+
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-2.suppr b/tests/data/test-diff-suppr/test5-fn-suppr-2.suppr
new file mode 100644 (file)
index 0000000..43a2b6c
--- /dev/null
@@ -0,0 +1,4 @@
+[suppress_function]
+
+  # suppress change reports for a function which symbol name is _Z3barP1S
+  symbol_name = _Z3barP1S
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-3.suppr b/tests/data/test-diff-suppr/test5-fn-suppr-3.suppr
new file mode 100644 (file)
index 0000000..f257419
--- /dev/null
@@ -0,0 +1,4 @@
+[suppress_function]
+
+  # suppress change reports for a function which symbol name is _Z3bari1S
+  symbol_name = _Z3bari1S
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-4.suppr b/tests/data/test-diff-suppr/test5-fn-suppr-4.suppr
new file mode 100644 (file)
index 0000000..6e90331
--- /dev/null
@@ -0,0 +1,5 @@
+[suppress_function]
+
+  # suppress change reports for a function which symbol name is _Z3barPS
+  # or _Z3barPPS
+  symbol_name_regexp = ^_Z3barP+1S
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-report-0.txt b/tests/data/test-diff-suppr/test5-fn-suppr-report-0.txt
new file mode 100644 (file)
index 0000000..b73d38d
--- /dev/null
@@ -0,0 +1,15 @@
+Functions changes summary: 0 Removed, 1 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C]'function void bar(S*)' has some indirect sub-type changes:
+    parameter 0 of type 'S*' has sub-type changes:
+      in pointed to type 'struct S':
+        size changed from 32 to 64 bits
+        1 data member insertion:
+          'char S::m0', at offset 0 (in bits)
+        1 data member change:
+         'int S::m1' offset changed from 0 to 32
+
+
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-report-1.txt b/tests/data/test-diff-suppr/test5-fn-suppr-report-1.txt
new file mode 100644 (file)
index 0000000..5e3b478
--- /dev/null
@@ -0,0 +1,14 @@
+Functions changes summary: 0 Removed, 1 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C]'function void bar(int, S)' has some indirect sub-type changes:
+    parameter 1 of type 'struct S' has sub-type changes:
+      size changed from 32 to 64 bits
+      1 data member insertion:
+        'char S::m0', at offset 0 (in bits)
+      1 data member change:
+       'int S::m1' offset changed from 0 to 32
+
+
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-report-2.txt b/tests/data/test-diff-suppr/test5-fn-suppr-report-2.txt
new file mode 100644 (file)
index 0000000..5e3b478
--- /dev/null
@@ -0,0 +1,14 @@
+Functions changes summary: 0 Removed, 1 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C]'function void bar(int, S)' has some indirect sub-type changes:
+    parameter 1 of type 'struct S' has sub-type changes:
+      size changed from 32 to 64 bits
+      1 data member insertion:
+        'char S::m0', at offset 0 (in bits)
+      1 data member change:
+       'int S::m1' offset changed from 0 to 32
+
+
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-report-3.txt b/tests/data/test-diff-suppr/test5-fn-suppr-report-3.txt
new file mode 100644 (file)
index 0000000..5e3b478
--- /dev/null
@@ -0,0 +1,14 @@
+Functions changes summary: 0 Removed, 1 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C]'function void bar(int, S)' has some indirect sub-type changes:
+    parameter 1 of type 'struct S' has sub-type changes:
+      size changed from 32 to 64 bits
+      1 data member insertion:
+        'char S::m0', at offset 0 (in bits)
+      1 data member change:
+       'int S::m1' offset changed from 0 to 32
+
+
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-report-4.txt b/tests/data/test-diff-suppr/test5-fn-suppr-report-4.txt
new file mode 100644 (file)
index 0000000..b73d38d
--- /dev/null
@@ -0,0 +1,15 @@
+Functions changes summary: 0 Removed, 1 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C]'function void bar(S*)' has some indirect sub-type changes:
+    parameter 0 of type 'S*' has sub-type changes:
+      in pointed to type 'struct S':
+        size changed from 32 to 64 bits
+        1 data member insertion:
+          'char S::m0', at offset 0 (in bits)
+        1 data member change:
+         'int S::m1' offset changed from 0 to 32
+
+
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-report-5.txt b/tests/data/test-diff-suppr/test5-fn-suppr-report-5.txt
new file mode 100644 (file)
index 0000000..5e3b478
--- /dev/null
@@ -0,0 +1,14 @@
+Functions changes summary: 0 Removed, 1 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C]'function void bar(int, S)' has some indirect sub-type changes:
+    parameter 1 of type 'struct S' has sub-type changes:
+      size changed from 32 to 64 bits
+      1 data member insertion:
+        'char S::m0', at offset 0 (in bits)
+      1 data member change:
+       'int S::m1' offset changed from 0 to 32
+
+
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-v0.cc b/tests/data/test-diff-suppr/test5-fn-suppr-v0.cc
new file mode 100644 (file)
index 0000000..025b72a
--- /dev/null
@@ -0,0 +1,21 @@
+// Compile this with:
+// g++ -Wall -g -shared -o libtest5-fn-suppr-v0.so test5-fn-suppr-v0.cc
+
+struct S
+{
+  int m1;
+
+    S()
+    : m1()
+  {}
+};
+
+void
+bar(S*)
+{
+}
+
+void
+bar(int, S)
+{
+}
diff --git a/tests/data/test-diff-suppr/test5-fn-suppr-v1.cc b/tests/data/test-diff-suppr/test5-fn-suppr-v1.cc
new file mode 100644 (file)
index 0000000..e4aa235
--- /dev/null
@@ -0,0 +1,23 @@
+// Compile this with:
+// g++ -Wall -g -shared -o libtest5-fn-suppr-v1.so test5-fn-suppr-v1.cc
+
+struct S
+{
+  char m0;
+  int m1;
+
+  S()
+    : m0(),
+      m1()
+  {}
+};
+
+void
+bar(S*)
+{
+}
+
+void
+bar(int, S)
+{
+}
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-0.suppr b/tests/data/test-diff-suppr/test6-fn-suppr-0.suppr
new file mode 100644 (file)
index 0000000..f93ba12
--- /dev/null
@@ -0,0 +1,2 @@
+[suppress_function]
+  symbol_version = VERSION_1.0
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-1.suppr b/tests/data/test-diff-suppr/test6-fn-suppr-1.suppr
new file mode 100644 (file)
index 0000000..0bead6d
--- /dev/null
@@ -0,0 +1,2 @@
+[suppress_function]
+  symbol_version_regexp = VERSION_1\.*
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-2.suppr b/tests/data/test-diff-suppr/test6-fn-suppr-2.suppr
new file mode 100644 (file)
index 0000000..948560e
--- /dev/null
@@ -0,0 +1,2 @@
+[suppress_function]
+  return_type_name = int
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-3.suppr b/tests/data/test-diff-suppr/test6-fn-suppr-3.suppr
new file mode 100644 (file)
index 0000000..e5797f5
--- /dev/null
@@ -0,0 +1,2 @@
+[suppress_function]
+  return_type_name = char
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-report-0.txt b/tests/data/test-diff-suppr/test6-fn-suppr-report-0.txt
new file mode 100644 (file)
index 0000000..7137cd9
--- /dev/null
@@ -0,0 +1,34 @@
+Functions changes summary: 0 Removed, 3 Changed, 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+3 functions with some indirect sub-type change:
+
+  [C]'function void bar(S1*)' has some indirect sub-type changes:
+    parameter 0 of type 'S1*' has sub-type changes:
+      in pointed to type 'struct S1':
+        size changed from 32 to 64 bits
+        1 base class insertion:
+          struct base
+        1 data member change:
+         'int S1::m0' offset changed from 0 to 32
+
+  [C]'function int bar(S&)' has some indirect sub-type changes:
+    parameter 0 of type 'S&' has sub-type changes:
+      in referenced type 'struct S':
+        size changed from 32 to 64 bits
+        1 base class insertion:
+          struct base
+        1 data member change:
+         'int S::m0' offset changed from 0 to 32
+
+  [C]'function char bar(int, S2**)' has some indirect sub-type changes:
+    parameter 1 of type 'S2**' has sub-type changes:
+      in pointed to type 'S2*':
+        in pointed to type 'struct S2':
+          size changed from 32 to 64 bits
+          1 base class insertion:
+            struct base
+          1 data member change:
+           'int S2::m0' offset changed from 0 to 32
+
+
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-report-1.txt b/tests/data/test-diff-suppr/test6-fn-suppr-report-1.txt
new file mode 100644 (file)
index 0000000..8c3e262
--- /dev/null
@@ -0,0 +1,25 @@
+Functions changes summary: 0 Removed, 2 Changed (1 filtered out), 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+2 functions with some indirect sub-type change:
+
+  [C]'function void bar(S1*)' has some indirect sub-type changes:
+    parameter 0 of type 'S1*' has sub-type changes:
+      in pointed to type 'struct S1':
+        size changed from 32 to 64 bits
+        1 base class insertion:
+          struct base
+        1 data member change:
+         'int S1::m0' offset changed from 0 to 32
+
+  [C]'function char bar(int, S2**)' has some indirect sub-type changes:
+    parameter 1 of type 'S2**' has sub-type changes:
+      in pointed to type 'S2*':
+        in pointed to type 'struct S2':
+          size changed from 32 to 64 bits
+          1 base class insertion:
+            struct base
+          1 data member change:
+           'int S2::m0' offset changed from 0 to 32
+
+
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-report-2.txt b/tests/data/test-diff-suppr/test6-fn-suppr-report-2.txt
new file mode 100644 (file)
index 0000000..8c3e262
--- /dev/null
@@ -0,0 +1,25 @@
+Functions changes summary: 0 Removed, 2 Changed (1 filtered out), 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+2 functions with some indirect sub-type change:
+
+  [C]'function void bar(S1*)' has some indirect sub-type changes:
+    parameter 0 of type 'S1*' has sub-type changes:
+      in pointed to type 'struct S1':
+        size changed from 32 to 64 bits
+        1 base class insertion:
+          struct base
+        1 data member change:
+         'int S1::m0' offset changed from 0 to 32
+
+  [C]'function char bar(int, S2**)' has some indirect sub-type changes:
+    parameter 1 of type 'S2**' has sub-type changes:
+      in pointed to type 'S2*':
+        in pointed to type 'struct S2':
+          size changed from 32 to 64 bits
+          1 base class insertion:
+            struct base
+          1 data member change:
+           'int S2::m0' offset changed from 0 to 32
+
+
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-report-3.txt b/tests/data/test-diff-suppr/test6-fn-suppr-report-3.txt
new file mode 100644 (file)
index 0000000..8c3e262
--- /dev/null
@@ -0,0 +1,25 @@
+Functions changes summary: 0 Removed, 2 Changed (1 filtered out), 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+2 functions with some indirect sub-type change:
+
+  [C]'function void bar(S1*)' has some indirect sub-type changes:
+    parameter 0 of type 'S1*' has sub-type changes:
+      in pointed to type 'struct S1':
+        size changed from 32 to 64 bits
+        1 base class insertion:
+          struct base
+        1 data member change:
+         'int S1::m0' offset changed from 0 to 32
+
+  [C]'function char bar(int, S2**)' has some indirect sub-type changes:
+    parameter 1 of type 'S2**' has sub-type changes:
+      in pointed to type 'S2*':
+        in pointed to type 'struct S2':
+          size changed from 32 to 64 bits
+          1 base class insertion:
+            struct base
+          1 data member change:
+           'int S2::m0' offset changed from 0 to 32
+
+
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-report-4.txt b/tests/data/test-diff-suppr/test6-fn-suppr-report-4.txt
new file mode 100644 (file)
index 0000000..5f27ff9
--- /dev/null
@@ -0,0 +1,24 @@
+Functions changes summary: 0 Removed, 2 Changed (1 filtered out), 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+2 functions with some indirect sub-type change:
+
+  [C]'function void bar(S1*)' has some indirect sub-type changes:
+    parameter 0 of type 'S1*' has sub-type changes:
+      in pointed to type 'struct S1':
+        size changed from 32 to 64 bits
+        1 base class insertion:
+          struct base
+        1 data member change:
+         'int S1::m0' offset changed from 0 to 32
+
+  [C]'function int bar(S&)' has some indirect sub-type changes:
+    parameter 0 of type 'S&' has sub-type changes:
+      in referenced type 'struct S':
+        size changed from 32 to 64 bits
+        1 base class insertion:
+          struct base
+        1 data member change:
+         'int S::m0' offset changed from 0 to 32
+
+
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-v0.cc b/tests/data/test-diff-suppr/test6-fn-suppr-v0.cc
new file mode 100644 (file)
index 0000000..2165429
--- /dev/null
@@ -0,0 +1,43 @@
+// Compile this with:
+// g++ -Wall -g -shared -Wl,--version-script=test6-fn-suppr-version-script -o libtest6-fn-suppr-v0.so test6-fn-suppr-v0.cc
+
+struct S
+{
+  int m0;
+
+  S()
+    : m0()
+  {}
+};
+
+struct S1
+{
+  int m0;
+
+  S1()
+    : m0()
+  {}
+};
+
+struct S2
+{
+  int m0;
+
+  S2()
+    : m0()
+  {}
+};
+
+int
+bar(S&)
+{return 0;}
+
+asm(".symver _Z3barR1S,_Z3barR1S@VERSION_1.0");
+
+void
+bar(S1*)
+{}
+
+char
+bar(int, S2**)
+{return 0;}
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-v1.cc b/tests/data/test-diff-suppr/test6-fn-suppr-v1.cc
new file mode 100644 (file)
index 0000000..bc07ab2
--- /dev/null
@@ -0,0 +1,53 @@
+// Compile this with:
+// g++ -Wall -g -shared -Wl,--version-script=test6-fn-suppr-version-script -o libtest6-fn-suppr-v1.so test6-fn-suppr-v1.cc
+
+struct base
+{
+  char m0;
+  char m1;
+
+  base()
+    : m0(), m1()
+  {}
+};
+
+struct S : public base
+{
+  int m0;
+
+  S()
+    : m0()
+  {}
+};
+
+struct S1 : private base
+{
+  int m0;
+
+  S1()
+    : m0()
+  {}
+};
+
+struct S2 : private base
+{
+  int m0;
+
+  S2()
+    : m0()
+  {}
+};
+
+int
+bar(S&)
+{return 0;}
+
+asm(".symver _Z3barR1S,_Z3barR1S@VERSION_1.0");
+
+void
+bar(S1*)
+{}
+
+char
+bar(int, S2**)
+{return 0;}
diff --git a/tests/data/test-diff-suppr/test6-fn-suppr-version-script b/tests/data/test-diff-suppr/test6-fn-suppr-version-script
new file mode 100644 (file)
index 0000000..94d9fc4
--- /dev/null
@@ -0,0 +1,3 @@
+VERSION_1.0 {
+  global: .*;
+};
\ No newline at end of file
index 5b8b8af1eb9e32f943d3138adcc5efb58095d29c..43ccc4653b5b307cb5e6f32b7bf0b140ecc11621 100644 (file)
@@ -167,6 +167,86 @@ InOutSpec in_out_specs[] =
     "data/test-diff-suppr/test4-local-suppr-report-0.txt",
     "output/test-diff-suppr/test4-local-suppr-report-0.txt",
   },
+  {
+    "data/test-diff-suppr/libtest5-fn-suppr-v0.so",
+    "data/test-diff-suppr/libtest5-fn-suppr-v1.so",
+    "",
+    "",
+    "data/test-diff-suppr/test5-fn-suppr-report-0.txt",
+    "output/test-diff-suppr/test5-fn-suppr-report-0.txt",
+  },
+  {
+    "data/test-diff-suppr/libtest5-fn-suppr-v0.so",
+    "data/test-diff-suppr/libtest5-fn-suppr-v1.so",
+    "data/test-diff-suppr/test5-fn-suppr-0.suppr",
+    "",
+    "data/test-diff-suppr/test5-fn-suppr-report-1.txt",
+    "output/test-diff-suppr/test5-fn-suppr-report-1.txt",
+  },
+  {
+    "data/test-diff-suppr/libtest5-fn-suppr-v0.so",
+    "data/test-diff-suppr/libtest5-fn-suppr-v1.so",
+    "data/test-diff-suppr/test5-fn-suppr-1.suppr",
+    "",
+    "data/test-diff-suppr/test5-fn-suppr-report-2.txt",
+    "output/test-diff-suppr/test5-fn-suppr-report-2.txt",
+  },
+  {
+    "data/test-diff-suppr/libtest5-fn-suppr-v0.so",
+    "data/test-diff-suppr/libtest5-fn-suppr-v1.so",
+    "data/test-diff-suppr/test5-fn-suppr-2.suppr",
+    "",
+    "data/test-diff-suppr/test5-fn-suppr-report-3.txt",
+    "output/test-diff-suppr/test5-fn-suppr-report-3.txt",
+  },
+  {
+    "data/test-diff-suppr/libtest5-fn-suppr-v0.so",
+    "data/test-diff-suppr/libtest5-fn-suppr-v1.so",
+    "data/test-diff-suppr/test5-fn-suppr-3.suppr",
+    "",
+    "data/test-diff-suppr/test5-fn-suppr-report-4.txt",
+    "output/test-diff-suppr/test5-fn-suppr-report-4.txt",
+  },
+  {
+    "data/test-diff-suppr/libtest5-fn-suppr-v0.so",
+    "data/test-diff-suppr/libtest5-fn-suppr-v1.so",
+    "data/test-diff-suppr/test5-fn-suppr-4.suppr",
+    "",
+    "data/test-diff-suppr/test5-fn-suppr-report-5.txt",
+    "output/test-diff-suppr/test5-fn-suppr-report-5.txt",
+  },
+  {
+    "data/test-diff-suppr/libtest6-fn-suppr-v0.so",
+    "data/test-diff-suppr/libtest6-fn-suppr-v1.so",
+    "",
+    "",
+    "data/test-diff-suppr/test6-fn-suppr-report-0.txt",
+    "output/test-diff-suppr/test6-fn-suppr-report-0.txt",
+  },
+  {
+    "data/test-diff-suppr/libtest6-fn-suppr-v0.so",
+    "data/test-diff-suppr/libtest6-fn-suppr-v1.so",
+    "data/test-diff-suppr/test6-fn-suppr-0.suppr",
+    "",
+    "data/test-diff-suppr/test6-fn-suppr-report-1.txt",
+    "output/test-diff-suppr/test6-fn-suppr-report-1.txt",
+  },
+  {
+    "data/test-diff-suppr/libtest6-fn-suppr-v0.so",
+    "data/test-diff-suppr/libtest6-fn-suppr-v1.so",
+    "data/test-diff-suppr/test6-fn-suppr-1.suppr",
+    "",
+    "data/test-diff-suppr/test6-fn-suppr-report-2.txt",
+    "output/test-diff-suppr/test6-fn-suppr-report-2.txt",
+  },
+  {
+    "data/test-diff-suppr/libtest6-fn-suppr-v0.so",
+    "data/test-diff-suppr/libtest6-fn-suppr-v1.so",
+    "data/test-diff-suppr/test6-fn-suppr-2.suppr",
+    "",
+    "data/test-diff-suppr/test6-fn-suppr-report-3.txt",
+    "output/test-diff-suppr/test6-fn-suppr-report-3.txt",
+  },
   // This should be the last entry
   {NULL, NULL, NULL, NULL, NULL, NULL}
 };
This page took 0.109691 seconds and 5 git commands to generate.