suppression: Factorize out is_data_member_offset_in_range

In preparation of subsequent changes, this patch factorizes a function
is_data_member_offset_in_range() out of
type_suppression::suppression().  This is useful to determine if a
data member offset is within an "offset range" expressed by the
type_suppression::insertion_range type.

This function is useful to implement the
offset_of_first_data_member_regexp and
offset_of_last_data_member_regexp properties to come in subsequent
patches.

Please note that is_data_member_offset_in_range works on data members
of unions and classes, not just on classes like what the original code
of inside type_suppression::suppresses_diff was doing.

This patch should not have any functional impact on the code.

	* include/abg-fwd.h (get_last_data_member)
	(get_next_data_member_offset): Declare functions.
	* src/abg-ir.cc (get_next_data_member): Add an overload for
	class_or_union and write the overload for class_or_union_sptr in
	term of the former.
	(get_last_data_member): Add overloads form class_or_union& and
	class_or_union*.  Write the overload for class_or_union_sptr in
	terms of the one for class_or_union*.
	(get_next_data_member_offset): Add an overload for
	class_or_union* and write the overload for class_or_union_sptr in
	terms of the former.
	* include/abg-suppression.h
	(type_suppression::insertion_range::eval_boundary): Take a
	class_or_union* for the context, as opposed to a class_decl_sptr.
	This makes this static function work for unions as well.
	(is_data_member_offset_in_range): Declare new function.
	* src/abg-suppression.cc (type_suppression::suppression_diff):
	Factorize ...
	(is_data_member_offset_in_range): ... this function out.
	(type_suppression::insertion_range::eval_boundary): Adjust this to
	make it take a class_or_union* rather than a class_decl_sptr.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2023-01-27 15:58:37 +01:00
parent 153b37a164
commit b1b69abd79
4 changed files with 138 additions and 64 deletions

View File

@ -655,6 +655,12 @@ is_data_member(const decl_base *);
const var_decl_sptr
get_next_data_member(const class_or_union_sptr&, const var_decl_sptr&);
var_decl_sptr
get_last_data_member(const class_or_union&);
var_decl_sptr
get_last_data_member(const class_or_union*);
var_decl_sptr
get_last_data_member(const class_or_union_sptr&);
@ -740,6 +746,11 @@ get_data_member_offset(const decl_base_sptr);
uint64_t
get_absolute_data_member_offset(const var_decl&);
bool
get_next_data_member_offset(const class_or_union*,
const var_decl_sptr&,
uint64_t&);
bool
get_next_data_member_offset(const class_or_union_sptr&,
const var_decl_sptr&,

View File

@ -346,9 +346,9 @@ public:
create_fn_call_expr_boundary(const string&);
static bool
eval_boundary(boundary_sptr boundary,
class_decl_sptr context,
uint64_t& value);
eval_boundary(const boundary_sptr boundary,
const class_or_union* context,
uint64_t& value);
static bool
boundary_value_is_end(uint64_t value);
@ -899,6 +899,12 @@ is_type_suppressed(const fe_iface& fe,
const location& type_location,
bool& type_is_private,
bool require_drop_property = false);
bool
is_data_member_offset_in_range(const var_decl_sptr&,
const type_suppression::insertion_range_sptr&,
const class_or_union*);
} // end namespace suppr

View File

