/// 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
public:
- virtual bool
+ virtual enum change_kind
has_local_changes() const = 0;
virtual ~type_diff_base();
public:
- virtual bool
+ virtual enum change_kind
has_local_changes() const = 0;
virtual ~decl_diff_base();
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual const string&
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
virtual bool
has_changes() const;
- virtual bool
+ virtual enum change_kind
has_local_changes() const;
virtual void
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);
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);
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
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);
/// 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);
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.
///
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.
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.
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
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.
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.
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.
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.
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;
}
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.
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.
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.
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.
/// 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
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
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.
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
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.
///
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.
///
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
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
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
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.
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
&& 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;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
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;
if (l.is_lvalue() != r.is_lvalue())
{
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
else
return result;
}
{
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;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
else
return false;
}
result = false;
if (k)
{
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
break;
}
else
result = true;
if (k)
{
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
break;
}
else
{
result = true;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
else
return true;
}
{
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);
result = false;
if (k)
{
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
break;
}
else
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
else
return false;
}
{
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;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
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;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
else
RETURN(result);
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
else
RETURN(result);
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
else
RETURN(result);
}
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);
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);
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
RETURN(result);
}
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;
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
return false;
}
{
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());
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;
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
if (!!def1 != !!def2)
{
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
return false;
}
&& l.type_base::operator==(r)))
{
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
return false;
}
bool val = *def1 == *def2;
if (!val)
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
RETURN(val);
}
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);
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
else
RETURN(result);
}
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);
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
RETURN(result);
}
result = false;
if (k)
{
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
break;
}
else
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
RETURN(result);
}
result = false;
if (k)
{
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
break;
}
else
if (!l.member_base::operator==(r))
{
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
return false;
}
{
result = false;
if (k)
- *k |= LOCAL_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_TYPE_CHANGE_KIND;
else
RETURN(result);
}
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);
{
result = false;
if (k)
- *k |= SUBTYPE_CHANGE_KIND;
+ *k |= LOCAL_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
else
RETURN(result);
}
{
result = false;
if (k)
- *k |= SUBTYPE_CHANGE_KIND;
+ *k |= LOCAL_NON_TYPE_CHANGE_KIND | LOCAL_NON_TYPE_CHANGE_KIND;
RETURN(result);
}
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);
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 \
--- /dev/null
+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)
+
+
--- /dev/null
+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*'
+
--- /dev/null
+// 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;}
--- /dev/null
+// 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;}
================ 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}
"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}
};