@@ -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&,
@@ -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
@@ -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
@@ -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