Better detect when diff nodes only carry local type changes

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>
This commit is contained in:
Dodji Seketeli 2018-05-23 11:43:29 +02:00
parent 1ef833b38d
commit 11c2437a19
14 changed files with 650 additions and 201 deletions

View 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

View 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);

View 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);

View 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

View 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);

View 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 \

View File

@ -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)

View File

@ -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*'

View File

@ -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;}

View File

@ -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;}

View 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}

View 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}
};