traverse(ir_node_visitor& v);
virtual ~enum_type_decl();
+
+ friend bool
+ enum_has_non_name_change(const enum_type_decl& l,
+ const enum_type_decl& r,
+ change_kind* k);
}; // end class enum_type_decl
bool
bool
operator!=(const enum_type_decl_sptr& l, const enum_type_decl_sptr& r);
+bool
+enum_has_non_name_change(const enum_type_decl& l,
+ const enum_type_decl& r,
+ change_kind* k);
+
/// The abstraction of an enumerator
class enum_type_decl::enumerator
{
/// Test if two decls represents a harmless name change.
///
-/// For now, a harmless name change is a name change for a typedef,
-/// enum or data member.
+/// For now, a harmless name change is considered only for a typedef,
+/// enum or a data member.
///
/// @param f the first decl to consider in the comparison.
///
bool
has_harmless_name_change(const decl_base_sptr& f, const decl_base_sptr& s)
{
+ // So, a harmless name change is either ...
return (decl_name_changed(f, s)
- && ((is_typedef(f) && is_typedef(s))
- || (is_data_member(f) && is_data_member(s))
- || (is_enum_type(f) && is_enum_type(s))));
+ && (// ... a typedef name change, without having the
+ // underlying type changed ...
+ (is_typedef(f)
+ && is_typedef(s)
+ && (is_typedef(f)->get_underlying_type()
+ == is_typedef(s)->get_underlying_type()))
+ // .. or a data member name change, without having the
+ // its type changed ...
+ || (is_data_member(f)
+ && is_data_member(s)
+ && (is_var_decl(f)->get_type()
+ == is_var_decl(s)->get_type()))
+ // .. an enum name change without having any other part
+ // of the enum to change.
+ || (is_enum_type(f)
+ && is_enum_type(s)
+ && !enum_has_non_name_change(*is_enum_type(f),
+ *is_enum_type(s),
+ 0))));
}
/// Test if a class_diff node has non-static members added or
maybe_report_diff_for_member(f, s, d.context(), out, indent);
- if (filtering::has_harmless_name_change(f, s)
- && ((d.context()->get_allowed_category()
- & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
- ||
- d.context()->show_leaf_changes_only()))
+ if ((filtering::has_harmless_name_change(f, s)
+ && ((d.context()->get_allowed_category()
+ & HARMLESS_DECL_NAME_CHANGE_CATEGORY)
+ || d.context()->show_leaf_changes_only()))
+ || f->get_qualified_name() != s->get_qualified_name())
{
out << indent << "typedef name changed from "
<< f->get_qualified_name()
enum_type_decl::~enum_type_decl()
{}
+/// Test if two enums differ, but not by a name change.
+///
+/// @param l the first enum to consider.
+///
+/// @param r the second enum to consider.
+///
+/// @return true iff @p l differs from @p r by anything but a name
+/// change.
+bool
+enum_has_non_name_change(const enum_type_decl& l,
+ const enum_type_decl& r,
+ change_kind* k)
+{
+ bool result = false;
+ if (*l.get_underlying_type() != *r.get_underlying_type())
+ {
+ result = true;
+ if (k)
+ *k |= SUBTYPE_CHANGE_KIND;
+ else
+ return true;
+ }
+
+ enum_type_decl::enumerators::const_iterator i, j;
+ for (i = l.get_enumerators().begin(), j = r.get_enumerators().begin();
+ i != l.get_enumerators().end() && j != r.get_enumerators().end();
+ ++i, ++j)
+ if (*i != *j)
+ {
+ result = true;
+ if (k)
+ {
+ *k |= LOCAL_CHANGE_KIND;
+ break;
+ }
+ else
+ return true;
+ }
+
+ if (i != l.get_enumerators().end() || j != r.get_enumerators().end())
+ {
+ result = true;
+ if (k)
+ *k |= LOCAL_CHANGE_KIND;
+ else
+ return true;
+ }
+
+ enum_type_decl &local_r = const_cast<enum_type_decl&>(r);
+ interned_string qn_r = l.get_environment()->intern(r.get_qualified_name());
+ interned_string qn_l = l.get_environment()->intern(l.get_qualified_name());
+ string n_l = l.get_name();
+ string n_r = r.get_name();
+ local_r.set_qualified_name(qn_l);
+ local_r.set_name(n_l);
+
+ if (!(l.decl_base::operator==(r) && l.type_base::operator==(r)))
+ {
+ result = true;
+ if (k)
+ *k |= LOCAL_CHANGE_KIND;
+ else
+ {
+ local_r.set_name(n_r);
+ local_r.set_qualified_name(qn_r);
+ return true;
+ }
+ }
+ local_r.set_qualified_name(qn_r);
+ local_r.set_name(n_r);
+
+ return result;
+}
+
/// Compares two instances of @ref enum_type_decl.
///
/// If the two intances are different, set a bitfield to give some