libabigail/include/abg-comparison.h
Dodji Seketeli aad0e11f50 comparison: Ensure that fn parms with basic types can't be redundant
When comparing the two libc binaries from
"https://the.owo.foundation/Ac1Ksw8.tgz", abidiff crashes.

It appears to be due to an assert that is hit because the overload of
default_reporter::report for fn_parm_diff momentarily removes the
redundant-ness from the categorization of the diff node of the type of
a function parameter.  The problem is that the sole child diff node of
that type diff node is itself redundant.  So the function parameter
type diff node should really be redundant too.  Oops, there is a logic
violation there, hence the assert violation.

I commented out the line that removes the redundant-ness.  After all,
if function parameter types shouldn't be redundant, that should have
been taken care of by the redundancy_marking_visitor code in
abg-comparison.cc as well as its associated category propagation code.

But then consider what happens with a reproducer of the libc binaries
above:

	$ cat test-PR29387-v0.c
	typedef int Integer;

	void
	f0(Integer i, char c)
	{
	  i + c;
	}

	void
	f1(Integer i, unsigned char c)
	{
	  i + c;
	}

	$
	$ cat test-PR29387-v1.c
	typedef long int Integer;

	void
	f0(Integer i, char c)
	{
	  i + c;
	}

	void
	f1(Integer i, unsigned char c)
	{
	  i + c;
	}

	$ gcc -g test-PR29387-v0.c
	$ gcc -g test-PR29387-v1.c
	$
	$ abidiff test-PR29387-v0.o test-PR29387-v1.o
	Functions changes summary: 0 Removed, 2 Changed, 0 Added functions
	Variables changes summary: 0 Removed, 0 Changed, 0 Added variable

	2 functions with some indirect sub-type change:

	  [C] 'function void f0(Integer, char)' at PR29387-test-v1.c:4:1 has some indirect sub-type changes:
	    parameter 1 of type 'typedef Integer' changed:
	      underlying type 'int' changed:
		type name changed from 'int' to 'long int'
		type size changed from 32 to 64 (in bits)

	  [C] 'function void f1(Integer, unsigned char)' at PR29387-test-v1.c:10:1 has some indirect sub-type changes:
	$
	$

So, the problem is this peace of report:

	  [C] 'function void f1(Integer, unsigned char)' at PR29387-test-v1.c:10:1 has some indirect sub-type changes:

You see that the report is empty; the reporter could not say what changed.

What changed is the typedef "Integer" that changed from "int" to "long
int".  The redundancy_marking_visitor pass marked the change of the
underlying type of the Integer typedef as being redundant.  This is
because that typedef change has already been reported on the f0
function interface.

The problem is that by design, the 'int' to 'long int' change should
not have been marked as being redundant by the
redundancy_marking_visitor pass.  This is because, we want to see all
the "basic type changes" on function parameters types.  They are
deemed "local changes" of the function types, and we want to see all
local changes to functions because it is almost 100% sure these are
non-compatible changes.

The root cause of the problem is that the function
has_basic_type_change_only in abg-comparison.cc fails to detect that
the parameter change carries a typedef-to-basic-type change, so the
function parameter is wrongly marked as being redundant even though it
ultimately carries a basic type change.

This patch thus teaches has_basic_type_change_only to look through
parameter changes to better detect basic type changes.

	* include/abg-comparison.h (peel_fn_parm_diff)
	(peel_typedef_qualified_type_or_parameter_diff): Declare ...
	* src/abg-comparison.cc (peel_fn_parm_diff)
	(peel_typedef_qualified_type_or_parameter_diff): ... new
	functions.
	(has_basic_type_change_only): Look through function parameters,
	typedefs and qualified types.
	* src/abg-default-reporter.cc (default_reporter::report): Remove
	the temporary removal of the redundant categorisation.
	Redundant-ness should have been handled by the
	redundancy_marking_visitor pass.
	* tests/data/test-diff-filter/test-PR29387-report.txt: Reference
	test output.
	* tests/data/test-diff-filter/test-PR29387-v{0,1}.c: Source of the
	input tests.
	* tests/data/test-diff-filter/test-PR29387-v{0,1}.o: Input test
	binaries.
	* tests/data/Makefile.am: Add the new test material above to the
	source distribution.
	* tests/test-diff-filter.cc (in_out_specs): Add the test binaries
	above to the test harness.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2022-09-22 01:46:20 +02:00

2879 lines
67 KiB
C++

// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- Mode: C++ -*-
//
// Copyright (C) 2013-2022 Red Hat, Inc.
//
// Author: Dodji Seketeli
#ifndef __ABG_COMPARISON_H__
#define __ABG_COMPARISON_H__
/// @file
#include <memory>
#include <ostream>
#include <unordered_map>
#include <unordered_set>
#include "abg-corpus.h"
#include "abg-diff-utils.h"
#include "abg-reporter.h"
namespace abigail
{
/// @brief utilities to compare abi artifacts
///
/// The main entry points of the namespace are the compute_diff()
/// overloads used to compute the difference between two abi artifacts.
namespace comparison
{
namespace filtering
{
struct filter_base;
typedef shared_ptr<filter_base> filter_base_sptr;
typedef std::vector<filter_base_sptr> filters;
}
// Inject types we need into this namespace.
using std::ostream;
using std::vector;
using std::unordered_map;
using std::unordered_set;
using std::pair;
using diff_utils::insertion;
using diff_utils::deletion;
using diff_utils::edit_script;
class diff;
/// Convenience typedef for a shared_ptr for the @ref diff class
typedef shared_ptr<diff> diff_sptr;
/// Convenience typedef for a weak_ptr for the @ref diff class
typedef weak_ptr<diff> diff_wptr;
/// Hasher for @ref diff_sptr.
struct diff_sptr_hasher
{
/// The actual hashing functor.
size_t
operator()(const diff_sptr& t) const
{return reinterpret_cast<size_t>(t.get());}
}; // end struct diff_sptr_hasher
/// Convenience typedef for a vector of @ref diff_sptr.
typedef vector<diff_sptr> diff_sptrs_type;
/// Convenience typedef for a vector of @ref diff*.
typedef vector<diff*> diff_ptrs_type;
/// Convenience typedef for an unoredered set of @ref diff_sptr
typedef unordered_set<diff_sptr, diff_sptr_hasher> unordered_diff_sptr_set;
class decl_diff_base;
/// Convenience typedef for a shared_ptr of @ref decl_diff_base.
typedef shared_ptr<decl_diff_base> decl_diff_base_sptr;
/// Convenience typedef for a vector of @ref decl_diff_base_sptr.
typedef vector<decl_diff_base_sptr> decl_diff_base_sptrs_type;
class type_diff_base;
/// Convenience pointer for a shared pointer to a type_diff_base
typedef shared_ptr<type_diff_base> type_diff_base_sptr;
/// Convenience typedef for a vector of @ref type_diff_base_sptr
typedef vector<type_diff_base_sptr> type_diff_base_sptrs_type;
class function_decl_diff;
/// Convenience typedef for a shared pointer to a @ref function_decl type.
typedef shared_ptr<function_decl_diff> function_decl_diff_sptr;
/// Convenience typedef for a vector of @ref function_decl_diff_sptr
typedef vector<function_decl_diff_sptr> function_decl_diff_sptrs_type;
class fn_parm_diff;
/// Convenience typedef for a shared pointer to a @ref fn_parm_diff
/// type.
typedef shared_ptr<fn_parm_diff> fn_parm_diff_sptr;
class var_diff;
/// Convenience typedef for a shared pointer to a @ref var_diff type.
typedef shared_ptr<var_diff> var_diff_sptr;
/// Convenience typedef for a vector of @ref var_diff_sptr.
typedef vector<var_diff_sptr> var_diff_sptrs_type;
class base_diff;
/// Convenience typedef for a shared pointer to a @ref base_diff type.
typedef shared_ptr<base_diff> base_diff_sptr;
/// Convenience typedef for a vector of @ref base_diff_sptr.
typedef vector<base_diff_sptr> base_diff_sptrs_type;
class class_diff;
/// Convenience typedef for a shared pointer on a @ref class_diff type.
typedef shared_ptr<class_diff> class_diff_sptr;
/// Convenience typedef for a map of pointer values. The Key is a
/// pointer value and the value is potentially another pointer value
/// associated to the first one.
typedef unordered_map<size_t, size_t> pointer_map;
/// Convenience typedef for a map which key is a string and which
/// value is a @ref decl_base_sptr.
typedef unordered_map<string, decl_base_sptr> string_decl_base_sptr_map;
/// Convenience typedef for a map which key is a string and which
/// value is a @ref type_base_sptr.
typedef unordered_map<string, type_base_sptr> string_type_base_sptr_map;
/// Convenience typedef for a map which key is an unsigned integer and
/// which value is a @ref decl_base_sptr
typedef unordered_map<unsigned, decl_base_sptr> unsigned_decl_base_sptr_map;
/// Convenience typedef for a map of string and class_decl::basse_spec_sptr.
typedef unordered_map<string, class_decl::base_spec_sptr> string_base_sptr_map;
/// Convenience typedef for a map of string and @ref base_diff_sptr.
typedef unordered_map<string, base_diff_sptr> string_base_diff_sptr_map;
/// Convenience typedef for a map which value is a changed function
/// parameter and which key is the name of the function parameter.
typedef unordered_map<string, fn_parm_diff_sptr> string_fn_parm_diff_sptr_map;
/// Convenience typedef for a map which key is an integer and which
/// value is a changed parameter.
typedef unordered_map<unsigned, fn_parm_diff_sptr>
unsigned_fn_parm_diff_sptr_map;
/// Convenience typedef for a map which key is an integer and which
/// value is a parameter.
typedef unordered_map<unsigned,
function_decl::parameter_sptr> unsigned_parm_map;
/// Convenience typedef for a map which value is a
/// type_diff_base_sptr. The key of the map is the qualified name of
/// the changed type.
typedef unordered_map<string,
type_diff_base_sptr> string_type_diff_base_sptr_map;
/// Convenience typedef for a map which value is a
/// decl_diff_base_sptr. The key of the map is the qualified name of
/// the changed type.
typedef unordered_map<string,
decl_diff_base_sptr> string_decl_diff_base_sptr_map;
/// Convenience typedef for a map which value is a diff_sptr. The key
/// of the map is the qualified name of the changed type.
typedef unordered_map<string, diff_sptr> string_diff_sptr_map;
/// Convenience typedef for a map which value is a diff*. The key of
/// the map is the qualified name of the changed type.
typedef unordered_map<string, diff*> string_diff_ptr_map;
/// Convenience typedef for a map whose key is a string and whose
/// value is a changed variable of type @ref var_diff_sptr.
typedef unordered_map<string,
var_diff_sptr> string_var_diff_sptr_map;
/// Convenience typedef for a map whose key is an unsigned int and
/// whose value is a changed variable of type @ref var_diff_sptr.
typedef unordered_map<unsigned, var_diff_sptr> unsigned_var_diff_sptr_map;
/// Convenience typedef for a map which value is a function
/// parameter. The key is the name of the function parm.
typedef unordered_map<string, function_decl::parameter_sptr> string_parm_map;
/// Convenience typedef for a map which value is an enumerator. The
/// key is the name of the enumerator.
typedef unordered_map<string, enum_type_decl::enumerator> string_enumerator_map;
/// Convenience typedef for a changed enumerator. The first element
/// of the pair is the old enumerator and the second one is the new enumerator.
typedef std::pair<enum_type_decl::enumerator,
enum_type_decl::enumerator> changed_enumerator;
/// Convenience typedef for a vector of changed enumerators.
typedef vector<changed_enumerator> changed_enumerators_type;
/// Convenience typedef for a map which value is a changed enumerator.
/// The key is the name of the changed enumerator.
typedef unordered_map<string, changed_enumerator> string_changed_enumerator_map;
/// Convenience typedef for a map which key is a string and which
/// value is a pointer to @ref decl_base.
typedef unordered_map<string, function_decl*> string_function_ptr_map;
/// Convenience typedef for a map which key is a string and which
/// value is a @ref function_decl_diff_sptr.
typedef unordered_map<string,
function_decl_diff_sptr>
string_function_decl_diff_sptr_map;
/// Convenience typedef for a pair of class_decl::member_function_sptr
/// representing a changed member function. The first element of the
/// pair is the initial member function and the second element is the
/// changed one.
typedef pair<method_decl_sptr,
method_decl_sptr> changed_member_function_sptr;
/// Convenience typedef for a hash map of strings and changed member functions.
typedef unordered_map<string,
changed_member_function_sptr>
string_changed_member_function_sptr_map;
/// Convenience typedef for a hash map of strings and member functions.
typedef unordered_map<string, method_decl_sptr> string_member_function_sptr_map;
/// Convenience typedef for a map which key is a string and which
/// value is a point to @ref var_decl.
typedef unordered_map<string, var_decl*> string_var_ptr_map;
/// Convenience typedef for a pair of pointer to @ref var_decl
/// representing a @ref var_decl change. The first member of the pair
/// represents the initial variable and the second member represents
/// the changed variable.
typedef std::pair<var_decl*, var_decl*> changed_var_ptr;
/// Convenience typedef for a pair of @ref var_decl_sptr representing
/// a @ref var_decl change. The first member of the pair represents
/// the initial variable and the second member represents the changed
/// variable.
typedef std::pair<var_decl_sptr, var_decl_sptr> changed_var_sptr;
/// Convenience typedef for a vector of @changed_var_sptr.gg381
typedef vector<changed_var_sptr> changed_var_sptrs_type;
/// Convenience typedef for a map whose key is a string and whose
/// value is an @ref elf_symbol_sptr.
typedef unordered_map<string, elf_symbol_sptr> string_elf_symbol_map;
/// Convenience typedef for a map which key is a string and which
/// value is a @ref var_diff_sptr.
typedef unordered_map<string, var_diff_sptr> string_var_diff_ptr_map;
class diff_context;
/// Convenience typedef for a shared pointer of @ref diff_context.
typedef shared_ptr<diff_context> diff_context_sptr;
/// Convenience typedef for a weak pointer of @ref diff_context.
typedef weak_ptr<diff_context> diff_context_wptr;
class diff_node_visitor;
class diff_traversable_base;
/// Convenience typedef for shared_ptr on diff_traversable_base.
typedef shared_ptr<diff_traversable_base> diff_traversable_base_sptr;
/// An enum for the different ways to visit a diff tree node.
///
/// This is used by the node traversing code, to know when to avoid
/// visiting children nodes, for instance.
enum visiting_kind
{
/// The default enumerator value of this enum. It doesn't have any
/// particular meaning yet.
DEFAULT_VISITING_KIND = 0,
/// This says that the traversing code should avoid visiting the
/// children nodes of the current node being visited.
SKIP_CHILDREN_VISITING_KIND = 1,
/// This says that the traversing code should not mark visited nodes
/// as having been traversed. This is useful, for instance, for
/// visitors which have debugging purposes.
DO_NOT_MARK_VISITED_NODES_AS_VISITED = 1 << 1
};
visiting_kind
operator|(visiting_kind l, visiting_kind r);
visiting_kind
operator&(visiting_kind l, visiting_kind r);
visiting_kind
operator~(visiting_kind l);
/// The base class for the diff classes that are to be traversed.
class diff_traversable_base : public traversable_base
{
public:
virtual bool
traverse(diff_node_visitor& v);
}; // end struct diff_traversable_base
/// An enum for the different categories that a diff tree node falls
/// into, regarding the kind of changes it represents.
///
/// Note that if you add an enumerator to this enum, you need to
/// update a few spots accordingly:
///
/// * update the ACCESS_CHANGE_CATEGORY enumerator (which is the
/// last enumerator of this enum by OR-ing its initializer with
/// the new enumerator.
///
/// * update the categorize_harmless_diff_node or
/// categorize_harmful_diff_node function depending on if the new
/// enumerator classifies diff nodes as harmless or harmful.
///
/// * update the get_default_harmless_categories_bitmap or
/// get_default_harmful_categories_bitmap function as well, just
/// like above.
///
/// * update the "operator<<(ostream& o, diff_category c)" streaming
/// operator so that it can stream the new enumerator to a textual
/// output stream.
enum diff_category
{
/// This means the diff node does not carry any (meaningful) change,
/// or that it carries changes that have not yet been categorized.
NO_CHANGE_CATEGORY = 0,
/// This means the diff node (or at least one of its descendant
/// nodes) carries access related changes, e.g, a private member
/// that becomes public.
ACCESS_CHANGE_CATEGORY = 1,
/// This means the diff node (or at least one of its descendant
/// nodes) carries a change involving two compatible types. For
/// instance a type and its typedefs.
COMPATIBLE_TYPE_CHANGE_CATEGORY = 1 << 1,
/// This means that a diff node in the sub-tree carries a harmless
/// declaration name change. This is set only for name changes for
/// data members and typedefs.
HARMLESS_DECL_NAME_CHANGE_CATEGORY = 1 << 2,
/// This means that a diff node in the sub-tree carries an addition
/// or removal of a non-virtual member function.
NON_VIRT_MEM_FUN_CHANGE_CATEGORY = 1 << 3,
/// This means that a diff node in the sub-tree carries an addition
/// or removal of a static data member.
STATIC_DATA_MEMBER_CHANGE_CATEGORY = 1 << 4,
/// This means that a diff node in the sub-tree carries an addition
/// of enumerator to an enum type.
HARMLESS_ENUM_CHANGE_CATEGORY = 1 << 5,
/// This means that a diff node in the sub-tree carries an a symbol
/// alias change that is harmless.
HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY = 1 << 6,
/// This means that a diff node in the sub-tree carries a harmless
/// union change.
HARMLESS_UNION_CHANGE_CATEGORY = 1 << 7,
/// This means that a diff node in the sub-tree carries a harmless
/// data member change. An example of harmless data member change
/// is an anonymous data member that replaces a given data member
/// without locally changing the layout.
HARMLESS_DATA_MEMBER_CHANGE_CATEGORY = 1 << 8,
/// This means that a diff node was marked as suppressed by a
/// user-provided suppression specification.
SUPPRESSED_CATEGORY = 1 << 9,
/// This means that a diff node was warked as being for a private
/// type. That is, the diff node is meant to be suppressed by a
/// suppression specification that was auto-generated to filter out
/// changes to private types.
PRIVATE_TYPE_CATEGORY = 1 << 10,
/// This means the diff node (or at least one of its descendant
/// nodes) carries a change that modifies the size of a type or an
/// offset of a type member. Removal or changes of enumerators in a
/// enum fall in this category too.
SIZE_OR_OFFSET_CHANGE_CATEGORY = 1 << 11,
/// This means that a diff node in the sub-tree carries an
/// incompatible change to a vtable.
VIRTUAL_MEMBER_CHANGE_CATEGORY = 1 << 12,
/// A diff node in this category is redundant. That means it's
/// present as a child of a other nodes in the diff tree.
REDUNDANT_CATEGORY = 1 << 13,
/// This means that a diff node in the sub-tree carries a type that
/// was declaration-only and that is now defined, or vice versa.
TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY = 1 << 14,
/// A diff node in this category is a function parameter type which
/// top cv-qualifiers change.
FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY = 1 << 15,
/// A diff node in this category has a function parameter type with a
/// cv-qualifiers change.
FN_PARM_TYPE_CV_CHANGE_CATEGORY = 1 << 16,
/// A diff node in this category is a function return type with a
/// cv-qualifier change.
FN_RETURN_TYPE_CV_CHANGE_CATEGORY = 1 << 17,
/// A diff node in this category is a function (or function type)
/// with at least one parameter added or removed.
FN_PARM_ADD_REMOVE_CHANGE_CATEGORY = 1 << 18,
/// A diff node in this category is for a variable which type holds
/// a cv-qualifier change.
VAR_TYPE_CV_CHANGE_CATEGORY = 1 << 19,
/// A diff node in this category carries a change from void pointer
/// to non-void pointer.
VOID_PTR_TO_PTR_CHANGE_CATEGORY = 1 << 20,
/// A diff node in this category carries a change in the size of the
/// array type of a global variable, but the ELF size of the
/// variable didn't change.
BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY = 1 << 21,
/// A special enumerator that is the logical 'or' all the
/// enumerators above.
///
/// This one must stay the last enumerator. Please update it each
/// time you add a new enumerator above.
EVERYTHING_CATEGORY =
ACCESS_CHANGE_CATEGORY
| COMPATIBLE_TYPE_CHANGE_CATEGORY
| HARMLESS_DECL_NAME_CHANGE_CATEGORY
| NON_VIRT_MEM_FUN_CHANGE_CATEGORY
| STATIC_DATA_MEMBER_CHANGE_CATEGORY
| HARMLESS_ENUM_CHANGE_CATEGORY
| HARMLESS_SYMBOL_ALIAS_CHANGE_CATEGORY
| HARMLESS_UNION_CHANGE_CATEGORY
| HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
| SUPPRESSED_CATEGORY
| PRIVATE_TYPE_CATEGORY
| SIZE_OR_OFFSET_CHANGE_CATEGORY
| VIRTUAL_MEMBER_CHANGE_CATEGORY
| REDUNDANT_CATEGORY
| TYPE_DECL_ONLY_DEF_CHANGE_CATEGORY
| FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
| FN_PARM_TYPE_CV_CHANGE_CATEGORY
| FN_RETURN_TYPE_CV_CHANGE_CATEGORY
| FN_PARM_ADD_REMOVE_CHANGE_CATEGORY
| VAR_TYPE_CV_CHANGE_CATEGORY
| VOID_PTR_TO_PTR_CHANGE_CATEGORY
| BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY
}; // enum diff_category
diff_category
operator|(diff_category c1, diff_category c2);
diff_category&
operator|=(diff_category& c1, diff_category c2);
diff_category&
operator&=(diff_category& c1, diff_category c2);
diff_category
operator^(diff_category c1, diff_category c2);
diff_category
operator&(diff_category c1, diff_category c2);
diff_category
operator~(diff_category c);
diff_category
get_default_harmless_categories_bitmap();
diff_category
get_default_harmful_categories_bitmap();
ostream&
operator<<(ostream& o, diff_category);
class corpus_diff;
/// This type contains maps. Each map associates a type name to a
/// diff of that type. Not all kinds of diffs are present; only those
/// that carry leaf changes are, for now.
class diff_maps
{
struct priv;
std::unique_ptr<priv> priv_;
public:
diff_maps();
~diff_maps();
const string_diff_ptr_map&
get_type_decl_diff_map() const;
string_diff_ptr_map&
get_type_decl_diff_map();
const string_diff_ptr_map&
get_enum_diff_map() const;
string_diff_ptr_map&
get_enum_diff_map();
const string_diff_ptr_map&
get_class_diff_map() const;
string_diff_ptr_map&
get_class_diff_map();
const string_diff_ptr_map&
get_union_diff_map() const;
string_diff_ptr_map&
get_union_diff_map();
const string_diff_ptr_map&
get_typedef_diff_map() const;
string_diff_ptr_map&
get_typedef_diff_map();
const string_diff_ptr_map&
get_array_diff_map() const;
string_diff_ptr_map&
get_array_diff_map();
const string_diff_ptr_map&
get_reference_diff_map() const;
string_diff_ptr_map&
get_reference_diff_map();
const string_diff_ptr_map&
get_fn_parm_diff_map() const;
string_diff_ptr_map&
get_fn_parm_diff_map();
const string_diff_ptr_map&
get_function_type_diff_map() const;
string_diff_ptr_map&
get_function_type_diff_map();
const string_diff_ptr_map&
get_function_decl_diff_map() const;
string_diff_ptr_map&
get_function_decl_diff_map();
const string_diff_ptr_map&
get_var_decl_diff_map() const;
string_diff_ptr_map&
get_var_decl_diff_map();
const string_diff_ptr_map&
get_distinct_diff_map() const;
string_diff_ptr_map&
get_distinct_diff_map();
bool
insert_diff_node(const diff *d,
const type_or_decl_base_sptr& impacted_iface);
artifact_sptr_set_type*
lookup_impacted_interfaces(const diff *d) const;
}; // end class diff_maps
/// A convenience typedef for a shared pointer to @ref corpus_diff.
typedef shared_ptr<corpus_diff> corpus_diff_sptr;
/// The context of the diff. This type holds various bits of
/// information that is going to be used throughout the diffing of two
/// entities and the reporting that follows.
class diff_context
{
struct priv;
std::unique_ptr<priv> priv_;
diff_sptr
has_diff_for(const type_or_decl_base_sptr first,
const type_or_decl_base_sptr second) const;
diff_sptr
has_diff_for_types(const type_base_sptr first,
const type_base_sptr second) const;
const diff*
has_diff_for(const diff* d) const;
diff_sptr
has_diff_for(const diff_sptr d) const;
void
add_diff(const type_or_decl_base_sptr first,
const type_or_decl_base_sptr second,
const diff_sptr d);
void
add_diff(const diff_sptr d);
void
add_diff(const diff* d);
void
set_canonical_diff_for(const type_or_decl_base_sptr first,
const type_or_decl_base_sptr second,
const diff_sptr);
diff_sptr
set_or_get_canonical_diff_for(const type_or_decl_base_sptr first,
const type_or_decl_base_sptr second,
const diff_sptr canonical_diff);
public:
diff_context();
~diff_context();
void
set_corpus_diff(const corpus_diff_sptr&);
const corpus_diff_sptr&
get_corpus_diff() const;
corpus_sptr
get_first_corpus() const;
corpus_sptr
get_second_corpus() const;
reporter_base_sptr
get_reporter() const;
void
set_reporter(reporter_base_sptr&);
diff_sptr
get_canonical_diff_for(const type_or_decl_base_sptr first,
const type_or_decl_base_sptr second) const;
diff_sptr
get_canonical_diff_for(const diff_sptr d) const;
void
initialize_canonical_diff(const diff_sptr diff);
void
keep_diff_alive(diff_sptr&);
diff*
diff_has_been_visited(const diff*) const;
diff_sptr
diff_has_been_visited(const diff_sptr) const;
void
mark_diff_as_visited(const diff*);
void
forget_visited_diffs();
void
mark_last_diff_visited_per_class_of_equivalence(const diff*);
void
clear_last_diffs_visited_per_class_of_equivalence();
const diff*
get_last_visited_diff_of_class_of_equivalence(const diff*);
void
forbid_visiting_a_node_twice(bool f);
bool
visiting_a_node_twice_is_forbidden() const;
void
forbid_visiting_a_node_twice_per_interface(bool);
bool
visiting_a_node_twice_is_forbidden_per_interface() const;
diff_category
get_allowed_category() const;
void
set_allowed_category(diff_category c);
void
switch_categories_on(diff_category c);
void
switch_categories_off(diff_category c);
const filtering::filters&
diff_filters() const;
void
add_diff_filter(filtering::filter_base_sptr);
void
maybe_apply_filters(diff_sptr diff);
void
maybe_apply_filters(corpus_diff_sptr diff);
suppr::suppressions_type&
suppressions() const;
void
add_suppression(const suppr::suppression_sptr suppr);
void
add_suppressions(const suppr::suppressions_type& supprs);
void
show_leaf_changes_only(bool f);
bool
show_leaf_changes_only() const;
bool
show_hex_values() const;
void
show_hex_values(bool f);
bool
show_offsets_sizes_in_bits() const;
void
show_offsets_sizes_in_bits(bool f);
void
show_relative_offset_changes(bool f);
bool
show_relative_offset_changes(void);
void
show_stats_only(bool f);
bool
show_stats_only() const;
void
show_soname_change(bool f);
bool
show_soname_change() const;
void
show_architecture_change(bool f);
bool
show_architecture_change() const;
void
show_deleted_fns(bool f);
bool
show_deleted_fns() const;
void
show_changed_fns(bool f);
bool
show_changed_fns() const;
void
show_added_fns(bool f);
bool
show_added_fns() const;
void
show_deleted_vars(bool f);
bool
show_deleted_vars() const;
void
show_changed_vars(bool f);
bool
show_changed_vars() const;
void
show_added_vars(bool f);
bool
show_added_vars() const;
bool
show_linkage_names() const;
void
show_linkage_names(bool f);
bool
show_locs() const;
void
show_locs(bool f);
bool
show_redundant_changes() const;
void
show_redundant_changes(bool f);
bool
show_symbols_unreferenced_by_debug_info() const;
void
show_symbols_unreferenced_by_debug_info(bool f);
bool
show_added_symbols_unreferenced_by_debug_info() const;
void
show_added_symbols_unreferenced_by_debug_info(bool f);
void show_unreachable_types(bool f);
bool show_unreachable_types();
bool
show_impacted_interfaces() const;
void
show_impacted_interfaces(bool f);
void
default_output_stream(ostream*);
ostream*
default_output_stream();
void
error_output_stream(ostream*);
ostream*
error_output_stream() const;
bool
dump_diff_tree() const;
void
dump_diff_tree(bool f);
void
do_dump_diff_tree(const diff_sptr) const;
void
do_dump_diff_tree(const corpus_diff_sptr) const;
friend class_diff_sptr
compute_diff(const class_decl_sptr first,
const class_decl_sptr second,
diff_context_sptr ctxt);
};//end struct diff_context.
/// The abstraction of a change between two ABI artifacts, a.k.a an
/// artifact change.
///
/// In the grand scheme of things, a diff is strongly typed; for
/// instance, a change between two enums is represented by an
/// enum_diff type. A change between two function_type is represented
/// by a function_type_diff type and a change between two class_decl
/// is represented by a class_diff type. All of these types derive
/// from the @ref diff parent class.
///
/// An artifact change D can have one (or more) details named D'. A
/// detail is an artifact change that "belongs" to another one. Here,
/// D' belongs to D. Or said otherwise, D' is a child change of D.
/// Said otherwise, D and D' are related, and the relation is a
/// "child relation".
///
/// For instance, if we consider a change carried by a class_diff, the
/// detail change might be a change on one data member of the class.
/// In other word, the class_diff change might have a child diff node
/// that would be a var_diff node.
///
/// There are two ways to get the child var_diff node (for the data
/// member change detail) of the class_diff.
///
/// The first way is through the typed API, that is, through the
/// class_diff::sorted_changed_data_members() member function which
/// returns var_diff nodes.
///
/// The second way is through the generic API, that is, through the
/// diff::children_nodes() member function which returns generic diff
/// nodes. This second way enables us to walk the diff nodes graph in
/// a generic way, regardless of the types of the diff nodes.
///
/// Said otherwise, there are two views for a given diff node. There
/// is typed view, and there is the generic view. In the typed view,
/// the details are accessed through the typed API. In the generic
/// view, the details are gathered through the generic view.
///
///
/// Please read more about the @ref DiffNode "IR" of the comparison
/// engine to learn more about this.
///
/// This type encapsulates an edit script (a set of insertions and
/// deletions) for two constructs that are to be diff'ed. The two
/// constructs are called the "subjects" of the diff.
class diff : public diff_traversable_base
{
friend class diff_context;
// Forbidden
diff();
protected:
struct priv;
std::unique_ptr<priv> priv_;
diff(type_or_decl_base_sptr first_subject,
type_or_decl_base_sptr second_subject);
diff(type_or_decl_base_sptr first_subject,
type_or_decl_base_sptr second_subject,
diff_context_sptr ctxt);
void
begin_traversing();
void
end_traversing();
virtual void
finish_diff_type();
void
set_canonical_diff(diff *);
public:
type_or_decl_base_sptr
first_subject() const;
type_or_decl_base_sptr
second_subject() const;
const vector<diff*>&
children_nodes() const;
const diff*
parent_node() const;
diff* get_canonical_diff() const;
bool
is_traversing() const;
void
append_child_node(diff_sptr);
const diff_context_sptr
context() const;
void
context(diff_context_sptr c);
bool
currently_reporting() const;
void
currently_reporting(bool f) const;
bool
reported_once() const;
void
reported_once(bool f) const;
diff_category
get_category() const;
diff_category
get_local_category() const;
diff_category
get_class_of_equiv_category() const;
diff_category
add_to_category(diff_category c);
diff_category
add_to_local_category(diff_category c);
void
add_to_local_and_inherited_categories(diff_category c);
diff_category
remove_from_category(diff_category c);
diff_category
remove_from_local_category(diff_category c);
void
set_category(diff_category c);
void
set_local_category(diff_category c);
bool
is_filtered_out() const;
bool
is_filtered_out_wrt_non_inherited_categories() const;
bool
is_suppressed() const;
bool
is_suppressed(bool &is_private_type) const;
bool
to_be_reported() const;
bool
has_local_changes_to_be_reported() const;
virtual const string&
get_pretty_representation() const;
/// This constructs the relation between this diff node and its
/// detail diff nodes, in the generic view of the diff node.
///
/// Each specific typed diff node should implement how the typed
/// view "links" itself to its detail nodes in the generic sense.
virtual void
chain_into_hierarchy();
/// Pure interface to get the length of the changes encapsulated by
/// this diff. A length of zero means that the current instance of
/// @ref diff doesn't carry any change.
///
/// This is to be implemented by all descendants of this type.
virtual bool
has_changes() const = 0;
/// Pure interface to know if the current instance of @diff carries
/// a local change. A local change is a change that is on the @ref
/// diff object itself, as opposed to a change that is carried by
/// some of its children nodes.
///
/// This is to be implemented by all descendants of this type.
virtual enum change_kind
has_local_changes() const = 0;
/// Pure interface to report the diff in a serialized form that is
/// legible for the user.
///
/// Note that the serializd report has to leave one empty line at
/// the end of its content.
///
/// @param out the output stream to serialize the report to.
///
/// @param indent the indentation string to use.
virtual void
report(ostream& out, const string& indent = "") const = 0;
virtual bool
traverse(diff_node_visitor& v);
};// end class diff
diff_sptr
compute_diff(const decl_base_sptr,
const decl_base_sptr,
diff_context_sptr ctxt);
diff_sptr
compute_diff(const type_base_sptr,
const type_base_sptr,
diff_context_sptr ctxt);
/// The base class of diff between types.
class type_diff_base : public diff
{
struct priv;
std::unique_ptr<priv> priv_;
type_diff_base();
protected:
type_diff_base(type_base_sptr first_subject,
type_base_sptr second_subject,
diff_context_sptr ctxt);
public:
virtual enum change_kind
has_local_changes() const = 0;
virtual ~type_diff_base();
};// end class type_diff_base
/// The base class of diff between decls.
class decl_diff_base : public diff
{
struct priv;
std::unique_ptr<priv> priv_;
protected:
decl_diff_base(decl_base_sptr first_subject,
decl_base_sptr second_subject,
diff_context_sptr ctxt);
public:
virtual enum change_kind
has_local_changes() const = 0;
virtual ~decl_diff_base();
};// end class decl_diff_base
string
get_pretty_representation(diff*);
class distinct_diff;
/// Convenience typedef for a shared pointer to distinct_types_diff
typedef shared_ptr<distinct_diff> distinct_diff_sptr;
/// An abstraction of a diff between entities that are of a different
/// kind (disctinct).
class distinct_diff : public diff
{
struct priv;
std::unique_ptr<priv> priv_;
protected:
distinct_diff(type_or_decl_base_sptr first,
type_or_decl_base_sptr second,
diff_context_sptr ctxt = diff_context_sptr());
public:
const type_or_decl_base_sptr
first() const;
const type_or_decl_base_sptr
second() const;
const diff_sptr
compatible_child_diff() const;
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream& out, const string& indent = "") const;
virtual void
chain_into_hierarchy();
static bool
entities_are_of_distinct_kinds(type_or_decl_base_sptr first,
type_or_decl_base_sptr second);
friend distinct_diff_sptr
compute_diff_for_distinct_kinds(const type_or_decl_base_sptr first,
const type_or_decl_base_sptr second,
diff_context_sptr ctxt);
};// end class distinct_types_diff
distinct_diff_sptr
compute_diff_for_distinct_kinds(const type_or_decl_base_sptr,
const type_or_decl_base_sptr,
diff_context_sptr ctxt);
/// Abstracts a diff between two instances of @ref var_decl
class var_diff : public decl_diff_base
{
struct priv;
std::unique_ptr<priv> priv_;
protected:
var_diff(var_decl_sptr first,
var_decl_sptr second,
diff_sptr type_diff,
diff_context_sptr ctxt = diff_context_sptr());
public:
var_decl_sptr
first_var() const;
var_decl_sptr
second_var() const;
diff_sptr
type_diff() const;
virtual void
chain_into_hierarchy();
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream& out, const string& indent = "") const;
virtual const string&
get_pretty_representation() const;
friend var_diff_sptr
compute_diff(const var_decl_sptr first,
const var_decl_sptr second,
diff_context_sptr ctxt);
};// end class var_diff
var_diff_sptr
compute_diff(const var_decl_sptr, const var_decl_sptr, diff_context_sptr);
class pointer_diff;
/// Convenience typedef for a shared pointer on a @ref
/// pointer_diff type.
typedef shared_ptr<pointer_diff> pointer_diff_sptr;
/// The abstraction of a diff between two pointers.
class pointer_diff : public type_diff_base
{
struct priv;
std::unique_ptr<priv> priv_;
protected:
pointer_diff(pointer_type_def_sptr first,
pointer_type_def_sptr second,
diff_sptr underlying_type_diff,
diff_context_sptr ctxt = diff_context_sptr());
public:
const pointer_type_def_sptr
first_pointer() const;
const pointer_type_def_sptr
second_pointer() const;
diff_sptr
underlying_type_diff() const;
void
underlying_type_diff(const diff_sptr);
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
friend pointer_diff_sptr
compute_diff(pointer_type_def_sptr first,
pointer_type_def_sptr second,
diff_context_sptr ctxt);
};// end class pointer_diff
pointer_diff_sptr
compute_diff(pointer_type_def_sptr first,
pointer_type_def_sptr second,
diff_context_sptr ctxt);
class reference_diff;
/// Convenience typedef for a shared pointer on a @ref
/// reference_diff type.
typedef shared_ptr<reference_diff> reference_diff_sptr;
/// The abstraction of a diff between two references.
class reference_diff : public type_diff_base
{
struct priv;
std::unique_ptr<priv> priv_;
protected:
reference_diff(const reference_type_def_sptr first,
const reference_type_def_sptr second,
diff_sptr underlying,
diff_context_sptr ctxt = diff_context_sptr());
public:
reference_type_def_sptr
first_reference() const;
reference_type_def_sptr
second_reference() const;
const diff_sptr&
underlying_type_diff() const;
diff_sptr&
underlying_type_diff(diff_sptr);
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
friend reference_diff_sptr
compute_diff(reference_type_def_sptr first,
reference_type_def_sptr second,
diff_context_sptr ctxt);
};// end class reference_diff
reference_diff_sptr
compute_diff(reference_type_def_sptr first,
reference_type_def_sptr second,
diff_context_sptr ctxt);
class array_diff;
/// Convenience typedef for a shared pointer on a @ref
/// array_diff type.
typedef shared_ptr<array_diff> array_diff_sptr;
/// The abstraction of a diff between two arrays.
class array_diff : public type_diff_base
{
struct priv;
std::unique_ptr<priv> priv_;
protected:
array_diff(const array_type_def_sptr first,
const array_type_def_sptr second,
diff_sptr element_type_diff,
diff_context_sptr ctxt = diff_context_sptr());
public:
const array_type_def_sptr
first_array() const;
const array_type_def_sptr
second_array() const;
const diff_sptr&
element_type_diff() const;
void
element_type_diff(diff_sptr);
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
friend array_diff_sptr
compute_diff(array_type_def_sptr first,
array_type_def_sptr second,
diff_context_sptr ctxt);
};// end class array_diff
array_diff_sptr
compute_diff(array_type_def_sptr first,
array_type_def_sptr second,
diff_context_sptr ctxt);
class qualified_type_diff;
typedef class shared_ptr<qualified_type_diff> qualified_type_diff_sptr;
/// Abstraction of a diff between two qualified types.
class qualified_type_diff : public type_diff_base
{
struct priv;
std::unique_ptr<priv> priv_;
protected:
qualified_type_diff(qualified_type_def_sptr first,
qualified_type_def_sptr second,
diff_sptr underling,
diff_context_sptr ctxt = diff_context_sptr());
public:
const qualified_type_def_sptr
first_qualified_type() const;
const qualified_type_def_sptr
second_qualified_type() const;
diff_sptr
underlying_type_diff() const;
void
underlying_type_diff(const diff_sptr);
diff_sptr
leaf_underlying_type_diff() const;
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
friend qualified_type_diff_sptr
compute_diff(const qualified_type_def_sptr first,
const qualified_type_def_sptr second,
diff_context_sptr ctxt);
};// end class qualified_type_diff.
qualified_type_diff_sptr
compute_diff(const qualified_type_def_sptr first,
const qualified_type_def_sptr second,
diff_context_sptr ctxt);
class enum_diff;
typedef shared_ptr<enum_diff> enum_diff_sptr;
/// Abstraction of a diff between two enums.
class enum_diff : public type_diff_base
{
struct priv;
std::unique_ptr<priv> priv_;
void
clear_lookup_tables();
bool
lookup_tables_empty() const;
void
ensure_lookup_tables_populated();
protected:
enum_diff(const enum_type_decl_sptr,
const enum_type_decl_sptr,
const diff_sptr,
diff_context_sptr ctxt = diff_context_sptr());
public:
const enum_type_decl_sptr
first_enum() const;
const enum_type_decl_sptr
second_enum() const;
diff_sptr
underlying_type_diff() const;
const string_enumerator_map&
deleted_enumerators() const;
const string_enumerator_map&
inserted_enumerators() const;
const string_changed_enumerator_map&
changed_enumerators() const;
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
friend enum_diff_sptr
compute_diff(const enum_type_decl_sptr first,
const enum_type_decl_sptr second,
diff_context_sptr ctxt);
};//end class enum_diff;
enum_diff_sptr
compute_diff(const enum_type_decl_sptr,
const enum_type_decl_sptr,
diff_context_sptr);
/// This is the base class of @ref class_diff and @ref union_diff.
class class_or_union_diff : public type_diff_base
{
protected:
struct priv;
typedef std::unique_ptr<priv> priv_ptr;
priv_ptr priv_;
void
clear_lookup_tables(void);
bool
lookup_tables_empty(void) const;
void
ensure_lookup_tables_populated(void) const;
void
allocate_priv_data();
protected:
class_or_union_diff(class_or_union_sptr first_scope,
class_or_union_sptr second_scope,
diff_context_sptr ctxt = diff_context_sptr());
public:
const class_or_union_diff::priv_ptr&
get_priv() const;
//TODO: add change of the name of the type.
virtual ~class_or_union_diff();
class_or_union_sptr
first_class_or_union() const;
class_or_union_sptr
second_class_or_union() const;
const edit_script&
member_types_changes() const;
edit_script&
member_types_changes();
const edit_script&
data_members_changes() const;
edit_script&
data_members_changes();
const string_decl_base_sptr_map&
inserted_data_members() const;
const string_decl_base_sptr_map&
deleted_data_members() const;
const edit_script&
member_fns_changes() const;
edit_script&
member_fns_changes();
const function_decl_diff_sptrs_type&
changed_member_fns() const;
const string_member_function_sptr_map&
deleted_member_fns() const;
const string_member_function_sptr_map&
inserted_member_fns() const;
const var_diff_sptrs_type&
sorted_changed_data_members() const;
size_t
count_filtered_changed_data_members(bool local_only = false) const;
const var_diff_sptrs_type&
sorted_subtype_changed_data_members() const;
size_t
count_filtered_subtype_changed_data_members(bool local_only = false) const;
const string_decl_base_sptr_map&
data_members_replaced_by_adms() const;
const changed_var_sptrs_type&
ordered_data_members_replaced_by_adms() const;
const edit_script&
member_fn_tmpls_changes() const;
edit_script&
member_fn_tmpls_changes();
const edit_script&
member_class_tmpls_changes() const;
edit_script&
member_class_tmpls_changes();
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
friend class default_reporter;
}; // end class_or_union_diff;
/// This type abstracts changes for a class_decl.
class class_diff : public class_or_union_diff
{
struct priv;
typedef std::unique_ptr<priv> priv_ptr;
priv_ptr priv_;
const priv_ptr& get_priv()const;
void
clear_lookup_tables(void);
bool
lookup_tables_empty(void) const;
void
ensure_lookup_tables_populated(void) const;
void
allocate_priv_data();
protected:
class_diff(class_decl_sptr first_scope,
class_decl_sptr second_scope,
diff_context_sptr ctxt = diff_context_sptr());
public:
//TODO: add change of the name of the type.
virtual ~class_diff();
class_decl_sptr
first_class_decl() const;
class_decl_sptr
second_class_decl() const;
const edit_script&
base_changes() const;
edit_script&
base_changes();
const string_base_sptr_map&
deleted_bases() const;
const string_base_sptr_map&
inserted_bases() const;
const base_diff_sptrs_type&
changed_bases();
const vector<class_decl::base_spec_sptr>&
moved_bases() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual const string&
get_pretty_representation() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
friend class_diff_sptr
compute_diff(const class_decl_sptr first,
const class_decl_sptr second,
diff_context_sptr ctxt);
friend class default_reporter;
};// end class_diff
class_diff_sptr
compute_diff(const class_decl_sptr first,
const class_decl_sptr second,
diff_context_sptr ctxt);
class union_diff;
typedef shared_ptr<union_diff> union_diff_sptr;
class union_diff : public class_or_union_diff
{
void
clear_lookup_tables(void);
bool
lookup_tables_empty(void) const;
void
ensure_lookup_tables_populated(void) const;
void
allocate_priv_data();
protected:
union_diff(union_decl_sptr first_union,
union_decl_sptr second_union,
diff_context_sptr ctxt = diff_context_sptr());
public:
virtual ~union_diff();
union_decl_sptr
first_union_decl() const;
union_decl_sptr
second_union_decl() const;
virtual const string&
get_pretty_representation() const;
virtual void
report(ostream&, const string& indent = "") const;
friend union_diff_sptr
compute_diff(const union_decl_sptr first,
const union_decl_sptr second,
diff_context_sptr ctxt);
}; // end class union_diff
union_diff_sptr
compute_diff(const union_decl_sptr first,
const union_decl_sptr second,
diff_context_sptr ctxt);
/// An abstraction of a diff between two instances of class_decl::base_spec.
class base_diff : public diff
{
struct priv;
std::unique_ptr<priv> priv_;
protected:
base_diff(class_decl::base_spec_sptr first,
class_decl::base_spec_sptr second,
class_diff_sptr underlying,
diff_context_sptr ctxt = diff_context_sptr());
public:
class_decl::base_spec_sptr
first_base() const;
class_decl::base_spec_sptr
second_base() const;
const class_diff_sptr
get_underlying_class_diff() const;
void
set_underlying_class_diff(class_diff_sptr d);
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
friend base_diff_sptr
compute_diff(const class_decl::base_spec_sptr first,
const class_decl::base_spec_sptr second,
diff_context_sptr ctxt);
};// end class base_diff
base_diff_sptr
compute_diff(const class_decl::base_spec_sptr first,
const class_decl::base_spec_sptr second,
diff_context_sptr ctxt);
class scope_diff;
/// Convenience typedef for a shared pointer on a @ref scope_diff.
typedef shared_ptr<scope_diff> scope_diff_sptr;
/// An abstractions of the changes between two scopes.
class scope_diff : public diff
{
struct priv;
std::unique_ptr<priv> priv_;
bool
lookup_tables_empty() const;
void
clear_lookup_tables();
void
ensure_lookup_tables_populated();
protected:
scope_diff(scope_decl_sptr first_scope,
scope_decl_sptr second_scope,
diff_context_sptr ctxt = diff_context_sptr());
public:
friend scope_diff_sptr
compute_diff(const scope_decl_sptr first,
const scope_decl_sptr second,
scope_diff_sptr d,
diff_context_sptr ctxt);
friend scope_diff_sptr
compute_diff(const scope_decl_sptr first_scope,
const scope_decl_sptr second_scope,
diff_context_sptr ctxt);
const scope_decl_sptr
first_scope() const;
const scope_decl_sptr
second_scope() const;
const edit_script&
member_changes() const;
edit_script&
member_changes();
const decl_base_sptr
deleted_member_at(unsigned index) const;
const decl_base_sptr
deleted_member_at(vector<deletion>::const_iterator) const;
const decl_base_sptr
inserted_member_at(unsigned i);
const decl_base_sptr
inserted_member_at(vector<unsigned>::const_iterator i);
const diff_sptrs_type&
changed_types() const;
const diff_sptrs_type&
changed_decls() const;
const string_decl_base_sptr_map&
removed_types() const;
const string_decl_base_sptr_map&
removed_decls() const;
const string_decl_base_sptr_map&
added_types() const;
const string_decl_base_sptr_map&
added_decls() const;
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream& out, const string& indent = "") const;
virtual void
chain_into_hierarchy();
friend class default_reporter;
friend class leaf_reporter;
};// end class scope_diff
scope_diff_sptr
compute_diff(const scope_decl_sptr first,
const scope_decl_sptr second,
scope_diff_sptr d,
diff_context_sptr ctxt);
scope_diff_sptr
compute_diff(const scope_decl_sptr first_scope,
const scope_decl_sptr second_scope,
diff_context_sptr ctxt);
/// Abstraction of a diff between two function parameters.
class fn_parm_diff : public decl_diff_base
{
struct priv;
std::unique_ptr<priv> priv_;
fn_parm_diff(const function_decl::parameter_sptr first,
const function_decl::parameter_sptr second,
diff_context_sptr ctxt);
public:
friend fn_parm_diff_sptr
compute_diff(const function_decl::parameter_sptr first,
const function_decl::parameter_sptr second,
diff_context_sptr ctxt);
const function_decl::parameter_sptr
first_parameter() const;
const function_decl::parameter_sptr
second_parameter() const;
diff_sptr
type_diff() const;
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
}; // end class fn_parm_diff
fn_parm_diff_sptr
compute_diff(const function_decl::parameter_sptr first,
const function_decl::parameter_sptr second,
diff_context_sptr ctxt);
class function_type_diff;
/// A convenience typedef for a shared pointer to @ref
/// function_type_type_diff
typedef shared_ptr<function_type_diff> function_type_diff_sptr;
/// Abstraction of a diff between two function types.
class function_type_diff: public type_diff_base
{
struct priv;
std::unique_ptr<priv> priv_;
void
ensure_lookup_tables_populated();
const function_decl::parameter_sptr
deleted_parameter_at(int i) const;
const function_decl::parameter_sptr
inserted_parameter_at(int i) const;
protected:
function_type_diff(const function_type_sptr first,
const function_type_sptr second,
diff_context_sptr ctxt);
public:
friend function_type_diff_sptr
compute_diff(const function_type_sptr first,
const function_type_sptr second,
diff_context_sptr ctxt);
const function_type_sptr
first_function_type() const;
const function_type_sptr
second_function_type() const;
const diff_sptr
return_type_diff() const;
const string_fn_parm_diff_sptr_map&
subtype_changed_parms() const;
const string_parm_map&
removed_parms() const;
const string_parm_map&
added_parms() const;
const vector<function_decl::parameter_sptr>&
sorted_deleted_parms() const;
const vector<function_decl::parameter_sptr>&
sorted_added_parms() const;
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
friend class default_reporter;
friend class leaf_reporter;
};// end class function_type_diff
function_type_diff_sptr
compute_diff(const function_type_sptr first,
const function_type_sptr second,
diff_context_sptr ctxt);
/// Abstraction of a diff between two function_decl.
class function_decl_diff : public decl_diff_base
{
struct priv;
std::unique_ptr<priv> priv_;
void
ensure_lookup_tables_populated();
protected:
function_decl_diff(const function_decl_sptr first,
const function_decl_sptr second,
diff_context_sptr ctxt);
public:
friend function_decl_diff_sptr
compute_diff(const function_decl_sptr first,
const function_decl_sptr second,
diff_context_sptr ctxt);
const function_decl_sptr
first_function_decl() const;
const function_decl_sptr
second_function_decl() const;
const function_type_diff_sptr
type_diff() const;
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
}; // end class function_decl_diff
function_decl_diff_sptr
compute_diff(const function_decl_sptr first,
const function_decl_sptr second,
diff_context_sptr ctxt);
class type_decl_diff;
/// Convenience typedef for a shared pointer on a @ref type_decl_diff type.
typedef shared_ptr<type_decl_diff> type_decl_diff_sptr;
/// Abstraction of a diff between two basic type declarations.
class type_decl_diff : public type_diff_base
{
type_decl_diff();
protected:
type_decl_diff(const type_decl_sptr first,
const type_decl_sptr second,
diff_context_sptr ctxt = diff_context_sptr());
public:
friend type_decl_diff_sptr
compute_diff(const type_decl_sptr first,
const type_decl_sptr second,
diff_context_sptr ctxt);
const type_decl_sptr
first_type_decl() const;
const type_decl_sptr
second_type_decl() const;
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream& out, const string& indent = "") const;
};// end type_decl_diff
type_decl_diff_sptr
compute_diff(const type_decl_sptr,
const type_decl_sptr,
diff_context_sptr);
class typedef_diff;
/// Convenience typedef for a shared pointer on a typedef_diff type.
typedef shared_ptr<typedef_diff> typedef_diff_sptr;
/// Abstraction of a diff between two typedef_decl.
class typedef_diff : public type_diff_base
{
struct priv;
std::unique_ptr<priv> priv_;
typedef_diff();
protected:
typedef_diff(const typedef_decl_sptr first,
const typedef_decl_sptr second,
const diff_sptr underlying_type_diff,
diff_context_sptr ctxt = diff_context_sptr());
public:
friend typedef_diff_sptr
compute_diff(const typedef_decl_sptr first,
const typedef_decl_sptr second,
diff_context_sptr ctxt);
const typedef_decl_sptr
first_typedef_decl() const;
const typedef_decl_sptr
second_typedef_decl() const;
const diff_sptr
underlying_type_diff() const;
void
underlying_type_diff(const diff_sptr);
virtual const string&
get_pretty_representation() const;
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream&, const string& indent = "") const;
virtual void
chain_into_hierarchy();
};// end class typedef_diff
typedef_diff_sptr
compute_diff(const typedef_decl_sptr,
const typedef_decl_sptr,
diff_context_sptr ctxt);
const diff*
get_typedef_diff_underlying_type_diff(const diff* diff);
class translation_unit_diff;
/// Convenience typedef for a shared pointer on a
/// @ref translation_unit_diff type.
typedef shared_ptr<translation_unit_diff> translation_unit_diff_sptr;
/// An abstraction of a diff between two translation units.
class translation_unit_diff : public scope_diff
{
struct priv;
std::unique_ptr<priv> priv_;
protected:
translation_unit_diff(translation_unit_sptr first,
translation_unit_sptr second,
diff_context_sptr ctxt = diff_context_sptr());
public:
const translation_unit_sptr
first_translation_unit() const;
const translation_unit_sptr
second_translation_unit() const;
friend translation_unit_diff_sptr
compute_diff(const translation_unit_sptr first,
const translation_unit_sptr second,
diff_context_sptr ctxt);
virtual bool
has_changes() const;
virtual enum change_kind
has_local_changes() const;
virtual void
report(ostream& out, const string& indent = "") const;
};//end class translation_unit_diff
translation_unit_diff_sptr
compute_diff(const translation_unit_sptr first,
const translation_unit_sptr second,
diff_context_sptr ctxt = diff_context_sptr());
/// An abstraction of a diff between between two abi corpus.
class corpus_diff
{
struct priv;
std::unique_ptr<priv> priv_;
protected:
corpus_diff(corpus_sptr first,
corpus_sptr second,
diff_context_sptr ctxt = diff_context_sptr());
void
finish_diff_type();
public:
class diff_stats;
virtual ~corpus_diff();
/// A convenience typedef for a shared pointer to @ref diff_stats
typedef shared_ptr<diff_stats> diff_stats_sptr;
corpus_sptr
first_corpus() const;
corpus_sptr
second_corpus() const;
const vector<diff*>&
children_nodes() const;
void
append_child_node(diff_sptr);
edit_script&
function_changes() const;
edit_script&
variable_changes() const;
bool
soname_changed() const;
bool
architecture_changed() const;
const string_function_ptr_map&
deleted_functions() const;
const string_function_ptr_map&
added_functions();
const string_function_decl_diff_sptr_map&
changed_functions();
const function_decl_diff_sptrs_type&
changed_functions_sorted();
const string_var_ptr_map&
deleted_variables() const;
const string_var_ptr_map&
added_variables() const;
const string_var_diff_sptr_map&
changed_variables();
const var_diff_sptrs_type&
changed_variables_sorted();
const string_elf_symbol_map&
deleted_unrefed_function_symbols() const;
const string_elf_symbol_map&
added_unrefed_function_symbols() const;
const string_elf_symbol_map&
deleted_unrefed_variable_symbols() const;
const string_elf_symbol_map&
added_unrefed_variable_symbols() const;
const string_type_base_sptr_map&
deleted_unreachable_types() const;
const vector<type_base_sptr>&
deleted_unreachable_types_sorted() const;
const string_type_base_sptr_map&
added_unreachable_types() const;
const vector<type_base_sptr>&
added_unreachable_types_sorted() const;
const string_diff_sptr_map&
changed_unreachable_types() const;
const vector<diff_sptr>&
changed_unreachable_types_sorted() const;
const diff_context_sptr
context() const;
const string&
get_pretty_representation() const;
bool
has_changes() const;
bool
has_incompatible_changes() const;
bool
has_net_subtype_changes() const;
bool
has_net_changes() const;
const diff_stats&
apply_filters_and_suppressions_before_reporting();
void
mark_leaf_diff_nodes();
diff_maps&
get_leaf_diffs();
const diff_maps&
get_leaf_diffs() const;
virtual void
report(ostream& out, const string& indent = "") const;
virtual bool
traverse(diff_node_visitor& v);
virtual void
chain_into_hierarchy();
friend corpus_diff_sptr
compute_diff(const corpus_sptr f,
const corpus_sptr s,
diff_context_sptr ctxt);
friend void
apply_suppressions(const corpus_diff* diff_tree);
friend void
maybe_report_unreachable_type_changes(const corpus_diff& d,
const corpus_diff::diff_stats &s,
const string& indent,
ostream& out);
friend class default_reporter;
friend class leaf_reporter;
}; // end class corpus_diff
corpus_diff_sptr
compute_diff(const corpus_sptr,
const corpus_sptr,
diff_context_sptr = diff_context_sptr());
corpus_diff_sptr
compute_diff(const corpus_group_sptr&,
const corpus_group_sptr&,
diff_context_sptr ctxt);
/// This is a document class that aims to capture statistics about the
/// changes carried by a @ref corpus_diff type.
///
/// Its values are populated by the member function
/// corpus_diff::apply_filters_and_suppressions_before_reporting()
class corpus_diff::diff_stats
{
struct priv;
std::unique_ptr<priv> priv_;
diff_stats();
public:
diff_stats(diff_context_sptr);
size_t num_func_removed() const;
void num_func_removed(size_t);
size_t num_removed_func_filtered_out() const;
void num_removed_func_filtered_out(size_t);
size_t net_num_func_removed() const;
size_t num_func_added() const;
void num_func_added(size_t);
size_t num_added_func_filtered_out() const;
void num_added_func_filtered_out(size_t);
size_t net_num_func_added() const;
size_t num_func_changed() const;
void num_func_changed(size_t);
size_t num_changed_func_filtered_out() const;
void num_changed_func_filtered_out(size_t);
size_t num_func_with_virtual_offset_changes() const;
void num_func_with_virtual_offset_changes(size_t);
size_t net_num_func_changed() const;
size_t num_vars_removed() const;
void num_vars_removed(size_t);
size_t num_removed_vars_filtered_out() const;
void num_removed_vars_filtered_out(size_t) const;
size_t net_num_vars_removed() const;
size_t num_vars_added() const;
void num_vars_added(size_t);
size_t num_added_vars_filtered_out() const;
void num_added_vars_filtered_out(size_t);
size_t net_num_vars_added() const;
size_t num_vars_changed() const;
void num_vars_changed(size_t);
size_t num_changed_vars_filtered_out() const;
void num_changed_vars_filtered_out(size_t);
size_t net_num_vars_changed() const;
size_t num_func_syms_removed() const;
void num_func_syms_removed(size_t);
size_t num_removed_func_syms_filtered_out() const;
void num_removed_func_syms_filtered_out(size_t);
size_t num_func_syms_added() const;
void num_func_syms_added(size_t);
size_t num_added_func_syms_filtered_out() const;
void num_added_func_syms_filtered_out(size_t);
size_t net_num_removed_func_syms() const;
size_t net_num_added_func_syms() const;
size_t num_var_syms_removed() const;
void num_var_syms_removed(size_t);
size_t num_removed_var_syms_filtered_out() const;
void num_removed_var_syms_filtered_out(size_t);
size_t num_var_syms_added() const;
void num_var_syms_added(size_t);
size_t num_added_var_syms_filtered_out() const;
void num_added_var_syms_filtered_out(size_t);
size_t net_num_removed_var_syms() const;
size_t net_num_added_var_syms() const;
size_t num_leaf_changes() const;
void num_leaf_changes(size_t);
size_t num_leaf_changes_filtered_out() const;
void num_leaf_changes_filtered_out(size_t);
size_t net_num_leaf_changes() const;
size_t num_leaf_type_changes() const;
void num_leaf_type_changes(size_t);
size_t num_leaf_type_changes_filtered_out() const;
void num_leaf_type_changes_filtered_out(size_t);
size_t net_num_leaf_type_changes() const;
size_t num_leaf_func_changes() const;
void num_leaf_func_changes(size_t);
size_t num_leaf_func_changes_filtered_out() const;
void num_leaf_func_changes_filtered_out(size_t);
size_t net_num_leaf_func_changes() const;
size_t num_leaf_var_changes() const;
void num_leaf_var_changes(size_t);
size_t num_leaf_var_changes_filtered_out() const;
void num_leaf_var_changes_filtered_out(size_t);
size_t net_num_leaf_var_changes() const;
size_t num_added_unreachable_types() const;
void num_added_unreachable_types(size_t);
size_t num_added_unreachable_types_filtered_out() const;
void num_added_unreachable_types_filtered_out(size_t);
size_t net_num_added_unreachable_types() const;
size_t num_removed_unreachable_types() const;
void num_removed_unreachable_types(size_t);
size_t num_removed_unreachable_types_filtered_out() const;
void num_removed_unreachable_types_filtered_out(size_t);
size_t net_num_removed_unreachable_types() const;
size_t num_changed_unreachable_types() const;
void num_changed_unreachable_types(size_t);
size_t num_changed_unreachable_types_filtered_out() const;
void num_changed_unreachable_types_filtered_out(size_t);
size_t net_num_changed_unreachable_types() const;
}; // end class corpus_diff::diff_stats
/// The base class for the node visitors. These are the types used to
/// visit each node traversed by the diff_traversable_base::traverse() method.
class diff_node_visitor : public node_visitor_base
{
protected:
struct priv;
std::unique_ptr<priv> priv_;
public:
diff_node_visitor();
virtual ~diff_node_visitor();
diff_node_visitor(visiting_kind k);
visiting_kind
get_visiting_kind() const;
void
set_visiting_kind(visiting_kind v);
void
or_visiting_kind(visiting_kind v);
void
set_current_topmost_iface_diff(diff*);
diff*
get_current_topmost_iface_diff() const;
virtual void
visit_begin(diff*);
virtual void
visit_begin(corpus_diff*);
virtual void
visit_end(diff*);
virtual void
visit_end(corpus_diff*);
virtual bool
visit(diff*, bool);
virtual bool
visit(distinct_diff*, bool);
virtual bool
visit(var_diff*, bool);
virtual bool
visit(pointer_diff*, bool);
virtual bool
visit(reference_diff*, bool);
virtual bool
visit(qualified_type_diff*, bool);
virtual bool
visit(enum_diff*, bool);
virtual bool
visit(class_diff*, bool);
virtual bool
visit(base_diff*, bool);
virtual bool
visit(scope_diff*, bool);
virtual bool
visit(function_decl_diff*, bool);
virtual bool
visit(type_decl_diff*, bool);
virtual bool
visit(typedef_diff*, bool);
virtual bool
visit(translation_unit_diff*, bool);
virtual bool
visit(corpus_diff*, bool);
}; // end struct diff_node_visitor
void
propagate_categories(diff* diff_tree);
void
propagate_categories(diff_sptr diff_tree);
void
propagate_categories(corpus_diff* diff_tree);
void
propagate_categories(corpus_diff_sptr diff_tree);
void
apply_suppressions(diff* diff_tree);
void
apply_suppressions(const corpus_diff* diff_tree);
void
apply_suppressions(diff_sptr diff_tree);
void
apply_suppressions(corpus_diff_sptr diff_tree);
void
print_diff_tree(diff* diff_tree, std::ostream&);
void
print_diff_tree(corpus_diff* diff_tree,
std::ostream&);
void
print_diff_tree(diff_sptr diff_tree,
std::ostream&);
void
print_diff_tree(corpus_diff_sptr diff_tree,
std::ostream&);
void
categorize_redundancy(diff* diff_tree);
void
categorize_redundancy(diff_sptr diff_tree);
void
categorize_redundancy(corpus_diff* diff_tree);
void
categorize_redundancy(corpus_diff_sptr diff_tree);
void
clear_redundancy_categorization(diff* diff_tree);
void
clear_redundancy_categorization(diff_sptr diff_tree);
void
clear_redundancy_categorization(corpus_diff* diff_tree);
void
clear_redundancy_categorization(corpus_diff_sptr diff_tree);
void
apply_filters(corpus_diff_sptr diff_tree);
bool
is_diff_of_variadic_parameter_type(const diff*);
bool
is_diff_of_variadic_parameter_type(const diff_sptr&);
bool
is_diff_of_variadic_parameter(const diff*);
bool
is_diff_of_variadic_parameter(const diff_sptr&);
const type_diff_base*
is_type_diff(const diff* diff);
const decl_diff_base*
is_decl_diff(const diff* diff);
const type_decl_diff*
is_diff_of_basic_type(const diff* diff);
const type_decl_diff*
is_diff_of_basic_type(const diff* diff, bool);
const class_or_union_diff*
is_diff_of_class_or_union_type(const diff *d);
bool
has_basic_type_change_only(const diff* diff);
const enum_diff*
is_enum_diff(const diff *diff);
const class_diff*
is_class_diff(const diff* diff);
const union_diff*
is_union_diff(const diff* diff);
const class_or_union_diff*
is_class_or_union_diff(const diff* d);
const class_or_union_diff*
is_anonymous_class_or_union_diff(const diff* d);
const array_diff*
is_array_diff(const diff* diff);
const function_type_diff*
is_function_type_diff(const diff* diff);
const function_type_diff*
is_function_type_diff_with_local_changes(const diff* diff);
const typedef_diff*
is_typedef_diff(const diff *diff);
const var_diff*
is_var_diff(const diff* diff);
const function_decl_diff*
is_function_decl_diff(const diff* diff);
const pointer_diff*
is_pointer_diff(const diff* diff);
const reference_diff*
is_reference_diff(const diff* diff);
const qualified_type_diff*
is_qualified_type_diff(const diff* diff);
const fn_parm_diff*
is_fn_parm_diff(const diff* diff);
const base_diff*
is_base_diff(const diff* diff);
const distinct_diff*
is_distinct_diff(const diff *diff);
bool
is_child_node_of_function_parm_diff(const diff* diff);
bool
is_child_node_of_base_diff(const diff* diff);
const corpus_diff*
is_corpus_diff(const diff* diff);
const diff*
peel_typedef_diff(const diff* dif);
const diff*
peel_pointer_diff(const diff* dif);
const diff*
peel_reference_diff(const diff* dif);
const diff*
peel_qualified_diff(const diff* dif);
const diff*
peel_fn_parm_diff(const diff* dif);
const diff*
peel_pointer_or_qualified_type_diff(const diff* dif);
const diff*
peel_typedef_or_qualified_type_diff(const diff* dif);
const diff*
peel_typedef_qualified_type_or_parameter_diff(const diff *dif);
}// end namespace comparison
}// end namespace abigail
#endif //__ABG_COMPARISON_H__