Better detect when diff nodes only carry local type changes
authorDodji Seketeli <dodji@redhat.com>
Wed, 23 May 2018 09:43:29 +0000 (11:43 +0200)
committerDodji Seketeli <dodji@redhat.com>
Thu, 24 May 2018 14:04:44 +0000 (16:04 +0200)
For some fine grain redundancy filtering, we need to know when a diff
node carries *only* a basic type change.  This is because basic type
changes should not be marked as redundant; we want to see all of them
-- unlike for class or union (user defined) type changes.

And so to know if a diff node carries only a basic type change, we
need to know if a diff node only carries a local type change.  If it
carries only a type change, we can safely just look at that type
change and see if it's a basic type change or not.

So, we then need to know what kind of local changes a diff node
carries: type change or non-type change.  That way, we can analyze the
local changes a node carries and infer that it only carries a local
type change or if it also carries a non-type change.

This patch thus changes the diff::has_local_changes() pure virtual member
function to make it return the enum change_kind bitmask, which
describes the different kinds of local changes the diff node has.

Note that two new bit values were added to that enum:
LOCAL_TYPE_CHANGE_KIND and LOCAL_NON_TYPE_CHANGE_KIND.  The first one
says that the diff node carries a local type change, while the second
one says that the diff node carries a local non-type change kind.

The various implementations of that interface are thus amended to make
them return the right bitmask.  To do this, the patch updates the
various 'equals' overloads to make them return the proper enum
change_kind bitmap with the LOCAL_TYPE_CHANGE_KIND and
LOCAL_NON_TYPE_CHANGE_KIND set, if need be.

* include/abg-comparison.h ({diff, type_diff_base, decl_diff_base,
distinct_diff, var_diff, pointer_diff, reference_diff, array_diff,
qualified_type, enum_diff, class_or_union_diff, class_diff,
base_diff, scope_diff, fn_parm_diff, function_type_diff,
function_decl_diff, typedef_diff,
translation_unit_diff}::has_local_changes): Return an enum
change_kind, rather than just a bool.
(is_diff_of_basic_type): Declare an overload that takes a boolean
flag.
(is_qualified_type_diff, peel_pointer_diff, peel_reference_diff)
(peel_qualified_type, peel_pointer_or_qualified_type): Declare new
functions
* include/abg-fwd.h (peel_qualified_type):
* include/abg-ir.h (enum change_kind::{LOCAL_TYPE_CHANGE_KIND,
LOCAL_NON_TYPE_CHANGE_KIND, ALL_LOCAL_CHANGES_MASK}): Add these
three new enumerators.
* src/abg-comparison.cc ({distinct_diff, var_diff, pointer_diff,
array_diff, reference_diff, qualified_type_diff, enum_diff,
class_or_union_diff, class_diff, base_diff, scope_diff,
fn_parm_diff, function_type_diff, function_decl_diff,
type_decl_diff, typedef_diff,
translation_unit_diff}::has_local_changes): Adjust to return an
enum change_kind, rather than just a bool.
(has_local_type_change_only): Define new functions.
(has_basic_type_change_only): Use the new
has_local_type_change_only function and the new overload for
is_diff_of_basic_type.
(is_diff_of_basic_type): Define an overload that takes a boolean
flag.
(is_qualified_type_diff, peel_pointer_diff, peel_reference_diff)
(peel_qualified_type, peel_pointer_or_qualified_type): Define new
functions.
* src/abg-ir.cc (equals): In the overloads for decl_base,
scope_decl, type_base, qualified_type_diff, pointer_type_def,
reference_type_def, array_type_def, enum_type_decl, typedef_decl,
var_decl, function_type, function_decl, function_decl::parameter,
class_or_union, class_decl::base_spec and class_decl, properly set
the new abigail::ir::{LOCAL_CHANGE_KIND,
LOCAL_NON_TYPE_CHANGE_KIND, LOCAL_TYPE_CHANGE_KIND} bits.
(types_have_similar_structure): Peel qualified types and typedefs
off, first thing.
(peel_qualified_or_typedef_type): Define new function.
* tests/data/test-diff-pkg/spice-server-0.12.4-19.el7.x86_64-0.12.8-1.el7.x86_64-report-3.txt:
Adjust.
* tests/data/test-diff-filter/libtest45-basic-type-change-report-{0,1}.txt:
New reference test reports.
* tests/data/test-diff-filter/libtest45-basic-type-change-v{0,1}.so:
New input test binaries.
* tests/data/test-diff-filter/test45-basic-type-change-v{0,1}.cc:
Source code of the input test binaries above.
* tests/data/Makefile.am: Add the new test file above to source
distribution.
* tests/test-diff-filter.cc: Add the test input above to the test
harness.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
14 files changed:
include/abg-comparison.h
include/abg-fwd.h
include/abg-ir.h
src/abg-comparison.cc
src/abg-ir.cc
tests/data/Makefile.am
tests/data/test-diff-filter/libtest45-basic-type-change-report-0.txt [new file with mode: 0644]
tests/data/test-diff-filter/libtest45-basic-type-change-report-1.txt [new file with mode: 0644]
tests/data/test-diff-filter/libtest45-basic-type-change-v0.so [new file with mode: 0755]
tests/data/test-diff-filter/libtest45-basic-type-change-v1.so [new file with mode: 0755]
tests/data/test-diff-filter/test45-basic-type-change-v0.cc [new file with mode: 0644]
tests/data/test-diff-filter/test45-basic-type-change-v1.cc [new file with mode: 0644]
tests/data/test-diff-pkg/spice-server-0.12.4-19.el7.x86_64-0.12.8-1.el7.x86_64-report-3.txt
tests/test-diff-filter.cc

index 59e162c..c6a6a1e 100644 (file)
@@ -957,7 +957,7 @@ public:
   /// some of its children nodes.
   ///
   /// This is to be implemented by all descendants of this type.
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const = 0;
 
   /// Pure interface to report the diff in a serialized form that is
@@ -1003,7 +1003,7 @@ protected:
 
 public:
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const = 0;
 
   virtual ~type_diff_base();
@@ -1024,7 +1024,7 @@ protected:
 
 public:
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const = 0;
 
   virtual ~decl_diff_base();
