libabigail/include/abg-reporter.h
Dodji Seketeli 3d7916caa4 Bug 26309 - Wrong leaf reporting of changes to typedef underlying type
In leaf mode, libabigail fails to report changes to the underlying
type of a typedef.

At its core, this is due to the fact that changes to the underlying
type of a typedef are not considered local.  As the leaf reporter only
reports local changes (as opposed to non-local changes which are
changes to sub-types) it doesn't detect those non-local typedef
changes.

To handle this, this patch makes changes to the underlying type of a
typedef be considered as local changes.  This is like what we already
do for pointer and qualified types.

Now that we have another set of changes to report in the leaf
reporter, we need to handle how to propagate the category and
redundancy status of those changes.  The patch does this too.

Also, just like we do pointer and qualified type changes, the patch
avoids marking the diff node carrying the typedef change as being a
leaf change.  That way, only existing leaf changes carrying that
typedef diff node will be reported.  For instance, a function whose
parameter has a typedef change will be reported because that change to
the function is considered a leaf change.  Otherwise, reporting the
typedef (or the pointer or qualified) type change on its own is not
useful unless it impacts those leaf changes that we deem useful.

The patch adds the example given in problem report to the testsuite.

 	* src/abg-ir.cc (equals): In the overload for typedef_decls,
	report changes to the underlying type as being local of kind
	LOCAL_TYPE_CHANGE_KIND.
	* src/abg-comparison.cc
	(leaf_diff_node_marker_visitor::visit_begin): Do not mark typedef
	diff node as leaf node.
	(suppression_categorization_visitor::visit_end): Propagate the
	'suppressed' category of the underlying type to the parent typedef
	unless the later has a local non-type change.
	(redundancy_marking_visitor::visit_end): Likewise for the
	'redundant' category.
	* include/abg-reporter.h (report_non_type_typedef_changes): Rename ...
	* src/abg-default-reporter.cc (report_non_type_typedef_changes):
	... report_local_typedef_changes into this.
	* src/abg-leaf-reporter.cc (leaf_reporter::report): Make the leaf
	reporter invoke the reporting method of the default reporter for
	typedefs as all typedef changes are now local.
	* tests/data/test-diff-filter/test-PR26309-report-0.txt: Add new
	test reference output.
	* tests/data/test-diff-filter/test-PR26309-v{0,1}.o: Add new test
	binary input.
	* tests/data/test-diff-filter/test-PR26309-v{0,1}.c: Add source
	code for new test binary input.
	* tests/data/Makefile.am: Add the new text material above to
	source distribution.
	* tests/test-diff-filter.cc (in_out_specs): Add the new test input
	above to this test harness.
	* tests/data/test-diff-pkg/spice-server-0.12.4-19.el7.x86_64-0.12.8-1.el7.x86_64-report-3.txt: Adjust.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2020-09-15 08:51:58 +02:00

348 lines
9.2 KiB
C++

// -*- Mode: C++ -*-
//
// Copyright (C) 2017-2020 Red Hat, Inc.
//
// This file is part of the GNU Application Binary Interface Generic
// Analysis and Instrumentation Library (libabigail). This library is
// free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 3, or (at your option) any
// later version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this program; see the file COPYING-LGPLV3. If
// not, see <http://www.gnu.org/licenses/>.
//
// Author: Dodji Seketeli
/// @file
///
/// The declaration of the reporting types of libabigail's diff
/// engine.
#ifndef __ABG_REPORTER_H__
#define __ABG_REPORTER_H__
#include <ostream>
#include <string>
#include "abg-cxx-compat.h"
namespace abigail
{
using abg_compat::shared_ptr;
namespace comparison
{
class diff;
class type_decl_diff;
class enum_diff;
class typedef_diff;
class qualified_type_diff;
class distinct_diff;
class pointer_diff;
class reference_diff;
class array_diff;
class base_diff;
class class_or_union_diff;
class class_diff;
class union_diff;
class scope_diff;
class fn_parm_diff;
class function_type_diff;
class function_decl_diff;
class var_diff;
class translation_unit_diff;
class corpus_diff;
class diff_maps;
class reporter_base;
/// A convenience typedef for a shared pointer to a @ref
/// reporter_base.
typedef shared_ptr<reporter_base> reporter_base_sptr;
/// The base class of all the reporting classes.
class reporter_base
{
public:
virtual bool diff_to_be_reported(const diff *d) const;
virtual bool diff_has_net_changes(const corpus_diff *d) const = 0;
virtual void
report(const type_decl_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const enum_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const typedef_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const qualified_type_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const distinct_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const pointer_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const reference_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const array_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const base_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const class_or_union_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const class_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const union_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const scope_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const fn_parm_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const function_type_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const function_decl_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const var_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const translation_unit_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual void
report(const corpus_diff& d, std::ostream& out,
const std::string& indent = "") const = 0;
virtual ~reporter_base() {}
}; //end class reporter_base
class default_reporter;
/// A convenience typedef for a shared_ptr to a @ref default_reporter.
typedef shared_ptr<default_reporter> default_reporter_sptr;
/// The default, initial, reporter of the libabigail comparison engine.
class default_reporter : public reporter_base
{
public:
virtual bool diff_has_net_changes(const corpus_diff *d) const;
virtual void
report(const type_decl_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const enum_diff& d, std::ostream& out,
const std::string& indent = "") const;
void
report_non_type_typedef_changes(const typedef_diff &d,
std::ostream& out,
const std::string& indent) const;
virtual void
report(const typedef_diff& d, std::ostream& out,
const std::string& indent = "") const;
bool
report_local_qualified_type_changes(const qualified_type_diff& d,
std::ostream& out,
const std::string& indent) const;
virtual void
report(const qualified_type_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const pointer_diff& d, std::ostream& out,
const std::string& indent = "") const;
void
report_local_reference_type_changes(const reference_diff& d,
std::ostream& out,
const std::string& indent) const;
virtual void
report(const reference_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const fn_parm_diff& d, std::ostream& out,
const std::string& indent = "") const;
void
report_local_function_type_changes(const function_type_diff& d,
std::ostream& out,
const std::string& indent) const;
virtual void
report(const function_type_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const array_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const base_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const scope_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const class_or_union_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const class_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const union_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const distinct_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const function_decl_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const var_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const translation_unit_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const corpus_diff& d, std::ostream& out,
const std::string& indent = "") const;
}; // end class default_reporter
/// A reporter that only reports leaf changes
class leaf_reporter : public default_reporter
{
public:
virtual bool diff_to_be_reported(const diff *d) const;
virtual bool diff_has_net_changes(const corpus_diff *d) const;
void
report_changes_from_diff_maps(const diff_maps&, std::ostream& out,
const std::string& indent) const;
virtual void
report(const typedef_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const qualified_type_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const pointer_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const reference_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const fn_parm_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const function_type_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const array_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const scope_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const class_or_union_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const class_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const union_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const distinct_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const function_decl_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const var_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const translation_unit_diff& d, std::ostream& out,
const std::string& indent = "") const;
virtual void
report(const corpus_diff& d, std::ostream& out,
const std::string& indent = "") const;
}; // end class leaf_reporter
} // end namespace comparison
} // end namespace abigail
#endif // __ABG_REPORTER_H__