[03/13] suppression: Factorize out is_data_member_offset_in_range

Message ID 87pm9rq8vl.fsf_-_@redhat.com
State New
Headers
Series Support negative suppression specifications |

Commit Message

Dodji Seketeli March 2, 2023, 6:57 p.m. UTC
  Hello,

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>
---
 include/abg-fwd.h         |  11 ++++
 include/abg-suppression.h |  12 +++-
 src/abg-ir.cc             |  57 +++++++++++++++++-
 src/abg-suppression.cc    | 122 ++++++++++++++++++++------------------
 4 files changed, 138 insertions(+), 64 deletions(-)
  

Patch

diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index 155642f0..4051fab5 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -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&,
diff --git a/include/abg-suppression.h b/include/abg-suppression.h
index 27f52110..b13bb9fb 100644
--- a/include/abg-suppression.h
+++ b/include/abg-suppression.h
@@ -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
 
 
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 321adbf5..ef19eb41 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -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
diff --git a/src/abg-suppression.cc b/src/abg-suppression.cc
index 5fcdef97..b596e0d5 100644
--- a/src/abg-suppression.cc
+++ b/src/abg-suppression.cc
@@ -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