@@ -1071,7 +1071,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -1127,7 +1127,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -1184,7 +1184,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -1244,7 +1244,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -1304,7 +1304,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -1365,7 +1365,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -1438,7 +1438,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -1549,7 +1549,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -1619,7 +1619,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual const string&
@@ -1730,7 +1730,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -1839,7 +1839,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -1899,7 +1899,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -1974,7 +1974,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -2032,7 +2032,7 @@ compute_diff(const function_decl_sptr     first,
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -2083,7 +2083,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -2141,7 +2141,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -2193,7 +2193,7 @@ public:
   virtual bool
   has_changes() const;
 
-  virtual bool
+  virtual enum change_kind
   has_local_changes() const;
 
   virtual void
@@ -2652,6 +2652,9 @@ is_decl_diff(const diff* diff);
 const type_decl_diff*
 is_diff_of_basic_type(const diff* diff);
 
+const type_decl_diff*
+is_diff_of_basic_type(const diff* diff, bool);
+
 const class_or_union_diff*
 is_diff_of_class_or_union_type(const diff *d);
 
@@ -2694,6 +2697,8 @@ is_pointer_diff(const diff* diff);
 const reference_diff*
 is_reference_diff(const diff* diff);
 
+const qualified_type_diff*
+is_qualified_type_diff(const diff* diff);
 bool
 is_reference_or_pointer_diff(const diff* diff);
 
@@ -2715,6 +2720,17 @@ is_child_node_of_base_diff(const diff* diff);
 const corpus_diff*
 is_corpus_diff(const diff* diff);
 
+const diff*
+peel_pointer_diff(const diff* dif);
+
+const diff*
+peel_reference_diff(const diff* dif);
+
+const diff*
+peel_qualified_diff(const diff* dif);
+
+const diff*
+peel_pointer_or_qualified_type(const diff*dif);
 }// end namespace comparison
 
 }// end namespace abigail
index d59aab6..fbc7922 100644 (file)
@@ -771,6 +771,9 @@ peel_qualified_type(const type_base*);
 const type_base_sptr
 peel_qualified_type(const type_base_sptr&);
 
+type_base*
+peel_qualified_or_typedef_type(const type_base* type);
+
 type_base_sptr
 peel_typedef_pointer_or_reference_type(const type_base_sptr,
                                       bool peel_qualified_type = true);
index a5c755f..bdd6526 100644 (file)
@@ -1094,15 +1094,33 @@ enum change_kind
 
   /// This means that a given IR artifact has local differences, with
   /// respect to the other artifact it was compared against.  A local
-  /// change is a change that is carried by the artifact itself,
-  /// rather than by one off its sub-types.
+  /// change is a change that is carried by the artifact itself (or
+  /// its type), rather than by one off its sub-types.
+  ///
+  /// Note that if this bit is set, then either one of the @ref
+  /// LOCAL_TYPE_CHANGE_KIND or LOCAL_NON_TYPE_CHANGE_KIND bit must be
+  /// set to, detailing what the kind of local change we have.
   LOCAL_CHANGE_KIND = 1,
 
+  /// This means that a given IR artifact has a local type change.  If
+  /// this bit is set, then the LOCAL_CHANGE_KIND bit must be set too.
+  LOCAL_TYPE_CHANGE_KIND = 1 << 1,
+
+  /// This means that a given IR artifact has a local non-type change.
+  /// That is a change that is carried by the artifact itself, not by
+  /// its type.  If this bit is set, then the LOCAL_CHANGE_KIND bit
+  /// must be set too.
+  LOCAL_NON_TYPE_CHANGE_KIND = 1 << 2,
+
   /// This means that a given IR artifact has changes in some of its
   /// sub-types, with respect to the other artifact it was compared
   /// against.
-  SUBTYPE_CHANGE_KIND = 1 << 1
-};// end enum change_kink
+  SUBTYPE_CHANGE_KIND = 1 << 3,
+
+  /// The masks below must always be the last enumerators.
+  ALL_LOCAL_CHANGES_MASK =
+  LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND
+};// end enum change_kind
 
 change_kind
 operator|(change_kind, change_kind);
index ac30453..f5bd7d5 100644 (file)
@@ -727,6 +727,18 @@ const reference_diff*
 is_reference_diff(const diff* diff)
 {return dynamic_cast<const reference_diff*>(diff);}
 
+/// Test if a diff node is about differences between two qualified
+/// types.
+///
+/// @param diff the diff node to consider.
+///
+/// @return @p diff converted into an instance of @ref
+/// qualified_type_diff iff @p diff is about differences between two
+/// qualified types.
+const qualified_type_diff*
+is_qualified_type_diff(const diff* diff)
+{return dynamic_cast<const qualified_type_diff*>(diff);}
+
 /// Test if a diff node is either a reference diff node or a pointer
 /// diff node.
 ///
@@ -2587,14 +2599,16 @@ bool
 distinct_diff::has_changes() const
 {return first() != second();}
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 distinct_diff::has_local_changes() const
 {
-  // The changes on a distinct_diff are all local.
+  // Changes on a distinct_diff are all local.
   if (has_changes())
-    return true;
-  return false;
+    return (LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND);
+  return NO_CHANGE_KIND;
 }
 
 /// Emit a report about the current diff instance.