@ -5752,7 +5752,7 @@ get_first_non_anonymous_data_member(const var_decl_sptr anon_dm)
/// @return the data member that is located right after @p
/// data_member.
const var_decl_sptr
get_next_data_member(const class_or_union_sptr &klass,
get_next_data_member(const class_or_union *klass,
const var_decl_sptr &data_member)
{
if (!klass ||!data_member)
@ -5773,12 +5773,40 @@ get_next_data_member(const class_or_union_sptr &klass,
return var_decl_sptr();
}
/// In the context of a given class or union, this function returns
/// the data member that is located after a given data member.
///
/// @param klass the class or union to consider.
///
/// @param the data member to consider.
///
/// @return the data member that is located right after @p
/// data_member.
const var_decl_sptr
get_next_data_member(const class_or_union_sptr& klass,
const var_decl_sptr &data_member)
{return get_next_data_member(klass.get(), data_member);}
/// Get the last data member of a class type.
///
/// @param klass the class type to consider.
var_decl_sptr
get_last_data_member(const class_or_union& klass)
{return klass.get_non_static_data_members().back();}
/// Get the last data member of a class type.
///
/// @param klass the class type to consider.
var_decl_sptr
get_last_data_member(const class_or_union* klass)
{return get_last_data_member(*klass);}
/// Get the last data member of a class type.
///
/// @param klass the class type to consider.
var_decl_sptr
get_last_data_member(const class_or_union_sptr &klass)
{return klass->get_non_static_data_members().back();}
{return get_last_data_member(klass.get());}
/// Test if a decl is an anonymous data member.
///
@ -6062,7 +6090,7 @@ get_data_member_offset(const decl_base_sptr d)
/// @return true iff the data member coming right after @p dm was
/// found.
bool
get_next_data_member_offset(const class_or_union_sptr& klass,
get_next_data_member_offset(const class_or_union* klass,
const var_decl_sptr& dm,
uint64_t& offset)
{
@ -6073,6 +6101,29 @@ get_next_data_member_offset(const class_or_union_sptr& klass,
return true;
}
/// Get the offset of the non-static data member that comes after a
/// given one.
///
/// If there is no data member after after the one given to this
/// function (maybe because the given one is the last data member of
/// the class type) then the function return false.
///
/// @param klass the class to consider.
///
/// @param dm the data member before the one we want to retrieve.
///
/// @param offset out parameter. This parameter is set by the
/// function to the offset of the data member that comes right after
/// the data member @p dm, iff the function returns true.
///
/// @return true iff the data member coming right after @p dm was
/// found.
bool
get_next_data_member_offset(const class_or_union_sptr& klass,
const var_decl_sptr& dm,
uint64_t& offset)
{return get_next_data_member_offset(klass.get(), dm, offset);}
/// Get the absolute offset of a data member.
///
/// If the data member is part of an anonymous data member then this

View File

@ -865,65 +865,19 @@ type_suppression::suppresses_diff(const diff* diff) const
const class_decl_sptr& first_type_decl =
klass_diff->first_class_decl();
for (string_decl_base_sptr_map::const_iterator m =
klass_diff->inserted_data_members().begin();
m != klass_diff->inserted_data_members().end();
++m)
// All inserted data members must be in an allowed
// insertion range.
for (const auto& m : klass_diff->inserted_data_members())
{
decl_base_sptr member = m->second;
size_t dm_offset = get_data_member_offset(member);
decl_base_sptr member = m.second;
bool matched = false;
for (insertion_ranges::const_iterator i =
get_data_member_insertion_ranges().begin();
i != get_data_member_insertion_ranges().end();
++i)
{
type_suppression::insertion_range_sptr range = *i;
uint64_t range_begin_val = 0, range_end_val = 0;
if (!type_suppression::insertion_range::eval_boundary
(range->begin(), first_type_decl, range_begin_val))
break;
if (!type_suppression::insertion_range::eval_boundary
(range->end(), first_type_decl, range_end_val))
break;
uint64_t range_begin = range_begin_val;
uint64_t range_end = range_end_val;
if (insertion_range::boundary_value_is_end(range_begin)
&& insertion_range::boundary_value_is_end(range_end))
{
// This idiom represents the predicate
// "has_data_member_inserted_at = end"
if (dm_offset >
get_data_member_offset(get_last_data_member
(first_type_decl)))
{
// So the data member was added after
// last data member of the klass. That
// matches the suppr spec
// "has_data_member_inserted_at = end".
matched = true;
continue;
}
}
if (range_begin > range_end)
// Wrong suppr spec. Ignore it.
continue;
if (dm_offset < range_begin || dm_offset > range_end)
// The offset of the added data member doesn't
// match the insertion range specified. So
// the diff object won't be suppressed.
continue;
// If we reached this point, then all the
// insertion range constraints have been
// satisfied. So
for (const auto& range : get_data_member_insertion_ranges())
if (is_data_member_offset_in_range(is_var_decl(member),
range,
first_type_decl.get()))
matched = true;
}
if (!matched)
return false;
}
@ -1404,9 +1358,9 @@ type_suppression::insertion_range::create_fn_call_expr_boundary(const string& s)
/// @return true iff the evaluation was successful and @p value
/// contains the resulting value.
bool
type_suppression::insertion_range::eval_boundary(boundary_sptr boundary,
class_decl_sptr context,
uint64_t& value)
type_suppression::insertion_range::eval_boundary(const boundary_sptr boundary,
const class_or_union* context,
uint64_t& value)
{
if (integer_boundary_sptr b = is_integer_boundary(boundary))
{
@ -4962,5 +4916,57 @@ is_type_suppressed(const fe_iface& fe,
return false;
}
/// Test if a data memer offset is in a given insertion range.
///
/// @param dm the data member to consider.
///
/// @param range the insertion range to consider.
///
/// @param the class (or union) type to consider as the context in
/// which to evaluate the insertion range denoted by @p range.
///
/// @return true iff the offset of the data member @p dm is in the
/// insertion range @p range in the context of the type denoted by @p
/// context.
bool
is_data_member_offset_in_range(const var_decl_sptr& dm,
const type_suppression::insertion_range_sptr& range,
const class_or_union* context)
{
ABG_ASSERT(dm && range && context);
uint64_t range_begin = 0, range_end = 0;
if (!type_suppression::insertion_range::eval_boundary (range->begin(),
context,
range_begin))
return false;
if (!type_suppression::insertion_range::eval_boundary (range->end(),
context,
range_end))
return false;
if (range_begin > range_end)
// wrong range, ignore it.
return false;
uint64_t dm_offset = get_data_member_offset(dm);
if (type_suppression::insertion_range::boundary_value_is_end(range_begin)
&& type_suppression::insertion_range::boundary_value_is_end(range_end))
{
// This idiom represents the predicate
// "has_data_member_inserted_at = end"
if (dm_offset > get_data_member_offset(get_last_data_member(context)))
return true;
return false;
}
if (dm_offset < range_begin || dm_offset > range_end)
// The offset of the data member is outside the range.
return false;
return true;
}
}// end namespace suppr
} // end namespace abigail