libabigail/include/abg-comp-filter.h
Dodji Seketeli 89ab39de78 suppression: Add "has_strict_flexible_array_data_member_conversion" property
In the past, it was common to have a "fake flex array" at the end of a
structure. Like this:

Nowadays, with improved compiler support, it's more common to use a real
flex array. As this is a common change which changes ABI representation
in a compatible way, we should have a suppression for it.

For example, if you have a change like this:

struct foo
{
  int x;
  int flex[1];
};

...

struct foo
{
  int x;
  int flex[];
};

abidiff reports:

  [C] 'struct foo' changed:
    type size changed from 64 to 32 (in bits)
    1 data member change:
      type of 'int flex[1]' changed:
        type name changed from 'int[1]' to 'int[]'
        array type size changed from 32 to 'unknown'
        array type subrange 1 changed length from 1 to 'unknown'

With a new has_strict_flexible_array_data_member_conversion property,
users can specify a suppression which stops abidiff from emitting
this diff for any "fake" flex arrays being converted to real ones:

[suppress_type]
  type_kind = struct
  has_size_change = true
  has_strict_flexible_array_data_member_conversion = true

	* include/abg-comp-filter.h (has_strict_fam_conversion): Declare
	new functions.
	* include/abg-fwd.h
	(ir::has_fake_flexible_array_data_member): Declare new accessor
	functions.
	* include/abg-suppression.h
	(type_suppression::{,set_}has_strict_fam_conversion): Declare new
	accessor functions.
	* src/abg-comp-filter.cc (has_strict_fam_conversion): Define new
	functions.
	* src/abg-ir.cc
	(ir::has_fake_flexible_array_data_member): Define new accessor
	functions.
	* src/abg-suppression-priv.h
	(type_suppression::priv::has_strict_fam_conv_): Define new
	data member.
	* src/abg-suppression.cc
	(type_suppression::{,set_}has_strict_fam_conversion): Define new
	accessor functions.
	(type_suppression::suppresses_diff): For a type suppression to
	match a fake flex array conversion, either the size of the type
	hasn't change or has_size_change must be true and then the type
	must change from a fake flex array to a real flex array.
	(read_type_suppression): Parse the new
	'has_strict_flexible_array_data_member_conversion' property to
	set the type_suppression::set_has_strict_fam_conversion property.
	* doc/manuals/libabigail-concepts.rst: Add an entry for the new
	'has_strict_flexible_array_data_member_conversion' property.
	* tests/data/test-diff-suppr/test-has-strict-flexible-array-data-member-conversion-{1,2}.suppr:
	Add new test suppression files.
	* tests/data/test-diff-suppr/test-has-strict-flexible-array-data-member-conversion-report-{1,2}.txt:
	Add new test reference output files.
	* tests/data/test-diff-suppr/test-has-strict-flexible-array-data-member-conversion-v{0,1}.c:
	Add source code for new binary test input files.
	* tests/data/test-diff-suppr/test-has-strict-flexible-array-data-member-conversion-v{0,1}.o:
	Add new binary test input files.
	* tests/data/Makefile.am: Add the new test files to the source
	distribution.
	* tests/test-diff-suppr.cc (in_out_specs): Add the new test input
	files to this test harness.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
Signed-off-by: John Moon <quic_johmoo@quicinc.com>
2023-11-15 09:55:08 +01:00

170 lines
4.0 KiB
C++

// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2023 Red Hat, Inc.
//
// Author: Dodji Seketeli
/// @file
///
/// This header declares filters for the diff trees resulting from
/// comparing ABI Corpora.
#ifndef __ABG_COMP_FILTER_H__
#define __ABG_COMP_FILTER_H__
#include "abg-comparison.h"
namespace abigail
{
namespace comparison
{
/// Facilities to walk, categorize and possibly filter nodes of the
/// diff tree.
namespace filtering
{
bool
has_harmless_name_change(const decl_base_sptr& f, const decl_base_sptr& s);
bool union_diff_has_harmless_changes(const diff *d);
bool
has_harmful_name_change(const decl_base_sptr& f, const decl_base_sptr& s);
bool
has_harmful_name_change(const diff* dif);
bool
has_virtual_mem_fn_change(const function_decl_diff* diff);
bool
is_decl_only_class_with_size_change(const class_or_union& first,
const class_or_union& second);
bool
is_decl_only_class_with_size_change(const class_or_union_sptr& first,
const class_or_union_sptr& second);
bool
is_decl_only_class_with_size_change(const diff *diff);
bool
has_decl_only_def_change(const decl_base_sptr& first,
const decl_base_sptr& second);
bool
has_decl_only_def_change(const diff *d);
bool
has_class_decl_only_def_change(const class_or_union_sptr& first,
const class_or_union_sptr& second);
bool
has_enum_decl_only_def_change(const enum_type_decl_sptr& first,
const enum_type_decl_sptr& second);
bool
has_class_decl_only_def_change(const diff *diff);
bool
has_enum_decl_only_def_change(const diff *diff);
bool
has_basic_type_name_change(const diff *);
bool
has_class_or_union_type_name_change(const diff *d);
bool
has_basic_or_class_type_name_change(const diff *d);
bool
is_mostly_distinct_diff(const diff *d);
bool
has_anonymous_data_member_change(const diff *d);
bool
has_anonymous_data_member_change(const diff_sptr &d);
bool
has_data_member_replaced_by_anon_dm(const diff* diff);
bool
is_var_1_dim_unknown_size_array_change(const diff*);
bool
is_var_1_dim_unknown_size_array_change(const var_decl_sptr& var1,
const var_decl_sptr& var2);
bool
has_strict_fam_conversion(const class_decl_sptr& first,
const class_decl_sptr& second);
bool
has_strict_fam_conversion(const diff *d);
struct filter_base;
/// Convenience typedef for a shared pointer to filter_base
typedef shared_ptr<filter_base> filter_base_sptr;
/// Convenience typedef for a vector of filter_base_sptr
typedef std::vector<filter_base_sptr> filters;
/// The base class for the diff tree node filter.
///
/// It's intended to walk a tree of diff nodes and tag each relevant
/// name into one or several categories depending on well choosen
/// properties of the diff nodes.
struct filter_base : public diff_node_visitor
{
friend void
apply_filter(filter_base_sptr f, diff_sptr deef);
}; //end class filter_base
void
apply_filter(filter_base& filter, diff_sptr d);
void
apply_filter(filter_base& filter, corpus_diff_sptr d);
void
apply_filter(filter_base_sptr filter, diff_sptr d);
class harmless_filter;
/// Convenience typedef for a shared pointer to a harmless_filter.
typedef shared_ptr<harmless_filter> harmless_filter_sptr;
/// A filter that walks the diff nodes tree and tags relevant diff
/// nodes into categories considered to represent harmless changes.
class harmless_filter : public filter_base
{
virtual bool
visit(diff*, bool);
virtual void
visit_end(diff*);
}; // end class harmless_filter
class harmless_harmful_filter;
/// A convenience typedef for a shared pointer to harmful_filter.
typedef shared_ptr<harmless_harmful_filter> harmful_harmless_filter_sptr;
/// A filter that walks the diff nodes tree and tags relevant diff
/// nodes into categories considered to represent potentially harmless
/// or harmful changes.
class harmless_harmful_filter : public filter_base
{
virtual bool
visit(diff*, bool);
virtual void
visit_end(diff*);
}; // end class harmless_harmful_filter
} // end namespace filtering
} // end namespace comparison
} // end namespace abigail
#endif // __ABG_COMP_FILTER_H__