@@ -3172,14 +3186,16 @@ bool
 var_diff::has_changes() const
 {return *first_var() != *second_var();}
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 var_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_var(), *second_var(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// Report the diff in a serialized form.
@@ -3297,14 +3313,16 @@ bool
 pointer_diff::has_changes() const
 {return first_pointer() != second_pointer();}
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 pointer_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_pointer(), *second_pointer(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// Getter for the diff between the pointed-to types of the pointers
@@ -3480,14 +3498,17 @@ array_diff::has_changes() const
   return l;
 }
 
-/// @return true iff the current diff node carries local changes.
-bool
+
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 array_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_array(), *second_array(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;;
 }
 
 /// Report the diff in a serialized form.
@@ -3623,14 +3644,16 @@ reference_diff::has_changes() const
   return first_reference() != second_reference();
 }
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 reference_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_reference(), *second_reference(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// Report the diff in a serialized form.
@@ -3781,14 +3804,16 @@ bool
 qualified_type_diff::has_changes() const
 {return first_qualified_type() != second_qualified_type();}
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 qualified_type_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_qualified_type(), *second_qualified_type(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// Report the diff in a serialized form.
@@ -4003,14 +4028,16 @@ bool
 enum_diff::has_changes() const
 {return first_enum() != second_enum();}
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 enum_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_enum(), *second_enum(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// Report the differences between the two enums.
@@ -4789,14 +4816,16 @@ bool
 class_or_union_diff::has_changes() const
 {return first_class_or_union() != second_class_or_union();}
 
-/// Test if the current diff node carries a local change.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 class_or_union_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_class_or_union(), *second_class_or_union(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 
@@ -5209,14 +5238,16 @@ bool
 class_diff::has_changes() const
 {return (first_class_decl() != second_class_decl());}
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 class_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_class_decl(), *second_class_decl(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// @return the first class invoveld in the diff.
@@ -5488,14 +5519,16 @@ bool
 base_diff::has_changes() const
 {return first_base() != second_base();}
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 base_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_base(), *second_base(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// Generates a report for the current instance of base_diff.
@@ -6122,14 +6155,16 @@ scope_diff::has_changes() const
   return changed_types().size() + changed_decls().size();
 }
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 scope_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_scope(), *second_scope(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// Report the changes of one scope against another.
@@ -6302,16 +6337,18 @@ bool
 fn_parm_diff::has_changes() const
 {return *first_parameter() != *second_parameter();}
 
-/// Check if the the current diff node carries a local change.
+/// Check if the current diff node carries a local change.
 ///
-/// @return true iff the current diff node carries a local change.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 fn_parm_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_parameter(), *second_parameter(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// Emit a textual report about the current fn_parm_diff instance.
@@ -6580,14 +6617,16 @@ function_type_diff::has_changes() const
 /// A local change is a change that is carried by this diff node, not
 /// by any of its children nodes.
 ///
-/// @return true iff the current diff node has local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 function_type_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_function_type(), *second_function_type(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// Build and emit a textual report about the current @ref
@@ -6756,14 +6795,16 @@ bool
 function_decl_diff::has_changes() const
 {return *first_function_decl() != *second_function_decl();}
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 function_decl_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_function_decl(), *second_function_decl(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// Serialize a report of the changes encapsulated in the current
@@ -6885,14 +6926,16 @@ bool
 type_decl_diff::has_changes() const
 {return first_type_decl() != second_type_decl();}
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 type_decl_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_type_decl(), *second_type_decl(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 /// Ouputs a report of the differences between of the two type_decl
 /// involved in the type_decl_diff.
@@ -7054,14 +7097,16 @@ typedef_diff::has_changes() const
   return !(*first_typedef_decl() == *second);
 }
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 typedef_diff::has_local_changes() const
 {
   ir::change_kind k = ir::NO_CHANGE_KIND;
   if (!equals(*first_typedef_decl(), *second_typedef_decl(), &k))
-    return k & LOCAL_CHANGE_KIND;
-  return false;
+    return k & ir::ALL_LOCAL_CHANGES_MASK;
+  return ir::NO_CHANGE_KIND;
 }
 
 /// Reports the difference between the two subjects of the diff in a
@@ -7178,10 +7223,12 @@ bool
 translation_unit_diff::has_changes() const
 {return scope_diff::has_changes();}
 
-/// @return true iff the current diff node carries local changes.
-bool
+/// @return the kind of local change carried by the current diff node.
+/// The value returned is zero if the current node carries no local
+/// change.
+enum change_kind
 translation_unit_diff::has_local_changes() const
-{return false;}
+{return ir::NO_CHANGE_KIND;}
 
 /// Report the diff in a serialized form.
 ///
@@ -11236,6 +11283,112 @@ const type_decl_diff*
 is_diff_of_basic_type(const diff *d)
 {return dynamic_cast<const type_decl_diff*>(d);}
 
+/// Test if a diff node represents a diff between two basic types, or
+/// between pointers, references or qualified type to basic types.
+///
+/// @param diff the diff node to consider.
+///
+/// @param allow_indirect_type if true, then this function looks into
+/// pointer, reference or qualified diff types to see if they "point
+/// to" basic types.
+///
+/// @return true iff @p d is a diff between two basic types.
+const type_decl_diff*
+is_diff_of_basic_type(const diff* diff, bool allow_indirect_type)
+{
+  if (allow_indirect_type)
+      diff = peel_pointer_or_qualified_type(diff);
+  return is_diff_of_basic_type(diff);
+}
+
+/// If a diff node is about changes between two pointer types, get the
+/// diff node about changes between the underlying (pointed-to) types.
+///
+/// Note that this function walks the tree of underlying diff nodes
+/// returns the first diff node about types that are not pointers.
+///
+/// @param dif the dif node to consider.
+///
+/// @return the underlying diff node of @p dif, or just return @p dif
+/// if it's not a pointer diff node.
+const diff*
+peel_pointer_diff(const diff* dif)
+{
+  const pointer_diff *d = 0;
+  while ((d = is_pointer_diff(dif)))
+    dif = d->underlying_type_diff().get();
+  return dif;
+}
+
+/// If a diff node is about changes between two reference types, get
+/// the diff node about changes between the underlying (pointed-to)
+/// types.
+///
+/// Note that this function walks the tree of underlying diff nodes
+/// returns the first diff node about types that are not references.
+///
+/// @param dif the dif node to consider.
+///
+/// @return the underlying diff node of @p dif, or just return @p dif
+/// if it's not a reference diff node.
+const diff*
+peel_reference_diff(const diff* dif)
+{
+  const reference_diff *d = 0;
+  while ((d = is_reference_diff(dif)))
+    dif = d->underlying_type_diff().get();
+  return dif;
+}
+
+/// If a diff node is about changes between two qualified types, get
+/// the diff node about changes between the underlying (non-qualified)
+/// types.
+///
+/// Note that this function walks the tree of underlying diff nodes
+/// returns the first diff node about types that are not qualified.
+///
+/// @param dif the dif node to consider.
+///
+/// @return the underlying diff node of @p dif, or just return @p dif
+/// if it's not a qualified diff node.
+const diff*
+peel_qualified_diff(const diff* dif)
+{
+  const qualified_type_diff *d = 0;
+  while ((d = is_qualified_type_diff(dif)))
+    dif = d->underlying_type_diff().get();
+  return dif;
+}
+
+/// If a diff node is about changes between two pointer, reference or
+/// qualified types, get the diff node about changes between the
+/// underlying types.
+///
+/// Note that this function walks the tree of underlying diff nodes
+/// returns the first diff node about types that are not pointer,
+/// reference or qualified.
+///
+/// @param dif the dif node to consider.
+///
+/// @return the underlying diff node of @p dif, or just return @p dif
+/// if it's not a pointer, reference or qualified diff node.
+const diff*
+peel_pointer_or_qualified_type(const diff*dif)
+{
+  while (true)
+    {
+      if (const pointer_diff *d = is_pointer_diff(dif))
+       dif = peel_pointer_diff(d);
+      else if (const reference_diff *d = is_reference_diff(dif))
+       dif = peel_reference_diff(d);
+      else if (const qualified_type_diff *d = is_qualified_type_diff(dif))
+       dif = peel_qualified_diff(d);
+      else
+       break;
+    }
+  return dif;
+}
+
 /// Test if a diff node represents a diff between two class or union
 /// types.
 ///
@@ -11248,9 +11401,29 @@ const class_or_union_diff*
 is_diff_of_class_or_union_type(const diff *d)
 {return dynamic_cast<const class_or_union_diff*>(d);}
 
+/// Test if a given diff node carries *only* a local type change.
+///
+/// @param d the diff node to consider.
+///
+/// @return true iff @p has a change and that change is a local type
+/// change.
+static bool
+has_local_type_change_only(const diff *d)
+{
+  if (enum change_kind k = d->has_local_changes())
+    if ((k & LOCAL_NON_TYPE_CHANGE_KIND) == 0
+       && (k & LOCAL_TYPE_CHANGE_KIND) != 0)
+      return true;
+
+  return false;
+}
+
 /// Test if a diff node is a decl diff that only carries a basic type
 /// change on its type diff sub-node.
 ///
+///Note that that pointers/references/qualified types diffs to basic
+/// type diffs are considered as having basic type change only.
+///
 /// @param d the diff node to consider.
 ///
 /// @return true iff @p d is a decl diff that only carries a basic
@@ -11258,19 +11431,20 @@ is_diff_of_class_or_union_type(const diff *d)
 bool
 has_basic_type_change_only(const diff *d)
 {
-  if (is_diff_of_basic_type(d) && d->has_changes())
+  if (is_diff_of_basic_type(d, true) && d->has_changes())
     return true;
   else if (const var_diff * v = dynamic_cast<const var_diff*>(d))
-    return (!v->has_local_changes()
-           && is_diff_of_basic_type(v->type_diff().get()));
+    return (has_local_type_change_only(v)
+           && is_diff_of_basic_type(v->type_diff().get(), true));
   else if (const fn_parm_diff * p = dynamic_cast<const fn_parm_diff*>(d))
-    return (!p->has_local_changes()
-           && is_diff_of_basic_type(p->type_diff().get()));
+    return (has_local_type_change_only(p)
+           && is_diff_of_basic_type(p->type_diff().get(), true));
   else if (const function_decl_diff* f =
           dynamic_cast<const function_decl_diff*>(d))
-    return (!f->has_local_changes()
+    return (has_local_type_change_only(f)
            && f->type_diff()
-           && is_diff_of_basic_type(f->type_diff()->return_type_diff().get()));
+           && is_diff_of_basic_type(f->type_diff()->return_type_diff().get(),
+                                    true));
   return false;
 }
 }// end namespace comparison
index 739a6bd..87ae642 100644 (file)
@@ -3326,7 +3326,7 @@ equals(const decl_base& l, const decl_base& r, change_kind* k)
            {
              result = false;
              if (k)
-               *k |= LOCAL_CHANGE_KIND;
+               *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
              else
                return false;
            }
@@ -3337,7 +3337,7 @@ equals(const decl_base& l, const decl_base& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -3380,7 +3380,7 @@ equals(const decl_base& l, const decl_base& r, change_kind* k)
        {
          result = false;
          if (k)
-           *k |= LOCAL_CHANGE_KIND;
+           *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
          else
            return false;
        }
@@ -4795,6 +4795,34 @@ peel_qualified_type(const type_base_sptr& type)
   return peel_qualified_type(t->get_underlying_type());
 }
 
+/// Return the leaf underlying type of a qualified or typedef type.
+///
+/// If the underlying type is itself a qualified or typedef type, then
+/// recursively return the first underlying type of that qualified or
+/// typedef type to return the first underlying type that is not a
+/// qualified or typedef type.
+///
+/// If the underlying type is NOT a qualified nor a typedef type, then
+/// just return that underlying type.
+///
+/// @param type the qualified or typedef type to consider.
+///
+/// @return the leaf underlying type.
+type_base*
+peel_qualified_or_typedef_type(const type_base* type)
+{
+  while (is_typedef(type) || is_qualified_type(type))
+    {
+      if (const typedef_decl* t = is_typedef(type))
+       type = peel_typedef_type(t);
+
+      if (const qualified_type_def* t = is_qualified_type(type))
+       type = peel_qualified_type(t);
+    }
+
+  return const_cast<type_base*>(type);
+}
+
 /// Return the leaf underlying or pointed-to type node of a @ref
 /// typedef_decl, @ref pointer_type_def, @ref reference_type_def or
 /// @ref qualified_type_def node.
@@ -5121,7 +5149,7 @@ equals(const scope_decl& l, const scope_decl& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -5148,7 +5176,7 @@ equals(const scope_decl& l, const scope_decl& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -10667,7 +10695,7 @@ equals(const type_base& l, const type_base& r, change_kind* k)
                 && l.get_alignment_in_bits() == r.get_alignment_in_bits());
   if (!result)
     if (k)
-      *k |= LOCAL_CHANGE_KIND;
+      *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
   return result;
 }
 
@@ -11610,7 +11638,7 @@ equals(const qualified_type_def& l, const qualified_type_def& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -11980,10 +12008,10 @@ equals(const pointer_type_def& l, const pointer_type_def& r, change_kind* k)
   if (!result)
     if (k)
       {
-       *k |= SUBTYPE_CHANGE_KIND;
-       if (l.get_pointed_to_type()->get_pretty_representation()
-           != r.get_pointed_to_type()->get_pretty_representation())
-         *k |= LOCAL_CHANGE_KIND;
+       if (!types_have_similar_structure(&l, &r))
+         *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
+       else
+         *k |= SUBTYPE_CHANGE_KIND;
       }
 
   return result;
@@ -12264,7 +12292,7 @@ equals(const reference_type_def& l, const reference_type_def& r, change_kind* k)
   if (l.is_lvalue() != r.is_lvalue())
     {
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
       return false;
     }
 
@@ -12687,7 +12715,7 @@ equals(const array_type_def::subrange_type& l,
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
       else
        return result;
     }
@@ -12699,7 +12727,13 @@ equals(const array_type_def::subrange_type& l,
     {
       result = false;
       if (k)
-       *k |= SUBTYPE_CHANGE_KIND;
+       {
+         if (!types_have_similar_structure(l.get_underlying_type().get(),
+                                           r.get_underlying_type().get()))
+           *k |= LOCAL_CHANGE_KIND;
+         else
+           *k |= SUBTYPE_CHANGE_KIND;
+       }
       else
        return result;
     }
@@ -12932,7 +12966,7 @@ equals(const array_type_def& l, const array_type_def& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -12946,7 +12980,7 @@ equals(const array_type_def& l, const array_type_def& r, change_kind* k)
        result = false;
        if (k)
          {
-           *k |= LOCAL_CHANGE_KIND;
+           *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
            break;
          }
        else
@@ -13303,7 +13337,7 @@ enum_has_non_name_change(const enum_type_decl& l,
        result = true;
        if (k)
          {
-           *k |= LOCAL_CHANGE_KIND;
+           *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
            break;
          }
        else
@@ -13314,7 +13348,7 @@ enum_has_non_name_change(const enum_type_decl& l,
     {
       result = true;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
       else
        return true;
     }
@@ -13331,7 +13365,13 @@ enum_has_non_name_change(const enum_type_decl& l,
     {
       result = true;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       {
+         if (!l.decl_base::operator==(r))
+           *k |= LOCAL_NON_TYPE_CHANGE_KIND;
+         if (!l.type_base::operator==(r))
+           *k |=  LOCAL_TYPE_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND;
+       }
       else
        {
          local_r.set_name(n_r);
@@ -13386,7 +13426,7 @@ equals(const enum_type_decl& l, const enum_type_decl& r, change_kind* k)
        result = false;
        if (k)
          {
-           *k |= LOCAL_CHANGE_KIND;
+           *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
            break;
          }
        else
@@ -13397,7 +13437,7 @@ equals(const enum_type_decl& l, const enum_type_decl& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -13406,7 +13446,13 @@ equals(const enum_type_decl& l, const enum_type_decl& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       {
+         if (!l.decl_base::operator==(r))
+           *k |= LOCAL_NON_TYPE_CHANGE_KIND;
+         if (!l.type_base::operator==(r))
+           *k |= LOCAL_TYPE_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND;
+       }
       else
        return false;
     }
@@ -13737,7 +13783,7 @@ equals(const typedef_decl& l, const typedef_decl& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -14029,9 +14075,7 @@ equals(const var_decl& l, const var_decl& r, change_kind* k)
        {
          if (!types_have_similar_structure(l.get_naked_type(),
                                           r.get_naked_type()))
-           // TODO: add new kinds of change_kind so that callers can
-           // analyse the type of change that happened in a finer fashion.
-           *k |= LOCAL_CHANGE_KIND;
+           *k |= (LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND);
          else
            *k |= SUBTYPE_CHANGE_KIND;
        }
@@ -14046,7 +14090,7 @@ equals(const var_decl& l, const var_decl& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -14054,7 +14098,7 @@ equals(const var_decl& l, const var_decl& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -14076,7 +14120,7 @@ equals(const var_decl& l, const var_decl& r, change_kind* k)
        {
          result = false;
          if (k)
-           *k |= LOCAL_CHANGE_KIND;
+           *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
          else
            return false;
        }
@@ -14086,7 +14130,7 @@ equals(const var_decl& l, const var_decl& r, change_kind* k)
       {
        result = false;
        if (k)
-         *k |= LOCAL_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
        else
          return false;
       }
@@ -14101,7 +14145,7 @@ equals(const var_decl& l, const var_decl& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -14611,7 +14655,7 @@ equals(const function_type& lhs,
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
       else
        RETURN(result);
     }
@@ -14629,7 +14673,7 @@ equals(const function_type& lhs,
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
       else
        RETURN(result);
     }
@@ -14639,7 +14683,7 @@ equals(const function_type& lhs,
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
       else
        RETURN(result);
     }
@@ -14672,10 +14716,11 @@ equals(const function_type& lhs,
          result = false;
          if (k)
            {
-             if (lhs.get_return_type()->get_pretty_representation()
-                 != rhs.get_return_type()->get_pretty_representation())
-               *k |= LOCAL_CHANGE_KIND;
-             *k |= SUBTYPE_CHANGE_KIND;
+             if (!types_have_similar_structure(lhs.get_return_type(),
+                                               rhs.get_return_type()))
+               *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
+             else
+               *k |= SUBTYPE_CHANGE_KIND;
            }
          else
            RETURN(result);
@@ -14714,10 +14759,11 @@ equals(const function_type& lhs,
          result = false;
          if (k)
            {
-             if ((*i)->get_pretty_representation()
-                 != (*j)->get_pretty_representation())
-               *k |= LOCAL_CHANGE_KIND;
-             *k |= SUBTYPE_CHANGE_KIND;
+             if (!types_have_similar_structure((*i)->get_type(),
+                                               (*j)->get_type()))
+               *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
+             else
+               *k |= SUBTYPE_CHANGE_KIND;
            }
          else
            RETURN(result);
@@ -14729,7 +14775,7 @@ equals(const function_type& lhs,
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        RETURN(result);
     }
@@ -15451,9 +15497,10 @@ equals(const function_decl& l, const function_decl& r, change_kind* k)
       result = false;
       if (k)
        {
-         if (l.get_pretty_representation() != r.get_pretty_representation())
-           *k |= LOCAL_CHANGE_KIND;
-         *k |= SUBTYPE_CHANGE_KIND;
+         if (!types_have_similar_structure(t0, t1))
+           *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
+         else
+           *k |= SUBTYPE_CHANGE_KIND;
        }
       else
        return false;
@@ -15464,7 +15511,7 @@ equals(const function_decl& l, const function_decl& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -15474,7 +15521,7 @@ equals(const function_decl& l, const function_decl& r, change_kind* k)
        {
          result = false;
          if (k)
-           *k |= LOCAL_CHANGE_KIND;
+           *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
          else
            return false;
        }
@@ -15504,7 +15551,7 @@ equals(const function_decl& l, const function_decl& r, change_kind* k)
        {
          result = false;
          if (k)
-           *k |= LOCAL_CHANGE_KIND;
+           *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
          else
            return false;
        }
@@ -15514,7 +15561,7 @@ equals(const function_decl& l, const function_decl& r, change_kind* k)
       {
        result = false;
        if (k)
-         *k |= LOCAL_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
        else
          return false;
       }
@@ -15525,7 +15572,7 @@ equals(const function_decl& l, const function_decl& r, change_kind* k)
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -15534,7 +15581,7 @@ equals(const function_decl& l, const function_decl& r, change_kind* k)
     {
       result = false;
       if (k)
-         *k |= LOCAL_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
       else
        return false;
     }
@@ -15556,7 +15603,7 @@ equals(const function_decl& l, const function_decl& r, change_kind* k)
        {
          result = false;
          if (k)
-           *k |= LOCAL_CHANGE_KIND;
+           *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
          else
            return false;
        }
@@ -15905,11 +15952,19 @@ equals(const function_decl::parameter& l,
     {
       result = false;
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       {
+         if (l.get_index() != r.get_index())
+           *k |= LOCAL_NON_TYPE_CHANGE_KIND;
+         if (l.get_variadic_marker() != r.get_variadic_marker()
+             || !!l.get_type() != !!r.get_type())
+           *k |= LOCAL_TYPE_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND;
+       }
       else
        return false;
     }
 
+
   // Sometimes, function parameters can be wrapped into a no-op
   // qualifier.  Let's strip that qualifier out.
   type_base_sptr l_type = look_through_no_op_qualified_type(l.get_type());
@@ -15919,10 +15974,10 @@ equals(const function_decl::parameter& l,
       result = false;
       if (k)
        {
-         *k |= SUBTYPE_CHANGE_KIND;
-         if (get_pretty_representation(l_type)
-             != get_pretty_representation(r_type))
-           *k |= LOCAL_CHANGE_KIND;
+         if (!types_have_similar_structure(l_type, r_type))
+           *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
+         else
+           *k |= SUBTYPE_CHANGE_KIND;
        }
       else
        return false;
@@ -17092,7 +17147,7 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
              else
                {
                  if (k)
-                   *k |= LOCAL_CHANGE_KIND;
+                   *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
                  // Not using RETURN(true) here, because that causes
                  // performance issues.  We don't need to do
                  // l.priv_->unmark_as_being_compared({l,r}) here because
@@ -17108,7 +17163,7 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
              if (!!def1 != !!def2)
                {
                  if (k)
-                   *k |= LOCAL_CHANGE_KIND;
+                   *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
                  return false;
                }
 
@@ -17117,7 +17172,7 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
                       && l.type_base::operator==(r)))
                {
                  if (k)
-                   *k |= LOCAL_CHANGE_KIND;
+                   *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
                  return false;
                }
 
@@ -17135,7 +17190,7 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
       bool val = *def1 == *def2;
       if (!val)
        if (k)
-         *k |= LOCAL_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
       RETURN(val);
     }
 
@@ -17144,7 +17199,7 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
   if (!(l.decl_base::operator==(r) && l.type_base::operator==(r)))
     {
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
       RETURN(false);
     }
 
@@ -17164,7 +17219,7 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
       {
        result = false;
        if (k)
-         *k |= LOCAL_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
        else
          RETURN(result);
       }
@@ -17180,11 +17235,12 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
          result = false;
          if (k)
            {
-             *k |= SUBTYPE_CHANGE_KIND;
              // Report any representation change as being local.
              if (!types_have_similar_structure((*d0)->get_type(),
                                                (*d1)->get_type()))
-               *k |= LOCAL_CHANGE_KIND;
+               *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
+             else
+               *k |= SUBTYPE_CHANGE_KIND;
            }
          else
            RETURN(result);
@@ -17203,7 +17259,7 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
       {
        result = false;
        if (k)
-         *k |= LOCAL_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
        else
          RETURN(result);
       }
@@ -17219,7 +17275,7 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
          result = false;
          if (k)
            {
-             *k |= LOCAL_CHANGE_KIND;
+             *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
              break;
            }
          else
@@ -17234,7 +17290,7 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
       {
        result = false;
        if (k)
-         *k |= LOCAL_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
        else
          RETURN(result);
       }
@@ -17250,7 +17306,7 @@ equals(const class_or_union& l, const class_or_union& r, change_kind* k)
          result = false;
          if (k)
            {
-             *k |= LOCAL_CHANGE_KIND;
+             *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
              break;
            }
          else
@@ -17864,7 +17920,7 @@ equals(const class_decl::base_spec& l,
   if (!l.member_base::operator==(r))
     {
       if (k)
-       *k |= LOCAL_CHANGE_KIND;
+       *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
       return false;
     }
 
@@ -18512,7 +18568,7 @@ equals(const class_decl& l, const class_decl& r, change_kind* k)
       {
        result = false;
        if (k)
-         *k |= LOCAL_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
        else
          RETURN(result);
       }
@@ -18528,7 +18584,11 @@ equals(const class_decl& l, const class_decl& r, change_kind* k)
          result = false;
          if (k)
            {
-             *k |= SUBTYPE_CHANGE_KIND;
+             if (!types_have_similar_structure((*b0)->get_base_class().get(),
+                                               (*b1)->get_base_class().get()))
+               *k |= LOCAL_CHANGE_KIND;
+             else
+               *k |= SUBTYPE_CHANGE_KIND;
              break;
            }
          RETURN(result);
@@ -18557,7 +18617,7 @@ equals(const class_decl& l, const class_decl& r, change_kind* k)
       {
        result = false;
        if (k)
-         *k |= SUBTYPE_CHANGE_KIND;
+         *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
        else
          RETURN(result);
       }
@@ -18587,7 +18647,7 @@ equals(const class_decl& l, const class_decl& r, change_kind* k)
          {
            result = false;
            if (k)
-             *k |= SUBTYPE_CHANGE_KIND;
+             *k |= LOCAL_NON_TYPE_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
            RETURN(result);
          }
 
@@ -20607,18 +20667,18 @@ types_have_similar_structure(const type_base* first, const type_base* second)
   if (!first)
     return false;
 
+  if (is_typedef(first) || is_qualified_type(first))
+    first = peel_qualified_or_typedef_type(first);
+
+  if (is_typedef(second) || is_qualified_type(second))
+    second = peel_qualified_or_typedef_type(second);
+
   bool was_indirect_type = (is_pointer_type(first)
                            || is_pointer_type(second)
                            || is_reference_type(first)
                            || is_reference_type(second));
 
-  bool peel_type_off = (was_indirect_type
-                       || is_typedef(first)
-                       || is_typedef(second)
-                       || is_qualified_type(first)
-                       || is_qualified_type(second));
-
-  if (peel_type_off)
+  if (was_indirect_type)
     {
       first = peel_typedef_pointer_or_reference_type(first);
       second = peel_typedef_pointer_or_reference_type(second);
index 0834f11..4fa5943 100644 (file)
@@ -657,6 +657,12 @@ test-diff-filter/test44-anonymous-data-member-report-0.txt \
 test-diff-filter/test44-anonymous-data-member-report-1.txt \
 test-diff-filter/test44-anonymous-data-member-v0.c \
 test-diff-filter/test44-anonymous-data-member-v1.c \
+test-diff-filter/libtest45-basic-type-change-report-0.txt \
+test-diff-filter/libtest45-basic-type-change-report-1.txt \
+test-diff-filter/libtest45-basic-type-change-v0.so \
+test-diff-filter/libtest45-basic-type-change-v1.so \
+test-diff-filter/test45-basic-type-change-v0.cc \
+test-diff-filter/test45-basic-type-change-v1.cc \
 \
 test-diff-suppr/test0-type-suppr-v0.cc \
 test-diff-suppr/test0-type-suppr-v1.cc \
diff --git a/tests/data/test-diff-filter/libtest45-basic-type-change-report-0.txt b/tests/data/test-diff-filter/libtest45-basic-type-change-report-0.txt
new file mode 100644 (file)
index 0000000..6fb973a
--- /dev/null
@@ -0,0 +1,54 @@
+Functions changes summary: 0 Removed, 4 Changed, 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+4 functions with some indirect sub-type change:
+
+  [C]'function int& foo0(S0&)' at test45-basic-type-change-v1.cc:24:1 has some indirect sub-type changes:
+    return type changed:
+      in referenced type 'int':
+        type name changed from 'int' to 'char'
+        type size changed from 32 to 8 (in bits)
+    parameter 1 of type 'S0&' has sub-type changes:
+      in referenced type 'struct S0' at test45-basic-type-change-v1.cc:8:1:
+        type size hasn't changed
+        1 data member change:
+         type of 'int* S0::m0' changed:
+           in pointed to type 'int':
+             type name changed from 'int' to 'char'
+             type size changed from 32 to 8 (in bits)
+
+
+  [C]'function int* foo1(S1&)' at test45-basic-type-change-v1.cc:28:1 has some indirect sub-type changes:
+    return type changed:
+      in pointed to type 'int':
+        type name changed from 'int' to 'char'
+        type size changed from 32 to 8 (in bits)
+    parameter 1 of type 'S1&' has sub-type changes:
+      in referenced type 'struct S1' at test45-basic-type-change-v1.cc:13:1:
+        type size hasn't changed
+        1 data member change:
+         type of 'int* S1::m0' changed:
+           in pointed to type 'int':
+             type name changed from 'int' to 'char'
+             type size changed from 32 to 8 (in bits)
+
+
+  [C]'function const int foo2(S2&)' at test45-basic-type-change-v1.cc:32:1 has some indirect sub-type changes:
+    return type changed:
+      'const int' changed to 'const char'
+    parameter 1 of type 'S2&' has sub-type changes:
+      in referenced type 'struct S2' at test45-basic-type-change-v1.cc:18:1:
+        type size hasn't changed
+        1 data member change:
+         type of 'int* S2::m0' changed:
+           in pointed to type 'int':
+             type name changed from 'int' to 'char'
+             type size changed from 32 to 8 (in bits)
+
+
+  [C]'function int foo3(S2&)' at test45-basic-type-change-v1.cc:36:1 has some indirect sub-type changes:
+    return type changed:
+      type name changed from 'int' to 'char'
+      type size changed from 32 to 8 (in bits)
+
+
diff --git a/tests/data/test-diff-filter/libtest45-basic-type-change-report-1.txt b/tests/data/test-diff-filter/libtest45-basic-type-change-report-1.txt
new file mode 100644 (file)
index 0000000..52aa688
--- /dev/null
@@ -0,0 +1,42 @@
+Leaf changes summary: 7 artifacts changed
+Changed leaf types summary: 3 leaf types changed
+Removed/Changed/Added functions summary: 0 Removed, 4 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
+4 functions with some sub-type change:
+
+  [C]'function int& foo0(S0&)' at test45-basic-type-change-v1.cc:24:1 has some sub-type changes:
+
+  [C]'function int* foo1(S1&)' at test45-basic-type-change-v1.cc:28:1 has some sub-type changes:
+    return type changed:
+      pointer type changed from: 'int*' to: 'char*'
+  [C]'function const int foo2(S2&)' at test45-basic-type-change-v1.cc:32:1 has some sub-type changes:
+
+  [C]'function int foo3(S2&)' at test45-basic-type-change-v1.cc:36:1 has some sub-type changes:
+    return type changed:
+      type name changed from 'int' to 'char'
+      type size changed from 32 to 8 (in bits)
+
+
+'struct S0 at test45-basic-type-change-v0.cc:8:1' changed:
+  type size hasn't changed
+  there are data member changes:
+   type 'int*' of 'S0::m0' changed:
+     pointer type changed from: 'int*' to: 'char*'
+
+
+
+'struct S1 at test45-basic-type-change-v0.cc:13:1' changed:
+  type size hasn't changed
+  there are data member changes:
+   type 'int*' of 'S1::m0' changed:
+     pointer type changed from: 'int*' to: 'char*'
+
+
+
+'struct S2 at test45-basic-type-change-v0.cc:18:1' changed:
+  type size hasn't changed
+  there are data member changes:
+   type 'int*' of 'S2::m0' changed:
+     pointer type changed from: 'int*' to: 'char*'
+
diff --git a/tests/data/test-diff-filter/libtest45-basic-type-change-v0.so b/tests/data/test-diff-filter/libtest45-basic-type-change-v0.so
new file mode 100755 (executable)
index 0000000..f9837e6
Binary files /dev/null and b/tests/data/test-diff-filter/libtest45-basic-type-change-v0.so differ
diff --git a/tests/data/test-diff-filter/libtest45-basic-type-change-v1.so b/tests/data/test-diff-filter/libtest45-basic-type-change-v1.so
new file mode 100755 (executable)
index 0000000..fd4b39e
Binary files /dev/null and b/tests/data/test-diff-filter/libtest45-basic-type-change-v1.so differ
diff --git a/tests/data/test-diff-filter/test45-basic-type-change-v0.cc b/tests/data/test-diff-filter/test45-basic-type-change-v0.cc
new file mode 100644 (file)
index 0000000..8648720
--- /dev/null
@@ -0,0 +1,40 @@
+// Compile this with:
+// g++ -g -shared -o libtest45-basic-type-change-v0.so test45-basic-type-change-v0.cc
+//
+// This test is to avoid marking the change to int* to char* in the
+// data members of struct S1 and S2 as being redundant.  This is
+// because those changes are, in the end, basic type changes.  Only
+// user-defined type changes should be marked redundant in that
+// scenario.
+
+struct S0
+{
+  int* m0;
+};
+
+struct S1
+{
+  int* m0;
+};
+
+struct S2
+{
+  int* m0;
+};
+
+
+int&
+foo0(S0& s)
+{return *s.m0;}
+
+int*
+foo1(S1& s)
+{return s.m0;}
+
+const int
+foo2(S2&)
+{return 0;}
+
+int
+foo3(S2&)
+{return 0;}
diff --git a/tests/data/test-diff-filter/test45-basic-type-change-v1.cc b/tests/data/test-diff-filter/test45-basic-type-change-v1.cc
new file mode 100644 (file)
index 0000000..b0e1672
--- /dev/null
@@ -0,0 +1,39 @@
+// Compile this with:
+// g++ -g -shared -o libtest45-basic-type-change-v1.so test45-basic-type-change-v1.cc
+//
+// This test is to avoid marking the change to int* to char* in the
+// data members of struct S1 and S2 as being redundant.  This is
+// because those changes are, in the end, basic type changes.  Only
+// user-defined types changes should be marked redundant in that
+// scenario.
+
+struct S0
+{
+  char* m0;
+};
+
+struct S1
+{
+  char* m0;
+};
+
+struct S2
+{
+  char* m0;
+};
+
+char&
+foo0(S0& s)
+{return *s.m0;}
+
+char*
+foo1(S1&s)
+{return s.m0;}
+
+const char
+foo2(S2&)
+{return 0;}
+
+char
+foo3(S2&)
+{return 0;}
index ab8b2a9..5cdbc77 100644 (file)
@@ -1,30 +1,13 @@
 ================ changes of 'libspice-server.so.1.8.0'===============
-Leaf changes summary: 13 artifacts changed (7 filtered out)
+Leaf changes summary: 11 artifacts changed (7 filtered out)
   Changed leaf types summary: 2 (7 filtered out) leaf types changed
-  Removed/Changed/Added functions summary: 1 Removed, 2 Changed, 8 Added functions
+  Removed/Changed/Added functions summary: 1 Removed, 0 Changed, 8 Added functions
   Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
 
   1 Removed function:
 
     [D] 'function int spice_server_migrate_client_state(SpiceServer*)'    {spice_server_migrate_client_state@@SPICE_SERVER_0.6.0}
 
-  2 functions with some sub-type change:
-
-    [C]'function spice_image_compression_t spice_server_get_image_compression(SpiceServer*)' at reds.c:3618:1 has some sub-type changes:
-      return type changed:
-        typedef name changed from spice_image_compression_t to SpiceImageCompression at enums.h:197:1
-
-        2 impacted interfaces:
-          function spice_image_compression_t spice_server_get_image_compression(SpiceServer*)
-          function int spice_server_set_image_compression(SpiceServer*, spice_image_compression_t)
-    [C]'function int spice_server_set_image_compression(SpiceServer*, spice_image_compression_t)' at reds.c:3602:1 has some sub-type changes:
-      parameter 2 of type 'typedef spice_image_compression_t' changed:
-      typedef name changed from spice_image_compression_t to SpiceImageCompression at enums.h:197:1
-
-      2 impacted interfaces:
-        function spice_image_compression_t spice_server_get_image_compression(SpiceServer*)
-        function int spice_server_set_image_compression(SpiceServer*, spice_image_compression_t)
-
   8 Added functions:
 
     [A] 'function void spice_replay_free(SpiceReplay*)'    {spice_replay_free@@SPICE_SERVER_0.12.6}
index 6e99bb1..aff569e 100644 (file)
@@ -514,6 +514,20 @@ InOutSpec in_out_specs[] =
     "data/test-diff-filter/test44-anonymous-data-member-report-1.txt",
     "output/test-diff-filter/test44-anonymous-data-member-report-1.txt",
   },
+  {
+    "data/test-diff-filter/libtest45-basic-type-change-v0.so",
+    "data/test-diff-filter/libtest45-basic-type-change-v1.so",
+    "--no-default-suppression",
+    "data/test-diff-filter/libtest45-basic-type-change-report-0.txt",
+    "output/test-diff-filter/libtest45-basic-type-change-report-0.txt",
+  },
+  {
+    "data/test-diff-filter/libtest45-basic-type-change-v0.so",
+    "data/test-diff-filter/libtest45-basic-type-change-v1.so",
+    "--no-default-suppression --leaf-changes-only",
+    "data/test-diff-filter/libtest45-basic-type-change-report-1.txt",
+    "output/test-diff-filter/libtest45-basic-type-change-report-1.txt",
+  },
   // This should be the last entry
   {NULL, NULL, NULL, NULL, NULL}
 };