// to show what the user expects, namely, a changed anonymous
// enum.
{
- std::set<enum_type_decl_sptr> deleted_anon_enums;
- std::set<enum_type_decl_sptr> added_anon_enums;
+ std::set<type_base_sptr> deleted_anon_types;
+ std::set<type_base_sptr> added_anon_types;
for (auto entry : deleted_unreachable_types_)
- if (is_enum_type(entry.second)
- && is_enum_type(entry.second)->get_is_anonymous())
- deleted_anon_enums.insert(is_enum_type(entry.second));
-
- for (auto entry : added_unreachable_types_)
- if (is_enum_type(entry.second)
- && is_enum_type(entry.second)->get_is_anonymous())
- added_anon_enums.insert(is_enum_type(entry.second));
+ {
+ if ((is_enum_type(entry.second)
+ && is_enum_type(entry.second)->get_is_anonymous())
+ || (is_class_or_union_type(entry.second)
+ && is_class_or_union_type(entry.second)->get_is_anonymous()))
+ deleted_anon_types.insert(entry.second);
+ }
- string_type_base_sptr_map added_anon_enum_to_erase;
- string_type_base_sptr_map removed_anon_enum_to_erase;
- // Look for deleted anonymous enums which have enumerators
- // present in an added anonymous enums ...
- for (auto deleted_enum : deleted_anon_enums)
+ for (auto entry : added_unreachable_types_)
+ if ((is_enum_type(entry.second)
+ && is_enum_type(entry.second)->get_is_anonymous())
+ || (is_class_or_union_type(entry.second)
+ && is_class_or_union_type(entry.second)->get_is_anonymous()))
+ added_anon_types.insert(entry.second);
+
+ string_type_base_sptr_map added_anon_types_to_erase;
+ string_type_base_sptr_map removed_anon_types_to_erase;
+ enum_type_decl_sptr deleted_enum;
+ class_or_union_sptr deleted_class;
+
+ // Look for deleted anonymous types (enums, unions, structs &
+ // classes) which have enumerators or data members present in an
+ // added anonymous type ...
+ for (auto deleted: deleted_anon_types)
{
- // Look for any enumerator of 'deleted_enum' that is also
- // present in an added anonymous enum.
- for (auto enr : deleted_enum->get_enumerators())
+ deleted_enum = is_enum_type(deleted);
+ deleted_class = is_class_or_union_type(deleted);
+
+ // For enums, look for any enumerator of 'deleted_enum' that
+ // is also present in an added anonymous enum.
+ if (deleted_enum)
{
- bool this_enum_got_changed = false;
- for (auto added_enum : added_anon_enums)
+ for (auto enr : deleted_enum->get_enumerators())
{
- if (is_enumerator_present_in_enum(enr, *added_enum))
+ bool this_enum_got_changed = false;
+ for (auto t : added_anon_types)
{
- // So the enumerator 'enr' from the
- // 'deleted_enum' enum is also present in the
- // 'added_enum' enum so we assume that
- // 'deleted_enum' and 'added_enum' are the same
- // enum that got changed. Let's represent it
- // using a diff node.
- diff_sptr d = compute_diff(deleted_enum,
- added_enum, ctxt);
- ABG_ASSERT(d->has_changes());
- string repr =
- abigail::ir::get_pretty_representation(is_type(deleted_enum),
- /*internal=*/false);
- changed_unreachable_types_[repr]= d;
- this_enum_got_changed = true;
- string r1 = abigail::ir::get_pretty_representation(is_type(deleted_enum));
- string r2 = abigail::ir::get_pretty_representation(is_type(added_enum));
- removed_anon_enum_to_erase[r1] = deleted_enum;
- added_anon_enum_to_erase[r2] = added_enum;
- break;
+ if (enum_type_decl_sptr added_enum = is_enum_type(t))
+ if (is_enumerator_present_in_enum(enr, *added_enum))
+ {
+ // So the enumerator 'enr' from the
+ // 'deleted_enum' enum is also present in the
+ // 'added_enum' enum so we assume that
+ // 'deleted_enum' and 'added_enum' are the same
+ // enum that got changed. Let's represent it
+ // using a diff node.
+ diff_sptr d = compute_diff(deleted_enum,
+ added_enum, ctxt);
+ ABG_ASSERT(d->has_changes());
+ string repr =
+ abigail::ir::get_pretty_representation(is_type(deleted_enum),
+ /*internal=*/false);
+ changed_unreachable_types_[repr]= d;
+ this_enum_got_changed = true;
+ string r1 =
+ abigail::ir::get_pretty_representation(is_type(deleted_enum),
+ /*internal=*/false);
+ string r2 =
+ abigail::ir::get_pretty_representation(is_type(added_enum),
+ /*internal=*/false);
+ removed_anon_types_to_erase[r1] = deleted_enum;
+ added_anon_types_to_erase[r2] = added_enum;
+ break;
+ }
}
+ if (this_enum_got_changed)
+ break;
+ }
+ }
+ else if (deleted_class)
+ {
+ // For unions, structs & classes, look for any data
+ // member of 'deleted_class' that is also present in an
+ // added anonymous class.
+ for (auto dm : deleted_class->get_data_members())
+ {
+ bool this_class_got_changed = false;
+ for (auto klass : added_anon_types)
+ {
+ if (class_or_union_sptr added_class =
+ is_class_or_union_type(klass))
+ if (class_or_union_types_of_same_kind(deleted_class,
+ added_class)
+ && lookup_data_member(added_class, dm))
+ {
+ // So the data member 'dm' from the
+ // 'deleted_class' class is also present in
+ // the 'added_class' class so we assume that
+ // 'deleted_class' and 'added_class' are the
+ // same anonymous class that got changed.
+ // Let's represent it using a diff node.
+ diff_sptr d = compute_diff(is_type(deleted_class),
+ is_type(added_class),
+ ctxt);
+ ABG_ASSERT(d->has_changes());
+ string repr =
+ abigail::ir::get_pretty_representation(is_type(deleted_class),
+ /*internal=*/false);
+ changed_unreachable_types_[repr]= d;
+ this_class_got_changed = true;
+ string r1 =
+ abigail::ir::get_pretty_representation(is_type(deleted_class),
+ /*internal=*/false);
+ string r2 =
+ abigail::ir::get_pretty_representation(is_type(added_class),
+ /*internal=*/false);
+ removed_anon_types_to_erase[r1] = deleted_class;
+ added_anon_types_to_erase[r2] = added_class;
+ break;
+ }
+ }
+ if (this_class_got_changed)
+ break;
}
- if (this_enum_got_changed)
- break;
}
}
- // Now remove the added/removed anonymous enums from their maps,
- // as they are now represented as a changed enum, not an added
- // and removed enum.
-
- for (auto entry : added_anon_enum_to_erase)
+ // Now remove the added/removed anonymous types from their maps,
+ // as they are now represented as a changed type, not an added
+ // and removed anonymous type.
+ for (auto entry : added_anon_types_to_erase)
added_unreachable_types_.erase(entry.first);
- for (auto entry : removed_anon_enum_to_erase)
+ for (auto entry : removed_anon_types_to_erase)
deleted_unreachable_types_.erase(entry.first);
}
}
&& is_class_or_union_type(d.get_type()));
}
+/// Test if a @ref var_decl is a data member belonging to an anonymous
+/// type.
+///
+/// @param d the @ref var_decl to consider.
+///
+/// @return true iff @p d is a data member belonging to an anonymous
+/// type.
+bool
+is_data_member_of_anonymous_class_or_union(const var_decl& d)
+{
+ if (is_data_member(d))
+ {
+ scope_decl* scope = d.get_scope();
+ if (scope && scope->get_is_anonymous())
+ return true;
+ }
+ return false;
+}
+
+/// Test if a @ref var_decl is a data member belonging to an anonymous
+/// type.
+///
+/// @param d the @ref var_decl to consider.
+///
+/// @return true iff @p d is a data member belonging to an anonymous
+/// type.
+bool
+is_data_member_of_anonymous_class_or_union(const var_decl* d)
+{return is_data_member_of_anonymous_class_or_union(*d);}
+
+/// Test if a @ref var_decl is a data member belonging to an anonymous
+/// type.
+///
+/// @param d the @ref var_decl to consider.
+///
+/// @return true iff @p d is a data member belonging to an anonymous
+/// type.
+bool
+is_data_member_of_anonymous_class_or_union(const var_decl_sptr& d)
+{return is_data_member_of_anonymous_class_or_union(d.get());}
+
/// Get the @ref class_or_union type of a given anonymous data member.
///
/// @param d the anonymous data member to consider.
is_class_or_union_type(const shared_ptr<type_or_decl_base>& t)
{return dynamic_pointer_cast<class_or_union>(t);}
+/// Test if two class or union types are of the same kind.
+///
+/// @param first the first type to consider.
+///
+/// @param second the second type to consider.
+///
+/// @return true iff @p first is of the same kind as @p second.
+bool
+class_or_union_types_of_same_kind(const class_or_union* first,
+ const class_or_union* second)
+{
+ if ((is_class_type(first) && is_class_type(second))
+ || (is_union_type(first) && is_union_type(second)))
+ return true;
+
+ return false;
+}
+
+/// Test if two class or union types are of the same kind.
+///
+/// @param first the first type to consider.
+///
+/// @param second the second type to consider.
+///
+/// @return true iff @p first is of the same kind as @p second.
+bool
+class_or_union_types_of_same_kind(const class_or_union_sptr& first,
+ const class_or_union_sptr& second)
+{return class_or_union_types_of_same_kind(first.get(), second.get());}
+
/// Test if a type is a @ref union_decl.
///
/// @param t the type to consider.
return cou->find_data_member(dm_name).get();
}
+/// Look for a data member of a given class, struct or union type and
+/// return it.
+///
+/// The data member is designated by its name.
+///
+/// @param type the class, struct or union type to consider.
+///
+/// @param dm the data member to lookup.
+///
+/// @return the data member iff it was found in @type or NULL if no
+/// data member with that name was found.
+const var_decl_sptr
+lookup_data_member(const type_base_sptr& type, const var_decl_sptr& dm)
+{
+ class_or_union_sptr cou = is_class_or_union_type(type);
+ if (!cou)
+ return var_decl_sptr();
+
+ return cou->find_data_member(dm);
+}
+
/// Get the function parameter designated by its index.
///
/// Note that the first function parameter has index 0.