suppression: Factorize out is_data_member_offset_in_range
authorDodji Seketeli <dodji@redhat.com>
Fri, 27 Jan 2023 14:58:37 +0000 (15:58 +0100)
committerDodji Seketeli <dodji@redhat.com>
Wed, 1 Mar 2023 12:49:51 +0000 (13:49 +0100)
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
include/abg-suppression.h
src/abg-ir.cc
src/abg-suppression.cc

index 155642f0960a2f0dc81eae49a12ed96c0062a66c..4051fab592a3fc04e3f46fcc7d8ab4afb5041a95 100644 (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&,
index 27f52110836b7796c20fb6156d1e788f7096a183..b13bb9fb460e1cf5dd0207c68bed2dca0b59c84b 100644 (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
 
 
index 321adbf5e05ef45e7caae15effde0a740df23b33..ef19eb4148fdcd9363ebc812dd45e6068295c10c 100644 (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
index 5fcdef97b6d8dc7509d11c76126b10592a68489f..b596e0d566e575fb1c26e0a5b41016256cb78d3e 100644 (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